# 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<N>_<feature_name>.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`.
