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:
Ilia Denisov
2026-05-23 20:49:35 +02:00
parent 80545e9f9d
commit 4e0058d46c
36 changed files with 707 additions and 343 deletions
+21 -12
View File
@@ -1,7 +1,10 @@
// Component tests for the create-game form. The lobby API is mocked
// Component tests for the create-game screen. The lobby API is mocked
// at module level; the GalaxyClient is replaced with a stub that does
// nothing (the test only asserts the createGame wrapper is invoked
// with the right shape).
// with the right shape). The app-shell navigation store is mocked so
// cancel and post-submit both resolve to `appScreen.go("lobby")`
// without running real `pushState` in JSDOM — the single-URL shell has
// no `/lobby` route.
import "fake-indexeddb/auto";
import { fireEvent, render, waitFor } from "@testing-library/svelte";
@@ -21,9 +24,13 @@ import { type GalaxyDB, openGalaxyDB } from "../src/platform/store/idb";
import { IDBCache } from "../src/platform/store/idb-cache";
import { WebCryptoKeyStore } from "../src/platform/store/webcrypto-keystore";
const gotoSpy = vi.fn<(url: string) => Promise<void>>(async () => {});
vi.mock("$app/navigation", () => ({
goto: (url: string) => gotoSpy(url),
// The create screen returns to the lobby through `appScreen.go("lobby")`,
// which internally calls SvelteKit `pushState`. Mock the whole nav
// module so the spy captures the transition and no real history
// mutation runs in JSDOM.
const appScreenGoSpy = vi.fn();
vi.mock("$lib/app-nav.svelte", () => ({
appScreen: { go: (...args: unknown[]) => appScreenGoSpy(...args) },
}));
const createGameSpy = vi.fn();
@@ -82,7 +89,7 @@ beforeEach(async () => {
await session.signIn("device-1");
i18n.resetForTests("en");
createGameSpy.mockReset();
gotoSpy.mockReset();
appScreenGoSpy.mockReset();
});
afterEach(async () => {
@@ -97,11 +104,13 @@ afterEach(async () => {
});
});
async function importCreatePage(): Promise<typeof import("../src/routes/lobby/create/+page.svelte")> {
return import("../src/routes/lobby/create/+page.svelte");
async function importCreatePage(): Promise<
typeof import("../src/lib/screens/lobby-create-screen.svelte")
> {
return import("../src/lib/screens/lobby-create-screen.svelte");
}
describe("lobby/create page", () => {
describe("lobby/create screen", () => {
test("submitting a valid form invokes createGame with the entered values and navigates back", async () => {
createGameSpy.mockResolvedValue({
gameId: "private-new",
@@ -150,7 +159,7 @@ describe("lobby/create page", () => {
expect(input.startGapPlayers).toBe(2);
expect(input.targetEngineVersion).toBe("v1");
expect(input.enrollmentEndsAt).toBeInstanceOf(Date);
expect(gotoSpy).toHaveBeenCalledWith("/lobby");
expect(appScreenGoSpy).toHaveBeenCalledWith("lobby");
});
});
@@ -179,7 +188,7 @@ describe("lobby/create page", () => {
});
});
test("cancel button navigates back to /lobby without calling the API", async () => {
test("cancel button navigates back to the lobby without calling the API", async () => {
const Page = (await importCreatePage()).default;
const ui = render(Page);
@@ -189,7 +198,7 @@ describe("lobby/create page", () => {
await fireEvent.click(ui.getByTestId("lobby-create-cancel"));
await waitFor(() => {
expect(gotoSpy).toHaveBeenCalledWith("/lobby");
expect(appScreenGoSpy).toHaveBeenCalledWith("lobby");
expect(createGameSpy).not.toHaveBeenCalled();
});
});