# QA Plan and Release Notes ## Automated coverage Run before a public release: ```bash npm run release:check npm run test:e2e ``` ### API integration tests File: `apps/api/src/__tests__/passport.integration.test.ts` Coverage: - Create demo passport user - Collect items - Prevent duplicate collection XP - Complete Group B challenge - Unlock Group B badge - Answer trivia - Submit giant-killing prediction - Unlock Giant Killer badge - Add memory - Unlock Memory Keeper badge - Verify leaderboard rank movement - Validate request errors and missing-user errors ### Web component tests File: `apps/web/src/__tests__/App.test.tsx` Coverage: - Loads content and renders onboarding state - Creates a passport through the API client - Shows collection board and empty badge state - Recovers when a stored local demo user is missing from the API memory store ### Playwright E2E File: `tests/e2e/demo.spec.ts` Coverage: - Browser journey from onboarding through collection, trivia, prediction, memory, badges, and leaderboard - Desktop Chromium project - Mobile Chrome viewport project - Automated Axe scan that fails on critical or serious accessibility violations ## Manual smoke test checklist Use the public demo script and verify: - [ ] App loads at `http://localhost:5173` - [ ] API health check returns `ok: true` - [ ] Create passport works with a valid display name - [ ] Display name shorter than 2 characters is blocked - [ ] Collection card buttons disable after collection - [ ] Duplicate API collection returns no additional XP - [ ] Trivia answer buttons disable after answer - [ ] Incorrect trivia still awards participation XP - [ ] Prediction can be updated before kick-off - [ ] Giant-killing prediction unlocks challenge and badge once - [ ] Memory form validates title and note lengths - [ ] Leaderboard rank changes after XP increases - [ ] Reset demo clears the local user and in-memory store ## Edge cases handled | Area | Handling | | --- | --- | | Missing user | `404 USER_NOT_FOUND`; web removes stale localStorage user and shows onboarding | | Unknown collection item | `404 COLLECTION_ITEM_NOT_FOUND` | | Duplicate collection | Action succeeds with explanatory message and zero new achievement events | | Duplicate trivia answer | Action succeeds with explanation and zero new trivia XP | | Invalid prediction team | `400 INVALID_PREDICTION_TEAM` | | Closed prediction | `409 PREDICTION_CLOSED` if match is no longer scheduled | | Invalid confidence | Zod + store confidence guard enforce 1–5 | | Missing optional memory match | Memory saves without match attachment | | Unknown memory match | `404 MATCH_NOT_FOUND` | | API unavailable | Web shows an alert with recovery copy | ## Accessibility QA Implemented: - Semantic landmarks: `header`, `main`, `section` - Skip link to main content - Visible labels for form fields - ARIA live region for action feedback - `role="alert"` for blocking errors - Native `progress` elements with labels - Disabled states for completed actions - High-contrast text on light panels - Reduced-motion media query - Keyboard-focusable controls without custom click-only elements - Table captioning through `aria-label` Manual checks to perform: - [ ] Navigate the full demo with keyboard only - [ ] Confirm focus order follows visual order - [ ] Confirm live status is announced by a screen reader - [ ] Confirm color is not the only way completion is shown - [ ] Run Playwright Axe test on a clean install - [ ] Test browser zoom at 200% ## Responsive QA notes Breakpoints in `apps/web/src/styles.css`: - `>1180px`: dense dashboard with 4-column challenge and badge layouts, 5-column collection cards - `<=1180px`: 2-column challenge/prediction/badge layouts and 3-column collection cards - `<=780px`: single-column mobile layout, stacked hero, stacked forms, horizontal table wrapper Manual device matrix: | Viewport | Expected result | | --- | --- | | 1440 × 900 | Full dashboard visible with multi-column cards | | 1024 × 768 | Cards wrap to 2–3 columns, no overlap | | 390 × 844 | Single-column mobile layout, buttons full width where appropriate | | 320 × 568 | No horizontal scrolling except leaderboard table wrapper | | 200% zoom desktop | Content remains readable and actionable | ## Known demo constraints - The API store is in-memory; resetting the process clears demo users. - Match data is representative and deterministic, not official final draw data. - There is no authentication in the demo build. - Prediction settlement is not included because this milestone focuses on the pre-tournament / live-tournament action loop. - Images are represented by `imageHint` metadata; the demo UI uses styled cards rather than external media assets.