One focused hour a day. Read, run, then do the exercise. Do not skip the exercises — reading automation code feels productive and teaches almost nothing.
Read: 00-setup.md
make install
make smoke # should be green in ~30 seconds
make app # then open http://127.0.0.1:5000 and click aroundPoke the app manually first. You cannot automate what you have not used.
Checkpoint: you can explain what make smoke selected and why it was faster than make test.
Read: 01-playwright-basics.md
Code: tests/01_basics/ — five files, read them in order.
pytest tests/01_basics -v
pytest tests/01_basics/test_02_locators.py --headed --slowmo 700Exercises 1–5 are at the bottom of each lesson file.
Checkpoint: you can say, without looking, why expect(loc).to_have_text("x") is safer than
assert loc.inner_text() == "x".
Read: 02-page-object-model.md
Code: pages/, then tests/02_pom/
pytest tests/02_pom -vExercise 6: the app has an upload page with a page object already
(pages/upload_page.py) but no POM tests. Write tests/02_pom/test_upload.py covering: upload
from disk, upload from memory, and the error when you submit with no file.
Checkpoint: a designer renames the "Log in" button to "Sign in". How many files do you change?
Read: 03-fixtures-and-markers.md
pytest --fixtures | grep -A3 "authenticated_page\|api_context\|storage_state"
pytest --markers
pytest -m "smoke and not slow" -vExercise 7: add an admin_page fixture that is logged in as admin rather than demo, with
its own storage state, and write one test that uses it.
Exercise 8: add a perf marker to pytest.ini, tag one test with it, and make it run in
neither the smoke nor the regression selection.
Checkpoint: you can explain why configure_timeouts uses request.fixturenames instead of
just taking page as an argument.
Read: 04-ci-cd-explained.md with .github/workflows/ci.yml open beside it.
Exercise 9: in your fork, create a branch, deliberately break one assertion, and open a PR. Watch the pipeline. Then:
- Find which shard the failure landed in.
- Download that shard's artifact and open
report.html. - Open the trace:
playwright show-trace trace.zip. - Read the bot's PR comment and the inline failure annotation.
- Fix it and watch the comment update rather than duplicate.
Exercise 10: change the matrix so WebKit runs only on main, not on pull requests. (Hint:
include plus an if: on the step, or a second job.)
Checkpoint: you can explain what concurrency: cancel-in-progress saves and what it risks.
Read: 05-debugging-traces.md
make debug # Playwright Inspector
playwright codegen http://127.0.0.1:5000 # record a script, then improve its locators
make traceExercise 11: run playwright codegen, record a login + filter flow, then rewrite the generated
code using page objects and role-based locators. Compare the two. Codegen is a starting point, not
an output.
Checkpoint: given only a trace.zip from a CI failure, you can say what the page looked like at
the moment of failure.
Read: 06-flaky-tests.md
pytest -m regression -n auto # run it three times
pytest -m regression -p no:randomly # and once in file orderExercise 12: introduce a flaky test on purpose — make two tests share a hard-coded user ID —
then run with -n 4 until it fails. Fix it properly (unique data), not with --reruns.
Checkpoint: you can argue for what belongs in smoke versus regression on a real product,
and defend the size of your smoke suite.
- Swap the bundled app for your own product; keep
pages/,utils/,conftest.pyand the workflows - Add contract tests against your real API and wire them into the
api-testsjob - Add accessibility checks (
axe-coreviapage.evaluate) as a new marker and a new CI job - Add a
stagingenvironment in GitHub with a required reviewer, and pointmanual-run.ymlat it - Replace
pytest-htmlwith Allure if your team wants historical trends