You've finished eight chapters of Playwright Python — installation, locators, fixtures, network mocking, page objects, visual testing, CI/CD, and the framework patterns that hold a 300-test suite together. Now we put all of it into one project. The capstone is TaskMaster, a fictional but realistic full-stack todo application, and your job is to build a production-quality automated test suite for it from scratch. The brief below is the spec; the next two lessons are guided walkthroughs of the implementation; the final lesson is the self-assessment and stretch list. Treat this as the project you'd ship to a real team — not a tutorial exercise.
The application — TaskMaster
TaskMaster is a team task-management app with a Python/FastAPI backend and a React frontend. Users register, log in, create and manage tasks, assign tasks to teammates, and filter by status, priority, or assignee. The features your test suite has to cover:
- User accounts. Register with name/email/password. Log in via the same credentials. Log out. Sessions persist across reloads via a JWT cookie. Forgot-password flow exists but is out of scope for this capstone.
- Task CRUD. Create a task with title, description, priority (low/medium/high), status (todo/in-progress/done), and an optional due date. Edit any field. Mark complete (a shortcut for status=done). Delete with a confirmation dialog.
- Team collaboration. Tasks can be assigned to any team member. The assignee sees the task on their personal "assigned to me" view. Reassignment fires an email notification (out of scope for testing — assume the email queue receives the message).
- Filtering. Status filter (a select), priority filter (radios), assignee filter (a multi-select), due-date range (two date inputs), and a free-text search across title and description.
- API endpoints. All UI flows have matching REST endpoints under
/api/. POST/GET/PUT/PATCH/DELETE for/api/tasks,/api/users,/api/sessions. The API is the system of record; the UI is a client.
Assume TaskMaster runs locally at http://localhost:8000 for backend, http://localhost:3000 for frontend. Adapt to whatever real or sandbox app you have at hand if you're following along.
Your deliverables — eight things to build
The capstone is a list of things you commit to your repo:
- Project structure.
pages/,tests/,utils/,fixtures/,conftest.pyat root,requirements.txt,pytest.ini. Match the convention from chapter 8's project structure lesson — feature-based test folders, page objects inpages/, factories inutils/. - Page objects. At least four:
BasePage,LoginPage,TaskListPage,TaskDetailPage. Every page object inherits fromBasePage, uses typedLocatorfields, and exposes high-level methods (login,create_task,filter_by_status). - Custom fixtures. Authenticated users for two roles (admin, member), an
ApiClientfixture for direct API calls, factory functions forTestUserandTestTask, and storage-state fixtures so tests start logged in without paying the UI-login cost. - A 25-test suite, organised by feature. Five tests in each of five buckets:
- Auth (5): register, login, logout, invalid credentials, session persistence across reload.
- Tasks CRUD (5): create, edit, mark complete, delete with confirmation, validation errors on empty title.
- Filtering (5): by status, by priority, by assignee, by due-date range, by search query.
- API (5): direct API tests for create/read/update/delete tasks plus auth-required-401.
- Visual + a11y (5): screenshot comparisons on task list and detail pages, axe-core scans on three key pages.
- Network mocking. Three route-mock tests that drive UI states a real backend doesn't easily produce: empty task list,
500API error, slow (3s) response. Verify the UI shows the right empty/error/loading states. - Data factories with dataclasses.
TestUserandTestTaskfactories inutils/data_factory.py, both with__post_init__for unique fields. UUID-suffixed defaults for parallel safety. - Parameterised tests. At least two — one parametrized over multiple roles (admin login, member login, viewer login), one parametrized over multiple filter criteria (status × priority combinations).
- CI/CD. A
.github/workflows/playwright.ymlthat runs the suite on every push and PR, with a matrix for Chromium and Firefox, parallel execution viapytest-xdist, Allure result generation, and artefact upload. Cache the browsers across runs.
The deliverables map to the chapters
- – Project setup with pytest-playwright
- – Locator strategies — get_by_role, get_by_label
- – Actions — click, fill, select_option, set_input_files
- – conftest.py with shared fixtures
- – pytest.mark.parametrize for data-driven tests
- – API testing via page.request + APIRequestContext
- – Network mocking via page.route
- – Page objects with BasePage inheritance
- – Storage state for fast authenticated tests
- – Multi-role fixtures (admin, member)
- Visual regression with to_have_screenshot –
- Accessibility audit with axe-playwright-python –
- GitHub Actions CI with matrix –
- pytest-xdist parallel execution –
- Allure reporting + artefact upload –
- Data factories for unique test data –
Every deliverable maps cleanly to one or two chapters. If you find yourself stuck on a deliverable, the corresponding chapter is the place to revisit.
Stretch goals
Once the core 25 tests pass, the suite has visual baselines, and CI runs green, take the project further:
- Dockerise the suite. Build a custom image based on
mcr.microsoft.com/playwright/python:v1.44.0-jammy. Commit the Dockerfile. Confirmdocker runproduces the same results as local pytest. - Multi-browser visual testing. Run the visual subset against Chromium, Firefox, and WebKit — three baselines per visual test. Use the matrix-strategy CI pattern from chapter 7.
- Custom Allure categories. Define categories for "UI failures", "API failures", "Visual diffs", "A11y violations" so the dashboard groups failures by type. The
categories.jsonfile goes inallure-results/before generation. - Performance assertions. Use
page.tracing.start()andtracing.stop()to capture trace timing on critical flows. Assert that the/taskspage renders in under 2 seconds even on a cold load. - pytest-xdist with worker-unique data. Run the suite with
-n 4and verify no test data collisions. Add theworker_id-based DB naming pattern from chapter 7's parallelism lesson.
Each stretch goal is a 1-2 hour effort and pulls in techniques the core deliverables don't strictly require.
How to approach the project
Three guiding principles for the next two lessons:
- Build the framework before the tests. Set up the folder structure, page objects, and fixtures before writing test number 1. The first test is a smoke check that the framework runs at all; everything else is filling in the matrix the framework already supports.
- Use the API for setup, the UI for assertions. Most tests need a logged-in user with seeded tasks. Don't drive the UI through registration and task-creation forms for every single test — POST users and tasks via the API in a fixture, then drive only the UI flow you're actually testing.
- Write the failing test first, then make it pass. TDD-style. The test is the spec; passing means the spec is met. Refactor freely once the test is green; the test stops you from breaking it.
Realistic time budget
Built end-to-end with no other distractions, the capstone is 10-15 hours of work. Most teams spread it over a week of evenings. The split that works for most:
- Day 1 (2-3 hours): project setup, BasePage, LoginPage, conftest with auth fixture, first three smoke tests passing.
- Day 2 (2-3 hours): TaskListPage and TaskDetailPage, factories, the Auth and Tasks CRUD test buckets.
- Day 3 (2-3 hours): Filtering tests, API tests, network mocking tests.
- Day 4 (1-2 hours): Visual baselines, axe audits, parametrize examples.
- Day 5 (1-2 hours): GitHub Actions workflow, Allure reporting, debugging the CI run.
- Day 6 (1-2 hours): polish, README, stretch goals.
If you're tight on time, prioritise: the framework + auth + CRUD tests + GitHub Actions workflow are non-negotiable. Visual, a11y, and parallelism are valuable but addable later.
The constraint that makes the capstone valuable
Don't copy from the walkthrough lessons line-for-line. Read them, type the code yourself, get it wrong once or twice, debug, get it right. The point of the capstone is the muscle memory of building from scratch — not the resulting repo. Three months from now you'll remember the patterns; six months from now you'll reach for them on a real project; a year from now they'll feel like the obvious way to write tests.
The next lesson is Part 1 of the walkthrough: project setup, dataclass models, page objects, and the first three tests passing. Read it as a reference if you're stuck; build alongside it if it helps you stay on track.