Files
waggle-os/tests/e2e/boot-screen-skip.spec.ts
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

97 lines
3.7 KiB
TypeScript

/**
* H-01 · QW-3 regression — skip BootScreen on return visits.
*
* apps/web/src/pages/Index.tsx gates BootScreen on a `waggle-booted`
* localStorage key. First visit: key absent → BootScreen mounts, runs
* through phase animation, calls `onComplete` which writes the key and
* sets `booted=true`. Subsequent visits: key present → BootScreen never
* mounts; Desktop renders immediately.
*
* Guards three properties:
* 1. Fresh storage shows BootScreen (behavior under the gate).
* 2. Pre-seeded BOOT_KEY makes BootScreen skip entirely.
* 3. Completing the boot writes the key and persists across reload.
*
* Run: npx playwright test tests/e2e/boot-screen-skip.spec.ts --reporter=list
*/
import { test, expect, type Page } from '@playwright/test';
const BASE = process.env.WAGGLE_E2E_BASE_URL ?? 'http://127.0.0.1:3333';
const BOOT_KEY = 'waggle-booted';
const BOOT_SCREEN = '[data-testid="boot-screen"]';
async function clearBootFlag(page: Page) {
// Fresh-storage setup: wipe BOOT_KEY before React mounts. Using
// addInitScript so the removal lands before the useState initializer
// in Index.tsx reads localStorage. Wrap in try-catch because some
// browsers throw on localStorage access in file:// contexts.
await page.addInitScript(() => {
try {
window.localStorage.removeItem('waggle-booted');
} catch {
// ignore — localStorage unavailable
}
});
}
async function seedBootFlag(page: Page) {
// Return-visit setup: mark boot as completed before first navigation.
await page.addInitScript(() => {
try {
window.localStorage.setItem('waggle-booted', 'true');
} catch {
// ignore
}
});
}
test.describe('H-01 · QW-3 · BootScreen skip on return visits', () => {
test('fresh storage renders BootScreen', async ({ page }) => {
await clearBootFlag(page);
await page.goto(`${BASE}/`);
// BootScreen should mount immediately (before the ~2.5s auto-advance
// completes). 1s window is well inside the animation runtime.
await expect(page.locator(BOOT_SCREEN)).toBeVisible({ timeout: 1_000 });
});
test('pre-seeded BOOT_KEY skips BootScreen entirely', async ({ page }) => {
await seedBootFlag(page);
await page.goto(`${BASE}/`);
await page.waitForLoadState('domcontentloaded');
// Assert BootScreen never mounted. toHaveCount(0) proves non-rendered,
// not merely off-screen — the AnimatePresence branch in Index.tsx
// conditionally renders on `!booted`.
await expect(page.locator(BOOT_SCREEN)).toHaveCount(0);
// Sanity: confirm the localStorage key survived into the page runtime.
const bootFlag = await page.evaluate(() => window.localStorage.getItem('waggle-booted'));
expect(bootFlag).not.toBeNull();
});
test('completing boot persists the flag across reload', async ({ page }) => {
await clearBootFlag(page);
await page.goto(`${BASE}/`);
// First visit: BootScreen visible.
await expect(page.locator(BOOT_SCREEN)).toBeVisible({ timeout: 1_000 });
// Click to skip — BootScreen listens for click + keydown and fires
// `onComplete`, which writes BOOT_KEY and flips the booted state.
await page.locator(BOOT_SCREEN).click();
// Wait for BootScreen to unmount (AnimatePresence exit anim ~500ms).
await expect(page.locator(BOOT_SCREEN)).toHaveCount(0, { timeout: 3_000 });
// The flag should now be persisted.
const bootFlag = await page.evaluate(() => window.localStorage.getItem('waggle-booted'));
expect(bootFlag).toBe('true');
// Reload — BootScreen must stay skipped.
await page.reload();
await page.waitForLoadState('domcontentloaded');
await expect(page.locator(BOOT_SCREEN)).toHaveCount(0);
});
});