# Testing

**The working test plan is `docs/test-plan.html`** — open it in a browser. 243 rows across six
panels (user, org, admin, token API, automated suite, cross-cutting), each with pass/fail state
and a note field saved in `localStorage`, plus the known gaps. That file is where testing is
tracked; this one exists so a fresh clone knows it is there.

> `docs/` is gitignored (`.gitignore:29`), so `test-plan.html` does **not** ship with the repo.
> Decide before handover whether it should.

```bash
composer test                 # 295 PHPUnit tests in 39 files (~7s)
php vendor/bin/phpunit --filter test_name_fragment
php vendor/bin/phpunit tests/Feature/BookingServiceTest.php

npm run e2e                   # 13 Playwright specs in 6 files
npm run e2e:ui                # interactive runner
npm run e2e:report            # last HTML report
```

## Rules

- **Class-based PHPUnit** (`extends TestCase`, `testX()` methods). **Pest is not adopted** — do
  not add it.
- **Write the test before the fix** when fixing a bug, and **confirm it fails on the old code**.
  An assertion that passes either way is not a regression test.
- **Run the suite before declaring a task done.**
- `tests/Feature/TenancyIsolationTest.php` **must stay green at all times**. Cross-tenant access
  is a test failure, full stop.
- `tests/Unit/Engine*` run **without a database** — that is the point of keeping `app/Flow/*`
  pure, and why they are the fastest signal in the suite.
