Settings sets the text size (100, 125 or 150 %) and the key of each button, kept in this browser's storage and validated on load. Every font size scales with --text-scale, and the dialogue box scrolls instead of growing past the screen. The game screen's label, the Play message and Help's control list name the current keys. Screen reader announcements for every native screen and touch control remapping remain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
3.9 KiB
TypeScript
86 lines
3.9 KiB
TypeScript
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("settings rebind a key, scale the text and survive a reload", async ({ page }) => {
|
|
await start(page);
|
|
const dialog = page.locator("#settings-dialog");
|
|
await page.locator("#settings").click();
|
|
await expect(dialog).toBeVisible();
|
|
const startRow = dialog.locator("#key-table tr", { hasText: "START" });
|
|
await expect(startRow).toContainText("Enter");
|
|
// Escape cancels a key change without closing the dialog.
|
|
await startRow.getByRole("button", { name: /Change the key for START/ }).click();
|
|
await expect(startRow).toContainText("Press a key");
|
|
await page.keyboard.press("Escape");
|
|
await expect(dialog).toBeVisible();
|
|
await expect(page.locator("#settings-status")).toHaveText("Key change cancelled.");
|
|
// Space is reserved; Q becomes START.
|
|
await startRow.getByRole("button", { name: /Change the key for START/ }).click();
|
|
await page.keyboard.press("Space");
|
|
await expect(page.locator("#settings-status")).toContainText("keeps its usual role");
|
|
await startRow.getByRole("button", { name: /Change the key for START/ }).click();
|
|
await page.keyboard.press("KeyQ");
|
|
await expect(startRow).toContainText("Q");
|
|
await expect(page.locator("#settings-status")).toHaveText("START is now Q.");
|
|
await dialog.getByLabel("Large", { exact: true }).check();
|
|
await expect(page.locator("html")).toHaveAttribute("style", /--text-scale: 1.25/);
|
|
await page.locator("#close-settings").click();
|
|
await expect(page.locator("#game-screen")).toHaveAttribute("aria-label", /Q is START/);
|
|
|
|
// Enter no longer opens the start menu; Q does.
|
|
await page.locator("#play").click();
|
|
await page.locator("#game-screen").focus();
|
|
await page.keyboard.press("Enter");
|
|
await page.clock.runFor(200);
|
|
await expect(page.locator("#dialogue-choice")).toBeHidden();
|
|
await page.keyboard.press("KeyQ");
|
|
await expect(page.locator("#dialogue-choice").getByRole("option", { name: /^POKéDEX/ })).toBeVisible();
|
|
|
|
// The choices stay after a reload.
|
|
await page.reload();
|
|
await expect(page.locator("html")).toHaveAttribute("style", /--text-scale: 1.25/);
|
|
await page.locator("#settings").click();
|
|
await expect(page.locator("#key-table tr", { hasText: "START" })).toContainText("Q");
|
|
await page.locator("#reset-keys").click();
|
|
await expect(page.locator("#key-table tr", { hasText: "START" })).toContainText("Enter");
|
|
});
|
|
|
|
test("help lists the current keys", async ({ page }) => {
|
|
await start(page);
|
|
await page.locator("#help").click();
|
|
const keys = page.locator("#help-keys");
|
|
await expect(keys).toContainText("Interact / Continue");
|
|
await expect(keys).toContainText("X (A)");
|
|
await expect(keys).toContainText("Enter (START)");
|
|
});
|