You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
test(web): add integration specs, fixtures, and docs for issue #75
Add the Playwright-side of the full-stack integration test suite:
- ServerMocks fixture class with auto-reset before/after each spec;
extends Playwright base with serverMocks, authedPage, and dashboard
- 6 spec files: api-token-guard (4 HTTP), config-service (3 HTTP),
start-stop (2 browser), status-polling (1 browser),
error-propagation (1 HTTP), can-run (skipped placeholder)
- Integration spec index re-exporting the extended test/expect
- Vite integration config: embed VITE_STATUS_POLL_MS=3000 so status
poller fires every 3s rather than 20s during integration runs
- Playwright integration config: raise Nest startup timeout 30s→120s
to accommodate ESM loading latency on WSL2/DrvFs (~50s observed)
- gitignore: exclude dist-integration/ build artifacts
- CLAUDE.md: promote two-tier table to three-tier; add integration
test conventions section; update reference docs table
- docs/docs/components/integration-tests.md: full architecture doc
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|**Unit / integration**|`npm run app:test`| Vitest. Server-side logic, hooks, helpers run under the `node` environment; React component specs in `@gsd/web` run under `jsdom` via `environmentMatchGlobs`. No real network — AWS SDK mocked via `aws-sdk-client-mock`; the `@gsd/web` API client is stubbed via `vi.mock`. | Pure logic, hook behaviour, server controllers, **per-component React behaviour** (rendering, callbacks, internal state transitions). |
169
170
|**E2E (tier 1 — #74)**|`npm run app:test:e2e`| Playwright against `vite build` + `vite preview`. Nest server never runs; every `/api/*` call is stubbed at the network layer via `page.route()`. | User-visible flows: routing, auth gate, button interactions, status-badge rendering, optimistic updates. |
170
-
171
-
A planned **tier 2** (#75) will add full-stack specs (real Nest + mocked AWS SDK) for scenarios that require real HTTP contract validation between the client and server. Until that lands, all browser-facing specs belong in tier 1.
171
+
|**Integration (tier 2 — #75)**|`npm run app:test:integration`| Playwright against `vite build (integration config)` + `vite preview` + real Nest server on `:3002`. AWS SDK intercepted by `aws-sdk-client-mock`. Mock state pushed via `ServerMocks` fixture to `/api/test/mocks/*`. | Real HTTP contract validation, `ApiTokenGuard` behaviour, `ConfigService` tfstate parsing, start/stop flows end-to-end, error propagation from ECS through the API response. |
172
172
173
173
**React component unit tests (`@gsd/web`):**
174
174
- Use **Vitest + jsdom + `@testing-library/react` + `@testing-library/user-event`**. `@testing-library/jest-dom` matchers (`toBeInTheDocument`, `toHaveTextContent`, etc.) are auto-loaded via `app/vitest.setup.ts`.
@@ -180,7 +180,7 @@ A planned **tier 2** (#75) will add full-stack specs (real Nest + mocked AWS SDK
180
180
- Each routed page (`DashboardPage`, `CostsPage`, `DiscordPage`, `LogsPage`, `SettingsPage`) gets a co-located `*.test.tsx` that mounts the page through `renderPage()` (`app/packages/web/src/test-utils/renderPage.tsx`). The helper wraps children in `PollingProvider → GameStatusProvider → MemoryRouter` so the same provider stack the production app uses is exercised; pass `initialEntries` when the page reads `useLocation`.
181
181
- Mock `../api.js` with `vi.mock` + `vi.hoisted` so the page drives off canned data instead of real fetches. Stub every method the page (and the GameStatusProvider above it) calls — at minimum `api.status` and `api.costsEstimate` — or the test will hang waiting for the polling registry to settle.
182
182
- These tests are intentionally **complementary** to the e2e tier, not a replacement: the e2e specs prove the indicator + chrome render at the route level under a real Vite preview build; the unit tests pin the page's own provider wiring (e.g. that `<PollingIndicator />` resolves to "Updated …" once the mocked status poll resolves) and let us iterate on the page layout without spinning up Playwright.
183
-
- Keep page-test scope tight: smoke-render each header section, exercise interactive controls that aren't already covered by a child component's unit test, and verify the polling indicator wiring. Anything that requires real HTTP belongs in the planned tier-2 specs (#75).
183
+
- Keep page-test scope tight: smoke-render each header section, exercise interactive controls that aren't already covered by a child component's unit test, and verify the polling indicator wiring. Anything that requires real HTTP belongs in tier-2 integration specs (`e2e/integration-specs/`).
184
184
185
185
**Playwright conventions:**
186
186
- Specs live under `app/packages/web/e2e/specs/`.
@@ -191,6 +191,13 @@ A planned **tier 2** (#75) will add full-stack specs (real Nest + mocked AWS SDK
191
191
- Use the `authedPage` fixture (token pre-seeded in localStorage) only when a spec needs raw `Page` access (e.g. to call `stubApis` or `addInitScript`); otherwise prefer the higher-level page-object fixtures.
192
192
- Stubs must cover every `/api/*` endpoint the page hits, or the catch-all returns 404 and the test will surface the missing stub quickly.
193
193
194
+
**Integration test conventions (tier 2):**
195
+
- Specs live under `app/packages/web/e2e/integration-specs/`. Import `{ test, expect }` from `./index.js` (NOT from `@playwright/test`) — the extended `test` includes the `serverMocks`, `authedPage`, and `dashboard` fixtures.
196
+
-`serverMocks` (`ServerMocks` from `e2e/fixtures/server-mocks.ts`) pushes queued responses to the test server via `POST /api/test/mocks/*`. Always include it in test parameters — it resets the MockStore before and after each spec automatically.
197
+
- The test Nest server (`test-main.ts`) runs on `:3002`; the Vite integration preview (port 4174) proxies `/api` to it. Pure HTTP tests call `http://localhost:3002/api/...` directly (bypasses the proxy). Browser tests navigate to the `baseURL` (port 4174) and the proxy routes API calls.
198
+
-`workers: 1` and `fullyParallel: false` in `playwright.integration.config.ts` are intentional — the shared in-process `MockStore` cannot be used concurrently.
199
+
- The integration Vite build sets `VITE_STATUS_POLL_MS=3000` so pollers fire every 3 s instead of 20 s, keeping status-polling specs fast without busy-looping.
200
+
194
201
## Git & Branch Workflow
195
202
196
203
`main` is a protected branch — direct pushes are blocked. All changes go through a PR, including trivial chores (`.gitignore` entries, config tweaks). Never commit directly to `main`.
0 commit comments