Curated multi-stack automation playbook for The Internet, using one shared scenario catalog to compare Selenium, Playwright, browser matrices, reports, and CI tradeoffs.
- A teaching repo for UI and resource-layer test automation.
- A side-by-side playbook for Java Selenium/TestNG, TypeScript Playwright, and Python Playwright.
- A catalog-driven suite: scenario IDs live in
scenarios/catalog.yml, tests reference those IDs, andtools/check-scenarios.pykeeps coverage honest. - A CI reference for fast PR gates, per-stack full gates, scheduled nightly coverage, and report artifacts.
- MIT-licensed; see
LICENSE.
- Not a production application; the app under test is the public The Internet demo app.
- Not fake REST CRUD; HTTP/resource checks focus on pages the demo app actually exposes.
- Not every framework. The maintained stacks are Java Selenium/TestNG, TypeScript Playwright, and Python Playwright.
- Not a place for unbounded framework experiments. Add scenarios and stacks through the catalog and roadmap.
Run the TypeScript Playwright smoke suite first; it is the quickest local feedback loop.
docker compose -f docker/compose.yml up -d website
cd stacks/ts-playwright
npm ci
npx playwright install chromium
THE_INTERNET_BASE_URL=http://localhost:7080 npm run test:chromium:smoke
cd ../..
docker compose -f docker/compose.yml downThen use the stack READMEs and guides for deeper runs:
- Java Selenium/TestNG stack
- TypeScript Playwright stack
- Python Playwright stack
- Framework comparison
- Interview guide
- Flakiness guide
- CI workflows
- Learning paths
| Stack | Status | Main tools | Local command | CI coverage |
|---|---|---|---|---|
| Java Selenium/TestNG | Active legacy-maintainer track | Java 25, Maven, Selenium, TestNG, Surefire | cd stacks/java-selenium-testng && mvn test |
PR smoke, path-filtered Chrome/Firefox regression, nightly Chrome/Edge/Firefox |
| TypeScript Playwright | Active modern flagship track | Node 22, npm, Playwright Test, ESLint, Prettier | cd stacks/ts-playwright && npm run test:chromium:smoke |
PR smoke, path-filtered browser/mobile matrix, nightly branded-browser/mobile matrix |
| Python Playwright | Active Python track | Python 3.14, pytest, pytest-playwright, Ruff, mypy | cd stacks/python-playwright && pytest -m smoke --browser chromium |
PR smoke, path-filtered browser/mobile matrix, nightly branded-browser/mobile matrix |
Embedded from docs/scenario-matrix.md, generated by tools/check-scenarios.py --write-matrix.
| ID | Priority | Scenario | Java | TS | Python |
|---|---|---|---|---|---|
| UI-LOGIN-001 | P0 | Login succeeds with valid credentials | ✅ | ✅ | ✅ |
| UI-LOGIN-002 | P0 | Login rejects an invalid username | ✅ | ✅ | ✅ |
| UI-LOGIN-003 | P0 | Login rejects an invalid password | ✅ | ✅ | ✅ |
| UI-ADDREMOVE-001 | P0 | Add and remove buttons update the dynamic DOM | — | ✅ | ✅ |
| UI-CHECKBOX-001 | P0 | Checkboxes toggle on and off | ✅ | ✅ | ✅ |
| UI-CONTEXT-001 | P1 | Context menu opens the expected alert | ✅ | ✅ | — |
| UI-DRAGDROP-001 | P1 | Drag box A over box B | ✅ | ✅ | — |
| UI-DRAGDROP-002 | P1 | Drag box B over box A | ✅ | ✅ | — |
| UI-DRAGDROP-003 | P1 | Drag boxes in both directions | ✅ | ✅ | — |
| UI-DROPDOWN-001 | P0 | Dropdown options can be selected | ✅ | ✅ | ✅ |
| UI-DYNCONTENT-001 | P2 | Dynamic content changes on reload | ✅ | ✅ | — |
| UI-DYNCONTENT-002 | P2 | Dynamic content partially changes on reload | ✅ | ✅ | — |
| UI-DYNCTRL-001 | P0 | Dynamic controls remove and add a checkbox | ✅ | ✅ | ✅ |
| UI-DYNCTRL-002 | P0 | Dynamic controls checkbox toggles | ✅ | ✅ | ✅ |
| UI-DYNCTRL-003 | P0 | Dynamic controls enable and disable a textbox | ✅ | ✅ | ✅ |
| UI-DYNLOAD-001 | P0 | Dynamic loading reveals the success message | ✅ | ✅ | ✅ |
| UI-UPLOAD-001 | P0 | File upload shows the uploaded file | ✅ | ✅ | ✅ |
| UI-DOWNLOAD-001 | P1 | File download retrieves the expected content | ✅ | ✅ | ✅ |
| UI-FLOATING-001 | P1 | Floating menu remains visible while scrolling | ✅ | ✅ | — |
| UI-IFRAME-001 | P0 | iFrame editor supports context switching | ✅ | ✅ | ✅ |
| UI-INPUT-001 | P0 | Numeric input accepts keyboard data | — | ✅ | ✅ |
| UI-HOVERS-001 | P1 | Hovering reveals user details | ✅ | ✅ | — |
| UI-JSALERT-001 | P0 | JavaScript alert buttons open popups | ✅ | ✅ | ✅ |
| UI-JSALERT-002 | P0 | JavaScript alert messages match expectations | ✅ | ✅ | ✅ |
| UI-JSALERT-003 | P0 | JavaScript prompt accepts input | ✅ | ✅ | ✅ |
| UI-JSERROR-001 | P1 | JavaScript error page exposes the expected error | ✅ | — | — |
| UI-WINDOWS-001 | P0 | Link opens expected content in a new tab | ✅ | ✅ | ✅ |
| HTTP-STATUS-001 | P0 | Status code endpoints return expected responses | — | ✅ | ✅ |
| HTTP-REDIRECT-001 | P0 | Redirect endpoint reaches the status codes page | — | ✅ | ✅ |
| HTTP-BASICAUTH-001 | P1 | Basic authentication accepts valid credentials | — | ✅ | ✅ |
| HTTP-DIGESTAUTH-001 | P1 | Digest authentication accepts valid credentials | — | ✅ | ✅ |
| HTTP-SLOW-001 | P2 | Slow resources fail with a bounded timeout | — | ✅ | ✅ |
| UI-BROKENIMG-001 | P0 | Broken images expose failed resource responses | — | ✅ | ✅ |
| UI-NOTIFY-001 | P1 | Notification message flash shows expected messages | ✅ | ✅ | — |
| UI-SHADOWDOM-001 | P1 | Shadow DOM exposes text through open roots and slots | — | ✅ | — |
| UI-SORTTABLE-001 | P1 | Sortable tables reorder rows by selected columns | — | ✅ | ✅ |
| UI-GEOLOCATION-001 | P1 | Geolocation displays the granted browser coordinates | — | ✅ | — |
| UI-INFINITE-001 | P1 | Infinite scroll loads additional content on demand | — | ✅ | — |
| UI-CHALLENGING-001 | P1 | Challenging DOM is asserted without dynamic identifiers | ✅ | ✅ | — |
| UI-SLIDER-001 | P1 | Horizontal slider moves by keyboard increments | — | ✅ | — |
| UI-DISAPPEAR-001 | P2 | Disappearing elements keep a stable core menu | — | ✅ | — |
| UI-ENTRYAD-001 | P2 | Entry ad modal can be observed and closed | — | ✅ | — |
| UI-EXITINTENT-001 | P2 | Exit intent modal opens on desktop mouse leave | — | ✅ | — |
| UI-TYPOS-001 | P2 | Typos page demonstrates nondeterministic copy | — | ✅ | — |
| UI-SHIFTING-001 | P2 | Shifting content demonstrates randomized layout | — | ✅ | — |
| UI-LARGEDOM-001 | P2 | Large and deep DOM supports targeted traversal | — | ✅ | — |
| UI-JQUERYUI-001 | P2 | JQuery UI menu exposes nested desktop options | — | ✅ | — |
| UI-ABTEST-001 | P2 | A/B testing page allows either experiment variant | — | ✅ | — |
| Path | Start here | Then study |
|---|---|---|
| Beginner | Login, checkboxes, dropdown, add/remove | JavaScript alerts, uploads, dynamic loading |
| Interview candidate | docs/interview-guide.md |
iframe, windows, upload/download, broken images, status codes |
| Legacy Selenium maintainer | docs/anti-patterns.md |
Page Objects, Grid, parallelism, Surefire reports |
| Modern Playwright learner | docs/framework-comparison.md |
Fixtures, projects, traces, browser channels, mobile emulation |
| Senior CI/architecture reviewer | Scenario catalog and stack matrix | Flake lab, PR gates, path filters, nightly matrix, artifact strategy |
CI stages report files under artifacts/<stack>/<run-id>/<slice>/ before uploading each stack and slice artifact.
| Stack | Local report path | CI artifacts |
|---|---|---|
| Java | stacks/java-selenium-testng/target/surefire-reports/ |
Surefire XML in artifacts/java/<run-id>/<slice>/surefire-reports/ from PR, Java, and Nightly workflows |
| TypeScript | stacks/ts-playwright/playwright-report/ and stacks/ts-playwright/test-results/ |
HTML reports in artifacts/ts/<run-id>/<slice>/html-report/; retry traces, screenshots, videos, and attachments in artifacts/ts/<run-id>/<slice>/test-results/ |
| Python | stacks/python-playwright/test-results/ |
JUnit XML plus retry traces, screenshots, videos, and attachments in artifacts/py/<run-id>/<slice>/ |
| Allure | Not wired yet | Deferred until it stays low-friction beside built-in reports |
| Workflow | Badge |
|---|---|
| PR fast gate | |
| Java full gate | |
| TypeScript full gate | |
| Python full gate | |
| Nightly matrix |