# Test Suite End-to-end tests for TrainUs using **Playwright** (Python) and **pytest**. ## Setup (first time) ```bash cd tests python -m venv .venv .venv/bin/pip install -r requirements.txt .venv/bin/playwright install firefox chromium ``` ## Running Tests The Vite dev server starts automatically on port 5199 via the `app_url` fixture in `conftest.py`. It is stopped automatically when all tests finish. ### Available commands (from project root) | Command | Browsers | Mode | | -------------------------------- | ------------------ | --------------------------------- | | `npm run test` | Firefox | Sequential | | `npm run test:chromium` | Chromium | Sequential | | `npm run test:parallel` | Firefox + Chromium | Parallel (all CPU cores) | | `npm run test:parallel:firefox` | Firefox | Parallel (all CPU cores) | | `npm run test:parallel:chromium` | Chromium | Parallel (all CPU cores) | | `npm run test:parallel:n` | Firefox + Chromium | Parallel, N workers (`WORKERS=N`) | ### Running directly with pytest ```bash # All tests, Firefox only cd tests && .venv/bin/python -m pytest --browser firefox -v # Single file, Firefox cd tests && .venv/bin/python -m pytest test_step3_exercises.py --browser firefox -v # Parallel via shell script ./tests/run_parallel.sh # Parallel, Firefox only, 4 workers PYTEST_WORKERS=4 PYTEST_BROWSERS="firefox" ./tests/run_parallel.sh # Single file in parallel via shell script ./tests/run_parallel.sh test_step3_exercises.py ``` ## Browser Targets - **Firefox** — primary browser; all tests must pass - **Chromium** — secondary browser; all tests must also pass ## File Naming Convention ``` test_step_.py ``` Each file corresponds to one implementation step. Tests within a file cover both green paths (happy flow) and red paths (bad inputs, edge cases, error states). ## Test Files | File | Feature | Tests | | --------------------------------------- | ------------------------------------------- | ------- | | `test_step0_scaffolding.py` | App shell, navigation, i18n | 5 | | `test_step1_database.py` | DB init, CRUD, persistence | 15 | | `test_step2_settings.py` | Language, theme, name, DB export/restore | 21 | | `test_step2b_schema_hardening.py` | UNIQUE constraints, suffix table | 10 | | `test_step3_exercises.py` | Exercise CRUD, search, validation | 17 | | `test_step3b_exercise_export_import.py` | JSON export/import, collisions, suffixes | 23 | | `test_step3c_backup.py` | Backup filename, reminder, threshold | 11 | | `test_step4_combos.py` | Combo CRUD, exercise ordering, reps/weight | 19 | | `test_step5_sessions.py` | Session CRUD, items, reps/weight | 20 | | `test_step6_collections_home.py` | Collections CRUD, home page stats | 19 | | `test_step7_import_export.py` | Full multi-entity export/import | 14 | | `test_step8_execution.py` | Execution mode, queue, partial logs | 17 | | `test_step9_stats.py` | Statistics charts, streak, date range | 16 | | `test_step10_pwa.py` | PWA manifest, install prompt, accessibility | 11 | | `test_step12_timers.py` | EMOM/AMRAP/TABATA timers, pause/resume | 20 | | `test_step13_markdown.py` | Markdown rendering in detail views | 9 | | `test_step14_form_shortcuts.py` | Ctrl+Enter save, Escape cancel on forms | 10 | | `test_step15_audio_cues.py` | TABATA/AMRAP audio cue timing (fake clock) | 7 | | **Total** | | **264** | ## Infrastructure - **`conftest.py`**: Pytest fixtures. Starts the Vite dev server (`npm run dev -- --port 5199`) before the first test and stops it after all tests complete. Handles multiple concurrent workers safely using file locks. - **`pytest.ini`**: Sets `base_url = http://localhost:5199`. - **`run_parallel.sh`**: Shell wrapper for `pytest-xdist` parallel runs. Accepts `PYTEST_WORKERS` and `PYTEST_BROWSERS` environment variables. - **`requirements.txt`**: `playwright`, `pytest`, `pytest-playwright`, `pytest-xdist`.