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: add full-stack integration test suite (real Nest + mocked AWS SDK) (#124)
Closes#75
## Summary
- Adds a **tier-2 integration test suite** (`npm run
app:test:integration`) where a real Nest server runs on `:3002`, AWS SDK
calls are intercepted by `aws-sdk-client-mock`, and the Vite preview on
`:4174` proxies `/api` to it — no real AWS required
- New `ServerMocks` Playwright fixture class + extended `test` object
that resets `MockStore` before/after each spec; mock responses pushed to
the server via `POST /api/test/mocks/*`
- 6 spec files covering API token guard (401/200 auth), ConfigService
tfstate parsing, start/stop browser flows, status-badge polling
transitions, and ECS error propagation; `canRun()` spec stubbed pending
Discord integration
- Integration Vite config injects `VITE_STATUS_POLL_MS=3000` so
poll-based assertions complete in < 10 s; Nest server startup timeout
raised to 120 s for WSL2/DrvFs ESM loading latency
- `CLAUDE.md` two-tier strategy table updated to three-tier; integration
conventions section added; reference docs table updated
- `docs/docs/components/integration-tests.md` added: architecture
diagram, key-file table, mock response reference, spec inventory, design
constraints
## Test plan
- [ ] `npm run app:test:integration` — 11 pass, 1 skip (`canRun.spec.ts`
placeholder)
- [ ] `npm run app:test` (unit) — all pass, unaffected
- [ ] `npm run app:test:e2e` (tier-1) — all pass, unaffected
🤖 Generated with [Claude Code](https://claude.ai/claude-code)
---------
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