docs: update tests/README and GUIDE__Development with current test patterns

tests/README.md:
- Add shared helpers table (_helpers/ files and purpose)
- Update "Writing / modifying tests" to reference setup_badge_test_page;
  badge tests are now the canonical template
- Add "Hard-Won Lessons — Badge Print / IDB Tests" section covering:
  - __version guard: why ae_defaults.ts must include __version: 1 or
    store_versions.ts silently wipes ae_loc and loses trusted_access
  - IDB inject-then-reload pattern: why reload is required (liveQuery
    won't fire on raw IDB writes that bypass Dexie's notification system)
- Fix pre-existing lint warnings: bare URLs → code spans, trailing newline

GUIDE__Development.md:
- Add Required Check #5: run Playwright integration tests for auth/store
  or badge print changes; badge tests are the canonical template
- Add tests/README.md to Key Documentation table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-18 17:12:36 -04:00
parent 81741919a8
commit 639e436854
2 changed files with 76 additions and 10 deletions

View File

@@ -11,6 +11,11 @@
2. **Type Safety:** Ensure interfaces in `src/lib/types/ae_types.ts` match backend schemas.
3. **Reactivity Check:** Verify Svelte 5 runes (`$state`, `$derived`) are not creating race conditions with Dexie `liveQuery`.
4. **Build Check:** For major changes, run `npm run build:staging` to ensure no SSR or build-time failures.
5. **Integration Tests:** For changes to badge print, event layouts, or auth/store logic, run the relevant Playwright test file(s):
```bash
npx playwright test tests/event_badge_render.test.ts tests/event_badge_attendee_workflow.test.ts
```
Run the full suite with `npm run test:integration`. The badge tests (`event_badge_*.test.ts`) are the canonical integration test template.
## 2. Commit Policy
- **Atomic Commits:** One component or one logic fix per commit. Do not batch unrelated changes.
@@ -46,6 +51,7 @@ You are not working in a vacuum. Coordinate with the Backend Agent via MCP tools
| `documentation/AE__Architecture.md` | System architecture overview |
| `documentation/AE__Naming_Conventions.md` | Naming rules |
| `documentation/PROJECT__AE_Events_Launcher_Native_integration.md` | Electron/Launcher reference |
| `tests/README.md` | Playwright test guide — shared helpers, hard-won lessons, demo IDs |
## 6. URL Parameters

View File

