test(ui): migrate suite to the app-shell (state-driven navigation)
- Unit: repoint moved screen imports (lib/screens, lib/game), mock $lib/app-nav (appScreen/activeView) instead of $app/navigation, drop the removed gameId props, assert screen/view selection. - e2e: add a dev-only window.__galaxyNav affordance; specs enter a game via enterGame(...) instead of a /games/:id URL; URL assertions become content assertions (the URL stays /game/); reload uses waitUntil:"commit" (shallow routing) and mocks /rpc on game entry. - Remove the obsolete report scroll-restore test (it relied on a SvelteKit route Snapshot that no longer exists); update the missing-membership test to the new lobby-redirect+toast behaviour. Fix a stale report.svelte docstring. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,18 +2,19 @@
|
||||
// boots an authenticated session through `/__debug/store` (the
|
||||
// in-game shell makes a handful of gateway calls — for the lobby
|
||||
// record, the report, and the order read-back; we don't mock them
|
||||
// here, the shell tolerates ECONNREFUSED), navigates into
|
||||
// `/games/<game-id>/map`, and exercises one slice of the chrome:
|
||||
// here, the shell tolerates ECONNREFUSED), enters the game through
|
||||
// the dev-only `window.__galaxyNav` affordance (the single-URL
|
||||
// app-shell has no `/games/<id>/<view>` route — the address bar
|
||||
// stays at the app base), and exercises one slice of the chrome:
|
||||
// header navigation, sidebar tab preservation, mobile bottom-tabs,
|
||||
// and the breakpoint switches at 768 / 1024 px.
|
||||
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
|
||||
// The `window.__galaxyDebug` surface is owned by
|
||||
// `src/routes/__debug/store/+page.svelte` and typed by
|
||||
// `tests/e2e/storage-keypair-persistence.spec.ts`. This spec only
|
||||
// needs the auth-bootstrap subset (`clearSession`,
|
||||
// `setDeviceSessionId`); the merged global declaration covers both.
|
||||
// `window.__galaxyDebug` is owned by `src/routes/__debug/store/+page.svelte`
|
||||
// (auth bootstrap) and `window.__galaxyNav` by `src/routes/+page.svelte`
|
||||
// (dev-only screen/view driver); both are typed by
|
||||
// `tests/e2e/storage-keypair-persistence.spec.ts`.
|
||||
|
||||
const SESSION_ID = "phase-10-shell-session";
|
||||
// GAME_ID has to be a real UUID — Phase 14's auto-sync calls
|
||||
@@ -30,7 +31,14 @@ async function bootShell(page: Page): Promise<void> {
|
||||
(id) => window.__galaxyDebug!.setDeviceSessionId(id),
|
||||
SESSION_ID,
|
||||
);
|
||||
await page.goto(`/games/${GAME_ID}/map`);
|
||||
// Load the app (seeded session → authenticated → lobby), then enter
|
||||
// the game via the in-memory nav affordance.
|
||||
await page.goto("/");
|
||||
await page.waitForFunction(() => window.__galaxyNav !== undefined);
|
||||
await page.evaluate(
|
||||
(id) => window.__galaxyNav!.enterGame(id, "map", {}),
|
||||
GAME_ID,
|
||||
);
|
||||
await expect(page.getByTestId("game-shell")).toBeVisible();
|
||||
await expect(page.getByTestId("active-view-map")).toBeVisible();
|
||||
}
|
||||
@@ -50,23 +58,20 @@ test("shell mounts with header / sidebar / active-view chrome", async ({
|
||||
test("header view-menu navigates to every active view", async ({ page }) => {
|
||||
await bootShell(page);
|
||||
|
||||
const destinations: Array<[string, string, string]> = [
|
||||
["view-menu-item-report", "active-view-report", "/report"],
|
||||
["view-menu-item-mail", "active-view-mail", "/mail"],
|
||||
["view-menu-item-battle", "active-view-battle", "/battle"],
|
||||
[
|
||||
"view-menu-item-designer-science",
|
||||
"active-view-designer-science",
|
||||
"/designer/science",
|
||||
],
|
||||
["view-menu-item-map", "active-view-map", "/map"],
|
||||
// The address bar stays at the app base in the single-URL app-shell,
|
||||
// so the visible active view is the only navigation signal to assert.
|
||||
const destinations: Array<[string, string]> = [
|
||||
["view-menu-item-report", "active-view-report"],
|
||||
["view-menu-item-mail", "active-view-mail"],
|
||||
["view-menu-item-battle", "active-view-battle"],
|
||||
["view-menu-item-designer-science", "active-view-designer-science"],
|
||||
["view-menu-item-map", "active-view-map"],
|
||||
];
|
||||
|
||||
for (const [trigger, viewTestId, urlSuffix] of destinations) {
|
||||
for (const [trigger, viewTestId] of destinations) {
|
||||
await page.getByTestId("view-menu-trigger").click();
|
||||
await page.getByTestId(trigger).click();
|
||||
await expect(page.getByTestId(viewTestId)).toBeVisible();
|
||||
await expect(page).toHaveURL(new RegExp(`/games/${GAME_ID}${urlSuffix}$`));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -92,9 +97,6 @@ test("header view-menu Tables sub-list navigates to every entity", async ({
|
||||
const view = page.getByTestId("active-view-table");
|
||||
await expect(view).toBeVisible();
|
||||
await expect(view).toHaveAttribute("data-entity", entity);
|
||||
await expect(page).toHaveURL(
|
||||
new RegExp(`/games/${GAME_ID}/table/${entity}$`),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user