feat: Implement Story 1.6 - Move Shared Defs Resources to the Dedicated Host

- Added documentation for Story 1.6 outlining the requirements and acceptance criteria for migrating shared defs-backed resources to a dedicated host.
- Updated sprint status to reflect the readiness of Story 1.6 for development.
- Created epics document detailing the breakdown of the Fantasy-Map-Generator project, including functional and non-functional requirements.
- Added implementation readiness report assessing the current state of documentation and readiness for the project.
- Introduced end-to-end tests for scene bootstrap to ensure runtime hosts are created and reused correctly.
This commit is contained in:
Azgaar 2026-03-13 00:22:23 +01:00
parent df18f69516
commit 125403b82f
10 changed files with 1522 additions and 0 deletions

View file

@ -0,0 +1,100 @@
import path from "path";
import { expect, test } from "@playwright/test";
async function collectCriticalErrors(page: import("@playwright/test").Page, action: () => Promise<void>) {
const errors: string[] = [];
page.on("pageerror", error => errors.push(`pageerror: ${error.message}`));
page.on("console", message => {
if (message.type() === "error") {
errors.push(`console.error: ${message.text()}`);
}
});
await action();
return errors.filter(
error =>
!error.includes("fonts.googleapis.com") &&
!error.includes("google-analytics") &&
!error.includes("googletagmanager") &&
!error.includes("Failed to load resource"),
);
}
test.describe("scene bootstrap", () => {
test.beforeEach(async ({ context, page }) => {
await context.clearCookies();
await page.goto("/");
await page.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
});
});
test("creates runtime hosts on fresh load", async ({ page }) => {
const criticalErrors = await collectCriticalErrors(page, async () => {
await page.goto("/?seed=test-scene-bootstrap&width=1280&height=720");
await page.waitForFunction(() => (window as any).mapId !== undefined, {timeout: 60000});
});
const runtimeHosts = await page.evaluate(() => {
const mapContainer = document.getElementById("map-container");
const sceneContainer = document.getElementById("map-scene");
const defsHost = document.getElementById("runtime-defs-host");
const map = document.getElementById("map");
const canvas = document.getElementById("webgl-canvas");
return {
hasMapContainer: !!mapContainer,
hasSceneContainer: !!sceneContainer,
hasDefsHost: !!defsHost,
mapInsideScene: !!sceneContainer?.contains(map),
canvasInsideScene: !!sceneContainer?.contains(canvas),
defsOutsideScene: !!defsHost && !!sceneContainer && !sceneContainer.contains(defsHost),
};
});
expect(runtimeHosts.hasMapContainer).toBe(true);
expect(runtimeHosts.hasSceneContainer).toBe(true);
expect(runtimeHosts.hasDefsHost).toBe(true);
expect(runtimeHosts.mapInsideScene).toBe(true);
expect(runtimeHosts.canvasInsideScene).toBe(true);
expect(runtimeHosts.defsOutsideScene).toBe(true);
expect(criticalErrors).toEqual([]);
});
test("reuses runtime hosts after loading a saved map", async ({ page }) => {
const criticalErrors = await collectCriticalErrors(page, async () => {
await page.goto("/");
await page.waitForSelector("#mapToLoad", {state: "attached"});
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
await page.locator("#mapToLoad").setInputFiles(mapFilePath);
await page.waitForFunction(() => (window as any).mapId !== undefined, {timeout: 120000});
});
const runtimeHosts = await page.evaluate(() => {
const sceneContainer = document.getElementById("map-scene");
const defsHost = document.getElementById("runtime-defs-host");
const map = document.getElementById("map");
const viewbox = document.getElementById("viewbox");
const deftemp = document.getElementById("deftemp");
const canvas = document.getElementById("webgl-canvas");
return {
hasSceneContainer: !!sceneContainer,
hasDefsHost: !!defsHost,
mapInsideScene: !!sceneContainer?.contains(map),
canvasInsideScene: !!sceneContainer?.contains(canvas),
rebuiltMapSelections: !!viewbox && !!deftemp,
};
});
expect(runtimeHosts.hasSceneContainer).toBe(true);
expect(runtimeHosts.hasDefsHost).toBe(true);
expect(runtimeHosts.mapInsideScene).toBe(true);
expect(runtimeHosts.canvasInsideScene).toBe(true);
expect(runtimeHosts.rebuiltMapSelections).toBe(true);
expect(criticalErrors).toEqual([]);
});
});