import { test, expect, type Page } from "@playwright/test"; import { existsSync } from "node:fs"; import { resolve } from "node:path"; const romPath = resolve( process.env.CRYSTAL_ROM_PATH ?? "Pokemon - Crystal Version (UE) (V1.1) [C][!].gbc", ); test.beforeEach(() => test.skip(!existsSync(romPath), "Requires the local user ROM.")); async function start(page: Page) { await page.route("**/src/game/runtime.ts", async (route) => { const response = await route.fetch(), source = await response.text(); const needle = "const world = new GameWorld(assets);"; expect(source).toContain(needle); // Fixture worlds stand in for a saved session, so no introduction runs. expect(source).toContain("this.world?.beginIntro();"); await route.fulfill({ response, body: source.replace("this.world?.beginIntro();", "").replace( needle, `const { pokedexFixtureWorld } = await import('/tests/pokedex-fixture.ts'); const world = pokedexFixtureWorld(assets);`, ), }); }); await page.clock.install({ time: new Date("2026-09-22T12:00:00") }); await page.goto("/"); await page.locator("#rom-file").setInputFiles(romPath); await expect(page.locator("#status")).toContainText("verified"); await page.clock.pauseAt(new Date("2026-09-22T12:05:00")); await page.locator("#play").click(); } test("the start menu's POKéDEX lists, opens entries and returns", async ({ page }) => { const errors: string[] = []; page.on("pageerror", (error) => errors.push(error.message)); await start(page); const dex = page.locator("#pokedex-screen"); await page.keyboard.press("Enter"); await page.locator("#dialogue-choice").getByRole("option", { name: /^POKéDEX/ }).click(); await expect(dex).toBeVisible(); await expect(page.locator("#native-dialogue")).toBeHidden(); const rows = dex.locator(".pokedex-list li"); await expect(rows).toHaveCount(7); await expect(rows.first()).toHaveText(/CHIKORITA/); await expect(rows.first()).toHaveAttribute("aria-current", "true"); await expect(rows.nth(1)).toHaveText(/-----/); await expect(dex.locator(".pokedex-counts")).toContainText("SEEN"); await expect(dex.locator(".pokedex-pic")).toHaveAttribute("aria-label", "CHIKORITA"); // Down three rows to CYNDAQUIL, which is owned. for (let i = 0; i < 3; i++) await page.keyboard.press("ArrowDown"); await expect(rows.nth(3)).toHaveAttribute("aria-current", "true"); await expect(rows.nth(3).locator(".pokedex-ball")).toHaveAttribute("aria-label", "Owned"); await page.keyboard.press("KeyX"); await expect(dex).toHaveAttribute("data-screen", "entry"); await expect(dex.locator(".pokedex-entry-details")).toContainText("FIRE MOUSE"); await expect(dex.locator(".pokedex-entry-details")).toContainText(`HT 1'08"`); await expect(dex.locator(".pokedex-page")).toHaveText("P.1"); await page.keyboard.press("KeyX"); await expect(dex.locator(".pokedex-page")).toHaveText("P.2"); // Up steps back to the previous seen Pokémon, which is not caught. await page.keyboard.press("ArrowUp"); await expect(dex.locator(".pokedex-entry-details")).toContainText("CHIKORITA"); await expect(dex.locator(".pokedex-entry-details")).toContainText(`HT ?'??"`); await expect(dex.locator(".pokedex-text")).toHaveText(""); // B returns to the list, then to the start menu. await page.keyboard.press("KeyZ"); await expect(dex).toHaveAttribute("data-screen", "list"); await page.keyboard.press("KeyZ"); await expect(dex).toBeHidden(); await expect(page.locator("#dialogue-choice").getByRole("option", { name: /^POKéDEX/ })).toBeVisible(); expect(errors).toEqual([]); }); test("the Pokédex tab shows seen and owned records from the game", async ({ page }) => { await start(page); await page.locator("#tab-pokedex").click(); const panel = page.locator("#panel-pokedex"); await expect(panel.locator("h2")).toHaveText("SEEN 3 · OWN 1"); const list = panel.locator(".pokedex-tab-list li"); // PIDGEY is tenth in New mode. await expect(list).toHaveCount(10); await expect(list.nth(1)).toHaveText(/-----/); await panel.getByRole("button", { name: /CYNDAQUIL/ }).click(); await expect(panel.locator(".pokedex-tab-entry")).toContainText("FIRE MOUSE"); await expect(panel.locator(".pokedex-tab-entry .pokedex-text")).toHaveCount(2); await panel.getByRole("button", { name: /PIDGEY/ }).click(); await expect(panel.locator(".pokedex-tab-entry")).toContainText("TINY BIRD"); await expect(panel.locator(".pokedex-tab-entry")).toContainText("Catch this Pokémon"); await expect(panel.locator(".pokedex-tab-entry .pokedex-text")).toHaveCount(0); });