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
Human Test Plan: User Theme Preferences#
Feature branch: user-theme-preferences
Automated coverage: 18/18 ACs passing (1266 tests, 0 failures)
Prerequisites#
- Development environment running via
devenv shell - Dependencies installed via
pnpm install .envfile configured with validAPPVIEW_URL- Development server started with
pnpm dev - All automated tests passing:
pnpm --filter @atbb/web test - At least two themes registered in the forum's theme policy (one light, one dark)
- An AT Protocol account available for login (e.g., a test Bluesky account)
Human Verification Required#
The following items cannot be validated by automated tests and must be verified manually:
| ID | Criterion | Why Manual |
|---|---|---|
| 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. |
| 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. |
| 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. |
Phase 1: Settings Page Access and Navigation#
| Step | Action | Expected |
|---|---|---|
| 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. |
| 1.2 | Click "Log in" and authenticate with a valid AT Protocol account. | Redirect to the forum homepage after successful login. |
| 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. |
| 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. |
| 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". |
| 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. |
Phase 2: Theme Selection Form Rendering#
| Step | Action | Expected |
|---|---|---|
| 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. |
| 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". |
| 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). |
Phase 3: HTMX Live Preview — HV1#
| Step | Action | Expected |
|---|---|---|
| 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. |
| 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. |
| 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://.... |
| 3.4 | Open the browser Console tab. Perform several dropdown changes. | No JavaScript errors appear in the console during any preview interaction. |
Phase 4: Saving Preferences#
| Step | Action | Expected |
|---|---|---|
| 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. |
| 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. |
| 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. |
Phase 5: Theme Application on Page Load#
| Step | Action | Expected |
|---|---|---|
| 5.1 | After saving preferences, navigate to the forum homepage (/). |
The page renders using the selected light theme's color tokens. |
| 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. |
| 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. |
Phase 6: Visual Swatch Correctness — HV2#
| Step | Action | Expected |
|---|---|---|
| 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. |
| 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. |
| 6.3 | Verify the theme name label above the swatches. | The name is clearly readable and matches the theme selected in the dropdown. |
| 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. |
Phase 7: Cookie Persistence Across Browser Sessions — HV3#
| Step | Action | Expected |
|---|---|---|
| 7.1 | Save theme preferences on /settings with non-default themes. |
"Preferences saved." banner appears. |
| 7.2 | Fully close the browser (all windows, not just the tab). | Browser process exits. |
| 7.3 | Reopen the browser and navigate to the forum homepage. | The forum renders with the previously selected theme, not the forum default. |
| 7.4 | Navigate to /settings. |
The dropdowns show the previously saved selections. |
| 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. |
Phase 8: Validation Error Flows#
| Step | Action | Expected |
|---|---|---|
| 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. |
| 8.2 | Submit a POST to /settings/appearance with an empty body. |
Browser redirects to /settings?error=invalid. |
End-to-End: Full Theme Preference Lifecycle#
Purpose: Validate the complete flow from unauthenticated state through preference selection, persistence, application, and cross-session retention.
- Open incognito window. Navigate to the forum homepage. Verify default theme is applied.
- Navigate to
/settings. Confirm redirect to/login. - Log in with a valid AT Protocol account. Navigate to
/settings. - Verify the light and dark theme dropdowns are populated and defaults are selected.
- Change the light theme dropdown. Verify the preview updates without page reload (HTMX swap).
- Change the dark theme dropdown. Verify the preview updates with the dark theme's swatches.
- Click Save. Confirm "Preferences saved." banner and
/settings?saved=1URL. - Navigate to the homepage. Verify the selected light theme is applied.
- Toggle to dark mode. Verify the selected dark theme is applied.
- Close the browser entirely. Reopen and navigate to the forum. Verify the dark theme persists.
- Navigate to
/settings. Verify both dropdowns still show the previously saved selections. - Log out. Navigate to
/settings. Confirm redirect to/login.
End-to-End: Admin Disables User Choice#
Purpose: Validate that the allowUserChoice: false policy flag gates the entire settings UI and POST endpoint.
- As a forum administrator, set the theme policy to
allowUserChoice: false. - Log in as a regular user. Navigate to
/settings. - Verify the page shows an informational banner: "Theme selection is managed by the forum administrator". Verify no
<select>dropdowns are present. - Using DevTools, manually POST to
/settings/appearancewith valid theme URIs. Verify the response is 302 to/settings?error=not-allowed. - Navigate to the forum homepage. Verify the forum default theme is applied regardless of any previously saved preference cookies.
Traceability#
| Acceptance Criterion | Automated Test | Manual Step |
|---|---|---|
| AC1.1: Settings link in nav | base.test.tsx: auth visibility + desktop/mobile rendering |
Phase 1, steps 1.1–1.4 |
| AC1.2: Settings page renders selects | settings.test.tsx: "renders form with light/dark theme selects" |
Phase 2, step 2.1 |
| AC1.3: Light select triggers preview | settings.test.tsx: "renders selects with hx-get attribute" |
Phase 3, steps 3.1–3.2 — HV1 |
| AC1.4: Dark select triggers preview | settings.test.tsx: same hx-* attribute test |
Phase 3, step 3.3 — HV1 |
| AC1.5: Unauth redirect to /login | settings.test.tsx: "redirects unauthenticated users to /login" |
Phase 1, step 1.6 |
| AC2.1: Form sets preference cookies | settings.test.tsx: "sets theme cookies and redirects" |
Phase 4, steps 4.1–4.2 — HV3 |
| AC2.2: "Preferences saved" banner | settings.test.tsx: "GET /settings with ?saved=1 shows success banner" |
Phase 4, step 4.1 |
| AC2.3: Saved themes pre-selected | settings.test.tsx: "pre-selects current preference cookie" |
Phase 4, step 4.3 |
| AC3.1: Light cookie applied on load | theme-resolution.test.ts: unit + integration |
Phase 5, step 5.1 — HV3 |
| AC3.2: Dark cookie applied on load | theme-resolution.test.ts: unit + integration |
Phase 5, step 5.2 — HV3 |
| AC3.3: Stale cookie falls back | theme-resolution.test.ts: unit + integration |
Automated only |
| AC4.1: Reject URI not in policy | settings.test.tsx: invalid light/dark theme URI tests |
Phase 8, step 8.1 |
| AC4.2: Reject when allowUserChoice false | settings.test.tsx: "rejects when allowUserChoice: false" |
E2E: Admin Disables User Choice, step 4 |
| AC4.3: Reject missing/malformed body | settings.test.tsx: three partial-body tests |
Phase 8, step 8.2 |
| AC4.4: Policy fetch failure is safe | settings.test.tsx: "rejects when policy fetch fails" |
Automated only |
| AC5.1: Info banner when choice disabled | settings.test.tsx: "shows informational banner" |
E2E: Admin Disables User Choice, steps 2–3 |
| AC5.2: Resolution ignores cookie when disabled | theme-resolution.test.ts: unit + integration |
E2E: Admin Disables User Choice, step 5 |
| AC6.1: Preview returns swatch fragment | settings.test.tsx: valid lightThemeUri/darkThemeUri tests |
Phase 6 — HV2 |
| AC6.2: Unknown URI returns empty fragment | settings.test.tsx: 4 edge-case tests |
Automated only |