WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: add test plan for user theme preferences

+171
+171
docs/test-plans/2026-03-20-user-theme-preferences.md
··· 1 + # Human Test Plan: User Theme Preferences 2 + 3 + **Feature branch:** `user-theme-preferences` 4 + **Automated coverage:** 18/18 ACs passing (1266 tests, 0 failures) 5 + 6 + --- 7 + 8 + ## Prerequisites 9 + 10 + - Development environment running via `devenv shell` 11 + - Dependencies installed via `pnpm install` 12 + - `.env` file configured with valid `APPVIEW_URL` 13 + - Development server started with `pnpm dev` 14 + - All automated tests passing: `pnpm --filter @atbb/web test` 15 + - At least two themes registered in the forum's theme policy (one light, one dark) 16 + - An AT Protocol account available for login (e.g., a test Bluesky account) 17 + 18 + --- 19 + 20 + ## Human Verification Required 21 + 22 + The following items cannot be validated by automated tests and **must be verified manually**: 23 + 24 + | ID | Criterion | Why Manual | 25 + |----|-----------|------------| 26 + | HV1 | HTMX live preview swap (AC1.3, AC1.4) | HTMX client-side JS intercepts `<select>` change events and performs DOM replacement. The test harness cannot exercise browser-side JS behavior. | 27 + | HV2 | Visual swatch correctness (AC6.1) | Automated tests verify swatch HTML and inline styles exist but cannot assess whether rendered colors are visually correct or CSS layout makes them visible. | 28 + | HV3 | Cookie persistence across sessions (AC2.1, AC3.1, AC3.2) | Integration tests verify Set-Cookie headers and cookie reading logic but cannot verify actual browser cookie storage and persistence across full browser restarts. | 29 + 30 + --- 31 + 32 + ## Phase 1: Settings Page Access and Navigation 33 + 34 + | Step | Action | Expected | 35 + |------|--------|----------| 36 + | 1.1 | Open the forum homepage in a browser while not logged in. Inspect the site header (desktop) and hamburger menu (mobile). | No "Settings" link is visible in either desktop or mobile navigation. "Log in" is visible. | 37 + | 1.2 | Click "Log in" and authenticate with a valid AT Protocol account. | Redirect to the forum homepage after successful login. | 38 + | 1.3 | Inspect the site header (desktop viewport, 1024px+). | A "Settings" link with `href="/settings"` is visible in the desktop navigation bar alongside the handle and "Log out" button. | 39 + | 1.4 | Resize the browser to mobile width (below 768px) and open the hamburger menu. | A "Settings" link is visible in the mobile dropdown navigation. | 40 + | 1.5 | Click the "Settings" link (either desktop or mobile). | Browser navigates to `/settings`. Page loads with a 200 status. The page title contains "Settings". | 41 + | 1.6 | Open a private/incognito window and navigate directly to `/settings` without logging in. | Browser is redirected to `/login`. The URL bar shows `/login`. | 42 + 43 + --- 44 + 45 + ## Phase 2: Theme Selection Form Rendering 46 + 47 + | Step | Action | Expected | 48 + |------|--------|----------| 49 + | 2.1 | On `/settings` while authenticated, inspect the form. | Two `<select>` dropdowns are present: one labeled for light theme (`id="lightThemeUri"`) and one for dark theme (`id="darkThemeUri"`). Each lists the available themes from the forum's theme policy. | 50 + | 2.2 | Open browser DevTools and inspect the `<select>` elements. | Each select has these attributes: `hx-get="/settings/preview"`, `hx-trigger="change"`, `hx-target="#theme-preview"`, `hx-swap="outerHTML"`, `hx-include="this"`. | 51 + | 2.3 | Verify that a `<div id="theme-preview">` element exists on the page below the selects. | The div is present and initially empty (no swatch content). | 52 + 53 + --- 54 + 55 + ## Phase 3: HTMX Live Preview — HV1 56 + 57 + | Step | Action | Expected | 58 + |------|--------|----------| 59 + | 3.1 | On `/settings`, change the light theme dropdown to a different theme. | Without a full page reload, the `#theme-preview` area updates to show the theme name and five colored swatch squares representing `color-bg`, `color-surface`, `color-primary`, `color-text`, and `color-border`. | 60 + | 3.2 | Open the browser Network tab (DevTools). Change the light theme dropdown again. | A GET request to `/settings/preview?lightThemeUri=at://...` appears in the network log. Response is 200 with an HTML fragment. No full page navigation occurs. | 61 + | 3.3 | Change the dark theme dropdown to a different dark theme. | The `#theme-preview` area updates with the dark theme's name and swatches. The network log shows a GET to `/settings/preview?darkThemeUri=at://...`. | 62 + | 3.4 | Open the browser Console tab. Perform several dropdown changes. | No JavaScript errors appear in the console during any preview interaction. | 63 + 64 + --- 65 + 66 + ## Phase 4: Saving Preferences 67 + 68 + | Step | Action | Expected | 69 + |------|--------|----------| 70 + | 4.1 | Select a specific light theme and a specific dark theme from the dropdowns. Click "Save preferences". | Browser redirects to `/settings?saved=1`. A success banner reading "Preferences saved." is visible. | 71 + | 4.2 | Open browser DevTools > Application > Cookies. Filter for the current domain. | Two cookies are present: `atbb-light-theme` (AT URI matching the selected light theme) and `atbb-dark-theme` (AT URI matching the selected dark theme). Both have `Path=/`, `Max-Age=31536000` (1 year), and `SameSite=Lax`. | 72 + | 4.3 | Refresh the `/settings` page. | The light and dark theme dropdowns pre-select the previously saved themes. The `selected` attribute is on the correct `<option>` elements. | 73 + 74 + --- 75 + 76 + ## Phase 5: Theme Application on Page Load 77 + 78 + | Step | Action | Expected | 79 + |------|--------|----------| 80 + | 5.1 | After saving preferences, navigate to the forum homepage (`/`). | The page renders using the selected light theme's color tokens. | 81 + | 5.2 | Click the color scheme toggle to switch to dark mode. | The page reloads and renders using the selected dark theme's color tokens. An `atbb-color-scheme=dark` cookie is set. | 82 + | 5.3 | Navigate to several pages (topic list, category view, etc.) while in dark mode. | All pages consistently use the selected dark theme. No flash of the default theme occurs during navigation. | 83 + 84 + --- 85 + 86 + ## Phase 6: Visual Swatch Correctness — HV2 87 + 88 + | Step | Action | Expected | 89 + |------|--------|----------| 90 + | 6.1 | On `/settings`, change the light theme dropdown. | The preview area shows visually distinct colored squares. Each swatch has a visible background color matching the theme's token values. | 91 + | 6.2 | Hover over each swatch (or inspect via DevTools). | Each swatch has a `title` attribute indicating the token (`color-bg`, `color-primary`, etc.). The inline `style="background:<color>"` matches the token value. | 92 + | 6.3 | Verify the theme name label above the swatches. | The name is clearly readable and matches the theme selected in the dropdown. | 93 + | 6.4 | Repeat steps 6.1-6.3 for a dark theme selection. | Dark theme swatches show appropriately dark colors. The theme name is correct. | 94 + 95 + --- 96 + 97 + ## Phase 7: Cookie Persistence Across Browser Sessions — HV3 98 + 99 + | Step | Action | Expected | 100 + |------|--------|----------| 101 + | 7.1 | Save theme preferences on `/settings` with non-default themes. | "Preferences saved." banner appears. | 102 + | 7.2 | Fully close the browser (all windows, not just the tab). | Browser process exits. | 103 + | 7.3 | Reopen the browser and navigate to the forum homepage. | The forum renders with the previously selected theme, not the forum default. | 104 + | 7.4 | Navigate to `/settings`. | The dropdowns show the previously saved selections. | 105 + | 7.5 | Switch to dark mode via the toggle and close/reopen the browser. | Dark mode with the custom dark theme persists across the browser restart. | 106 + 107 + --- 108 + 109 + ## Phase 8: Validation Error Flows 110 + 111 + | Step | Action | Expected | 112 + |------|--------|----------| 113 + | 8.1 | Using browser DevTools Console, submit a POST to `/settings/appearance` with a `lightThemeUri` not in the available themes. | Browser redirects to `/settings?error=invalid-theme`. No cookies are set or modified. | 114 + | 8.2 | Submit a POST to `/settings/appearance` with an empty body. | Browser redirects to `/settings?error=invalid`. | 115 + 116 + --- 117 + 118 + ## End-to-End: Full Theme Preference Lifecycle 119 + 120 + **Purpose:** Validate the complete flow from unauthenticated state through preference selection, persistence, application, and cross-session retention. 121 + 122 + 1. Open incognito window. Navigate to the forum homepage. Verify default theme is applied. 123 + 2. Navigate to `/settings`. Confirm redirect to `/login`. 124 + 3. Log in with a valid AT Protocol account. Navigate to `/settings`. 125 + 4. Verify the light and dark theme dropdowns are populated and defaults are selected. 126 + 5. Change the light theme dropdown. Verify the preview updates without page reload (HTMX swap). 127 + 6. Change the dark theme dropdown. Verify the preview updates with the dark theme's swatches. 128 + 7. Click Save. Confirm "Preferences saved." banner and `/settings?saved=1` URL. 129 + 8. Navigate to the homepage. Verify the selected light theme is applied. 130 + 9. Toggle to dark mode. Verify the selected dark theme is applied. 131 + 10. Close the browser entirely. Reopen and navigate to the forum. Verify the dark theme persists. 132 + 11. Navigate to `/settings`. Verify both dropdowns still show the previously saved selections. 133 + 12. Log out. Navigate to `/settings`. Confirm redirect to `/login`. 134 + 135 + --- 136 + 137 + ## End-to-End: Admin Disables User Choice 138 + 139 + **Purpose:** Validate that the `allowUserChoice: false` policy flag gates the entire settings UI and POST endpoint. 140 + 141 + 1. As a forum administrator, set the theme policy to `allowUserChoice: false`. 142 + 2. Log in as a regular user. Navigate to `/settings`. 143 + 3. Verify the page shows an informational banner: "Theme selection is managed by the forum administrator". Verify no `<select>` dropdowns are present. 144 + 4. Using DevTools, manually POST to `/settings/appearance` with valid theme URIs. Verify the response is 302 to `/settings?error=not-allowed`. 145 + 5. Navigate to the forum homepage. Verify the forum default theme is applied regardless of any previously saved preference cookies. 146 + 147 + --- 148 + 149 + ## Traceability 150 + 151 + | Acceptance Criterion | Automated Test | Manual Step | 152 + |----------------------|----------------|-------------| 153 + | AC1.1: Settings link in nav | `base.test.tsx`: auth visibility + desktop/mobile rendering | Phase 1, steps 1.1–1.4 | 154 + | AC1.2: Settings page renders selects | `settings.test.tsx`: "renders form with light/dark theme selects" | Phase 2, step 2.1 | 155 + | AC1.3: Light select triggers preview | `settings.test.tsx`: "renders selects with hx-get attribute" | Phase 3, steps 3.1–3.2 — **HV1** | 156 + | AC1.4: Dark select triggers preview | `settings.test.tsx`: same hx-* attribute test | Phase 3, step 3.3 — **HV1** | 157 + | AC1.5: Unauth redirect to /login | `settings.test.tsx`: "redirects unauthenticated users to /login" | Phase 1, step 1.6 | 158 + | AC2.1: Form sets preference cookies | `settings.test.tsx`: "sets theme cookies and redirects" | Phase 4, steps 4.1–4.2 — **HV3** | 159 + | AC2.2: "Preferences saved" banner | `settings.test.tsx`: "GET /settings with ?saved=1 shows success banner" | Phase 4, step 4.1 | 160 + | AC2.3: Saved themes pre-selected | `settings.test.tsx`: "pre-selects current preference cookie" | Phase 4, step 4.3 | 161 + | AC3.1: Light cookie applied on load | `theme-resolution.test.ts`: unit + integration | Phase 5, step 5.1 — **HV3** | 162 + | AC3.2: Dark cookie applied on load | `theme-resolution.test.ts`: unit + integration | Phase 5, step 5.2 — **HV3** | 163 + | AC3.3: Stale cookie falls back | `theme-resolution.test.ts`: unit + integration | Automated only | 164 + | AC4.1: Reject URI not in policy | `settings.test.tsx`: invalid light/dark theme URI tests | Phase 8, step 8.1 | 165 + | AC4.2: Reject when allowUserChoice false | `settings.test.tsx`: "rejects when allowUserChoice: false" | E2E: Admin Disables User Choice, step 4 | 166 + | AC4.3: Reject missing/malformed body | `settings.test.tsx`: three partial-body tests | Phase 8, step 8.2 | 167 + | AC4.4: Policy fetch failure is safe | `settings.test.tsx`: "rejects when policy fetch fails" | Automated only | 168 + | AC5.1: Info banner when choice disabled | `settings.test.tsx`: "shows informational banner" | E2E: Admin Disables User Choice, steps 2–3 | 169 + | AC5.2: Resolution ignores cookie when disabled | `theme-resolution.test.ts`: unit + integration | E2E: Admin Disables User Choice, step 5 | 170 + | AC6.1: Preview returns swatch fragment | `settings.test.tsx`: valid lightThemeUri/darkThemeUri tests | Phase 6 — **HV2** | 171 + | AC6.2: Unknown URI returns empty fragment | `settings.test.tsx`: 4 edge-case tests | Automated only |