feat(tests): add E2E tests with pytfm framework
- Add pytfm workspace dependency to tests and types groups - Create E2E test example using pytfm API and page objects - Add BlogHomePage and BlogAPI test classes Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -38,6 +38,7 @@ tests = [
|
|||||||
"pytest>=9.0.3",
|
"pytest>=9.0.3",
|
||||||
"pytest-asyncio>=1.3.0",
|
"pytest-asyncio>=1.3.0",
|
||||||
"pytest-cov>=7.1.0",
|
"pytest-cov>=7.1.0",
|
||||||
|
"pytfm",
|
||||||
]
|
]
|
||||||
lints = [
|
lints = [
|
||||||
"black>=23.7.0",
|
"black>=23.7.0",
|
||||||
@@ -47,11 +48,15 @@ lints = [
|
|||||||
types = [
|
types = [
|
||||||
"mimesis>=19.1.0",
|
"mimesis>=19.1.0",
|
||||||
"mypy>=1.20.1",
|
"mypy>=1.20.1",
|
||||||
|
"pytfm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
blog = "app.main:main"
|
blog = "app.main:main"
|
||||||
|
|
||||||
|
[tool.uv.sources]
|
||||||
|
pytfm = { workspace = true }
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
asyncio_mode = "auto"
|
asyncio_mode = "auto"
|
||||||
asyncio_default_fixture_loop_scope = "function"
|
asyncio_default_fixture_loop_scope = "function"
|
||||||
|
|||||||
57
tests/e2e/test_example.py
Normal file
57
tests/e2e/test_example.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
"""Example E2E test using pytfm framework.
|
||||||
|
|
||||||
|
This module demonstrates how to use pytfm for testing
|
||||||
|
the blog application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
from pytfm.api import APIClient
|
||||||
|
from pytfm.web import BasePage
|
||||||
|
|
||||||
|
|
||||||
|
class BlogHomePage(BasePage):
|
||||||
|
"""Page object for the blog home page."""
|
||||||
|
|
||||||
|
path = "/"
|
||||||
|
|
||||||
|
async def get_posts(self) -> list[str]:
|
||||||
|
"""Get list of post titles on the page."""
|
||||||
|
posts = await self.page.query_selector_all('[data-testid="post-title"]')
|
||||||
|
return [await post.text_content() or "" for post in posts]
|
||||||
|
|
||||||
|
|
||||||
|
class TestBlogE2E:
|
||||||
|
"""End-to-end tests for the blog application."""
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_homepage_loads(self) -> None:
|
||||||
|
"""Test that homepage loads successfully."""
|
||||||
|
async with async_playwright() as p:
|
||||||
|
browser = await p.chromium.launch()
|
||||||
|
page = await browser.new_page()
|
||||||
|
|
||||||
|
home_page = BlogHomePage(page, "http://localhost:8000")
|
||||||
|
await home_page.open()
|
||||||
|
|
||||||
|
assert await home_page.is_visible('data-testid="nav-logo"')
|
||||||
|
|
||||||
|
await browser.close()
|
||||||
|
|
||||||
|
|
||||||
|
class TestBlogAPI:
|
||||||
|
"""API tests for the blog application."""
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_posts(self) -> None:
|
||||||
|
"""Test GET /api/v1/posts endpoint."""
|
||||||
|
async with APIClient("http://localhost:8000") as client:
|
||||||
|
response = await client.get("/api/v1/posts")
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.is_success
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
assert isinstance(data, list)
|
||||||
Reference in New Issue
Block a user