Port the Pokédex list, entries and tab (#35)
Checks / web (push) Failing after 21s
Private ROM checks / private-rom (push) Failing after 14m27s

The start menu's POKéDEX runs Pokedex in New mode: the list up to the
last seen Pokémon, its cursor and page moves, and DisplayDexEntry with
the category, number, footprint, and the height, weight and pages once
caught. The Pokédex tab shows the same records from the loaded game.
Order, entries and footprints are compared with the pinned PRET source.

AREA, CRY, PRNT, the option and search screens, Old and A to Z modes
and Unown mode remain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
samyandClaude Opus 5.5 committed 2026-10-03 20:19:24 +02:00
1 parent 03aa913a94
commit cdee576818
20 files changed
+1624 -29

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
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);
});