Add native Crystal exploration port and reference tooling
Checks / web (push) Canceled after 0s

This commit is contained in:
Sébastien QUEROL committed 2026-09-23 09:23:29 +02:00
1 parent 2127f5f459
commit 8b80d05ca2
56 files changed
+6910 -1

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
import { test, expect } 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("development server does not serve ROMs or the private reference checkout", async ({
request,
}) => {
for (const path of [
"/Pokemon%20-%20Crystal%20Version%20(UE)%20(V1.1)%20%5BC%5D%5B!%5D.gbc",
"/.reference/pokecrystal/README.md",
]) {
const response = await request.get(path);
expect([403, 404]).toContain(response.status());
}
});
test("native player loads the actual ROM without loading an emulator and persists movement", async ({
page,
context,
}, testInfo) => {
test.skip(
!existsSync(romPath),
"Requires a local user-supplied ROM; never downloaded or committed.",
);
const requests: string[] = [],
errors: string[] = [];
page.on("request", (request) => requests.push(request.url()));
page.on("pageerror", (error) => errors.push(error.message));
await page.goto("/");
await page.locator("#player-name").fill("KAWA");
await page.locator("#player-avatar").selectOption("kris");
await page.locator("#rom-file").setInputFiles(romPath);
await expect(page.locator("#status")).toContainText("verified");
await expect(page.locator("#game-screen")).toHaveAttribute(
"data-map",
"24:7",
);
await page.locator("#play").click();
await expect(page.locator("#game-screen")).toHaveAttribute("data-x", "3");
await page.keyboard.down("ArrowUp");
await expect(page.locator("#game-screen")).toHaveAttribute("data-y", "2");
await page.keyboard.up("ArrowUp");
await page.waitForTimeout(150);
await page.keyboard.press("KeyX");
await expect(page.locator("#native-dialogue")).toBeVisible();
await expect(page.locator("#dialogue-page")).toHaveText("1 / 4");
for (let i = 0; i < 4; i++) await page.locator("#dialogue-next").click();
await expect(page.locator("#native-dialogue")).toBeHidden();
await page.locator("#play").click();
await expect(page.locator("#save-status")).toContainText("Session saved");
const exported = page.waitForEvent("download");
await page.locator("#backup").click();
const backup = await exported;
page.once("dialog", (dialog) => dialog.accept());
await page.locator("#save-file").setInputFiles((await backup.path())!);
await expect(page.locator("#status")).toContainText("Backup restored");
await page.reload();
await page.locator("#rom-file").setInputFiles(romPath);
await expect(page.locator("#status")).toContainText("saved session");
await expect(page.locator("#game-screen")).toHaveAttribute("data-y", "2");
await page.locator("#play").click();
await page.keyboard.press("KeyX");
await expect(page.locator("#dialogue-page")).toHaveText("1 / 1");
await page.locator("#dialogue-next").click();
for (const [width, height] of [
[1440, 1000],
[1024, 900],
[390, 844],
[320, 740],
[844, 390],
]) {
await page.setViewportSize({ width, height });
await page.evaluate(() => scrollTo(0, 0));
expect(
await page.evaluate(
() => document.documentElement.scrollWidth <= innerWidth,
),
).toBe(true);
if (width <= 390 || height <= 390) {
const box = (await page.locator(".console").boundingBox())!;
expect(box.y + box.height).toBeLessThanOrEqual(height);
}
}
await page.setViewportSize({ width: 390, height: 844 });
await page.screenshot({
path: testInfo.outputPath("native-local-rom.png"),
fullPage: true,
});
const other = await context.newPage();
await other.goto("/");
await other.locator("#rom-file").setInputFiles(romPath);
await expect(other.locator("#status")).toContainText("another tab");
await other.close();
expect(
requests.some((url) => /binjgb|\.wasm|\/src\/emulator\//.test(url)),
).toBe(false);
expect(requests.every((url) => new URL(url).hostname === "127.0.0.1")).toBe(
true,
);
expect(errors).toEqual([]);
});