@@ -25,20 +25,36 @@ Notes
- Tests in `tests/disabled/` are ignored by default (see `playwright.config.ts`). Move flaky or environment-dependent tests there.
- The runner starts a local dev server via `npm run dev` by default (see `playwright.config.ts:webServer`). Ensure the app can start on port `5173` or update the config.
Shared test helpers (`tests/_helpers/`)
| File | Purpose |
| --- | --- |
| `env.ts` | Constants: `testing_event_id`, `testing_account_id`, `mock_site_domain` |
| `ae_defaults.ts` | `ae_app_local_data_defaults` — full localStorage seed object with `__version` |
| `idb_helpers.ts` | `inject_badge_and_template()` — write badge + template records into IndexedDB |
| `minimal_v3_mocks.ts` | `attach_minimal_v3_routes()`, `seed_trusted_session()`, `setup_badge_test_page()` |
**`setup_badge_test_page(page, event_id)`** is the one-call `beforeEach` for any badge/event print page test. It wires the pageerror listener, all V3 API mocks, and the trusted auth localStorage seed in one call.
Writing / modifying tests
- Tests are TypeScript files under `tests/` and should export Playwright `test` blocks. Example header:
- Tests are TypeScript files under `tests/` and should export Playwright `test` blocks.
- The badge tests (`event_badge_*.test.ts`) are the **canonical template** — copy the pattern from there when adding tests for any new event module feature.
- Minimal `beforeEach` using shared helpers:
```ts
import { test, expect } from '@playwright/test';
import { testing_event_id } from './_helpers/env';
import { inject_badge_and_template } from './_helpers/idb_helpers'; // only if IDB needed
import { setup_badge_test_page } from './_helpers/minimal_v3_mocks';
test('example', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/OSIT/);
const event_id = testing_event_id;
test.beforeEach(async ({ page }) => {
await setup_badge_test_page(page, event_id);
});
```
- Use `page.route('**/v3/**', handler)` to mock backend responses for deterministic tests.
- Use `page.addInitScript` to inject `ae_loc` localStorage defaults when tests need authenticated/admin state.
- If you need IDB data (badge, template), use the inject-then-reload pattern (see Hard-Won Lessons below).
- Use `page.route('**/v3/**', handler)` to mock backend responses. `attach_minimal_v3_routes` covers the common cases; add inline `page.route()` calls only for test-specific overrides.
Adding new tests
- Create a new file `tests/my_feature.test.ts`.
@@ -58,6 +74,50 @@ Help
---
## Hard-Won Lessons — Badge Print / IDB Tests
These lessons came from debugging the badge attendee workflow tests. Document them here so the next person doesn't spend hours on the same issues.
### The `__version` Guard — Always Include It in `ae_app_local_data_defaults`
**Symptom:** Tests set `trusted_access: true` in `addInitScript`, but after `page.reload()` the print button is gone. Logging `$ae_loc.trusted_access` after reload shows `false`.
**Cause:** `src/lib/stores/store_versions.ts` is a module-level side-effect import that runs *before* `persisted()` hydrates the store. It reads `ae_loc` from localStorage and calls `localStorage.removeItem('ae_loc')` if `parsed.__version !== AE_LOC_VERSION`. After the wipe, `persisted()` falls back to its `initialValue` (app defaults where `trusted_access: false`), erasing the test's auth seed.
**Fix:** `ae_defaults.ts` must include `__version: 1` (matching `AE_LOC_VERSION` in `store_versions.ts`). This is already done — **do not remove it**.
```typescript
export const ae_app_local_data_defaults = {
__version: 1, // Must match AE_LOC_VERSION in store_versions.ts — store_versions.ts
// wipes ae_loc if version doesn't match. Tests will silently lose auth.
...
};
```
If `AE_LOC_VERSION` ever increments in `store_versions.ts`, update the value here too or every test that relies on `trusted_access` will silently break.
---
### The IDB Inject-Then-Reload Pattern
**Why reload?** Dexie's `liveQuery` subscribes to IDB change notifications. Writing directly to IDB via the raw `indexedDB` API (as `inject_badge_and_template` does) bypasses Dexie's notification system — `liveQuery` will not fire. Reloading the page forces Dexie to open fresh, query the now-populated IDB, and fire `liveQuery` with the seeded data.
**Correct pattern:**
```typescript
await page.goto(`/events/${event_id}/badges/${badge_id}/print`);
await page.waitForLoadState('domcontentloaded');
// First nav initializes the Dexie schema. Now inject data.
await page.evaluate(inject_badge_and_template, { badge, template });
// Reload so liveQuery starts fresh against populated IDB.
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
```
**Do not** try to `waitForFunction` for IDB changes after `inject_badge_and_template` without reloading — it will time out because liveQuery will not re-fire.
---
## Deep Dive: Testing IDAA Edit Form Components
This section documents hard-won lessons from writing `idaa_recovery_meeting_edit.test.ts`. These issues are not obvious and cost significant debugging time — read this before writing tests for any Svelte 5 form component.
@@ -231,8 +291,8 @@ await page.route(`**/v3/crud/event/${event_id}`, async (route) => {
## Development / Testing / Demo environment information
* Use snake_case (or Snake_Case or Snake_case or test_NASA_example or test_API_key)
* Aether test/demo base URL: 'http://demo.localhost:5173'
* Aether development API: 'https://dev-api.oneskyit.com'
* Aether test/demo base URL: `http://demo.localhost:5173`
* Aether development API: `https://dev-api.oneskyit.com`
These are IDs for records that we can use for testing. Please do not delete them. They are also used for demo purposes with clients.
@@ -276,4 +336,4 @@ These are IDs for records that we can use for testing. Please do not delete them
### Events Module (IDAA Recovery Meetings)
* Aether test/demo Event: '1Pkd025vvxU' (36) "IDAA Recovery Meeting Test"
* Aether test/demo Event: 'gIZgAjISkf8' (43) "IDAA Recovery Meeting Test"
* Aether test/demo Event: 'gIZgAjISkf8' (43) "IDAA Recovery Meeting Test"