Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions e2e/atlas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ async function fixture(page: any, api: any) {
}
async function showList(page: any) { const button = page.getByRole("button", { name: "Repository list", exact: true }); if (await button.isVisible())
await button.click(); }
/** Inspect without entering: the explicit "Check cached facts" path. Card clicks enter directly. */
async function inspect(page: any, key: string) { await showList(page); const input = page.locator("#atlas-repository"); await input.fill(`https://github.com/${key}`); await input.press("Enter"); }
function row(page: any, key: string) { return page.locator(".atlas-list-rows").getByRole("button", { name: new RegExp(key) }); }
test("SYNTHETIC Atlas two-repository cached round trips preserve identity/source/styles/view/focus without stars or POST", async ({ page, api }) => {
const worlds = await fixture(page, api);
await page.goto(atlasPath);
await expect(row(page, keys[0])).toContainText("Cached status not checked");
expect(api.requests.filter((r: any) => r.path.includes("/api/world/"))).toEqual([]);
for (const [i, key] of keys.slice(0, 2).entries()) {
await row(page, key).click();
await inspect(page, key);
await expect(page).toHaveURL(/\/atlas/);
const card = page.locator(".atlas-card");
await expect(card.getByText("Discovered on this device · No Exploration star awarded.", { exact: true })).toBeVisible();
await expect(card.getByRole("link", { name: "GitHub source" })).toHaveAttribute("href", worlds[i].repo.url);
Expand All @@ -38,9 +41,10 @@ test("SYNTHETIC Atlas two-repository cached round trips preserve identity/source
await cv.focus();
await cv.press("=");
await cv.press("ArrowDown");
const before = await page.evaluate(() => JSON.parse(sessionStorage.getItem("moonfactory.atlas.session.v1")!));
await card.getByRole("link", { name: "Enter cached world" }).click();
await row(page, key).click();
await expect(page).toHaveURL(new RegExp(`/world/${key}\\?`));
// The view saved at entry (after the list click located the landmark) is what Back restores.
const before = await page.evaluate(() => JSON.parse(sessionStorage.getItem("moonfactory.atlas.session.v1")!));
await expect(page.locator(".explorer-visit-status")).toContainText("Visited on this device");
await expect(page.locator(".explorer-visit-status")).toContainText("No Exploration star");
await page.locator(".district-list").getByRole("button", { name: /SYNTHETIC 源码/ }).click();
Expand Down Expand Up @@ -78,13 +82,16 @@ test("SYNTHETIC actual painted map label selects the same repository as its visi
await page.emulateMedia({ reducedMotion: "no-preference" });
await fixture(page, api);
await page.goto(atlasPath);
await row(page, keys[0]).click();
await inspect(page, keys[0]);
await expect(page.getByRole("link", { name: "Enter cached world" })).toBeVisible();
await page.getByRole("button", { name: "Close selected landmark" }).click();
const mapTab = page.getByRole("button", { name: "Map", exact: true }); if (await mapTab.isVisible()) await mapTab.click();
const cv = page.locator(".atlas-map > canvas");
await expect.poll(() => cv.evaluate((c: any, key: string) => c.__labels?.some((p: any) => p.text === key), keys[0])).toBe(true);
const label = await cv.evaluate((c: any, key: string) => c.__labels.find((p: any) => p.text === key), keys[0]), box = (await cv.boundingBox())!;
await page.mouse.click(box.x + label.x, box.y + label.y);
await expect(page).toHaveURL(new RegExp(`/world/${keys[0]}\\?`));
await page.getByRole("link", { name: "Back to Atlas", exact: true }).click();
await expect(row(page, keys[0])).toHaveAttribute("aria-pressed", "true");
await expect(page.locator(".atlas-card")).toContainText("a".repeat(40));
await page.waitForTimeout(150);
Expand All @@ -105,14 +112,13 @@ for (const width of [320, 390, 768])
await page.keyboard.press("ArrowDown");
await expect(row(page, keys[1])).toBeFocused();
await page.keyboard.press("Enter");
await expect(page.locator(".explorer-visit-status")).toContainText("Visited on this device");
await page.getByRole("link", { name: "Back to Atlas", exact: true }).click();
await expect(row(page, keys[1])).toBeFocused();
await expect(page.locator(".atlas-card")).toContainText("b".repeat(40));
await expect(page.locator(".atlas-card").getByRole("link", { name: "GitHub source" })).toHaveAttribute("href", "https://github.com/" + keys[1]);
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
expect(await page.locator(".atlas-card").evaluate(e => e.scrollWidth <= e.clientWidth + 1)).toBe(true);
await page.getByRole("link", { name: "Enter cached world" }).click();
await expect(page.locator(".explorer-visit-status")).toContainText("Visited on this device");
await page.getByRole("link", { name: "Back to Atlas", exact: true }).click();
await expect(row(page, keys[1])).toBeFocused();
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
});
test("SYNTHETIC hidden Atlas map stops drawing, resumes one state-correct frame and never polls", async ({ page, api }) => {
Expand Down Expand Up @@ -149,7 +155,7 @@ test("SYNTHETIC real two-touch pinch and cancellation never become repository en
await cv.press("0");
await showList(page);
await row(page, keys[0]).click();
await expect(page.getByRole("link", { name: "Enter cached world" })).toBeVisible();
await expect(page).toHaveURL(new RegExp(`/world/${keys[0]}\\?`));
expect(api.requests.every((r: any) => r.method === "GET")).toBe(true);
});

Expand All @@ -159,8 +165,7 @@ test("SYNTHETIC Atlas light/dark chrome computes readable contrast and mobile en
await page.goto(basePath + "/");
await expect(page.getByRole("link", { name: "Explore Atlas", exact: true }).filter({ visible: true })).toBeVisible();
await page.getByRole("link", { name: "Explore Atlas", exact: true }).filter({ visible: true }).click();
await showList(page);
await row(page, keys[0]).click();
await inspect(page, keys[0]);
await expect(page.getByRole("link", { name: "Enter cached world" })).toBeVisible();
const audit = await page.evaluate(() => {
const rgb = (value: string) => { const a = value.match(/[\d.]+/g)?.map(Number) ?? []; return [a[0] ?? 0, a[1] ?? 0, a[2] ?? 0, a[3] ?? 1]; };
Expand Down
12 changes: 9 additions & 3 deletions e2e/gallery-preview.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ import type { StyleId } from "../src/contracts";

const previewApi = "/api/gallery-preview/synthetic-moonshot/browser-fixture";
test.beforeEach(async ({ page }) => { await page.setViewportSize({ width: 1440, height: 600 }); });
test("SYNTHETIC unknown gallery worlds cannot navigate to an empty route", async ({ page, api }) => {
test("SYNTHETIC unknown gallery worlds hand the repository to the explicit generate form without navigating", async ({ page, api }) => {
api.respond("GET", "/api/gallery", () => ({ body: { projects: syntheticGallery.map((p) => ({ ...p, ready: false, collectedAt: null })) } }));
await page.goto(`${basePath}/`);
const card = page.locator(".project-card").filter({ has: page.getByRole("heading", { name: "SYNTHETIC Atlas", exact: true }) });
await expect(card).toHaveAttribute("aria-disabled", "true");
await expect(card).toHaveAttribute("data-ready", "false");
expect(await card.getAttribute("href")).toBeNull();
await expect(card).toContainText("Map unavailable");
await expect(card).toContainText("Build this world");
const before = page.url();
await card.click();
expect(page.url()).toBe(before);
const fullName = syntheticGallery.find((p) => p.name === "SYNTHETIC Atlas")!.fullName;
await expect(page.locator("#repository")).toHaveValue(`https://github.com/${fullName}`);
await expect(page.locator("#repository")).toBeFocused();
await page.locator(".site-footer").scrollIntoViewIfNeeded();
await expect(page.getByText("Powered by Meta Muse Spark 1.3", { exact: true })).toBeVisible();
expect(api.requests.filter((r) => r.method === "POST")).toEqual([]);
Expand Down
8 changes: 4 additions & 4 deletions e2e/progression.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ async function harness(page:any){const result=await Bun.build({entrypoints:["./e
test("SYNTHETIC two-repo source challenge loop: wrong answer, Saved receipt, Atlas lamp/back/focus, reload and repeat retain one slot",async({page,api})=>{
await fixtures(api);await page.goto(basePath+"/atlas");
for(const key of [keyA,keyB]){
const row=page.locator(".atlas-list-rows").getByRole("button",{name:new RegExp(key)});await row.click();await expect(page.locator(".atlas-card")).toContainText("Discovered on this device");await expect(page.locator(".atlas-lantern")).toHaveCount(key===keyA?0:0);
await page.getByRole("link",{name:"Enter cached world",exact:true}).click();await expect(page.locator(".explorer-visit-status")).toContainText("No Exploration star awarded for entry");
const row=page.locator(".atlas-list-rows").getByRole("button",{name:new RegExp(key)});await row.click();await expect(page).toHaveURL(new RegExp(`/world/${key}\\?`));
await expect(page.locator(".explorer-visit-status")).toContainText("No Exploration star awarded for entry");
await answer(page,true);await expect(challenge(page).getByRole("status")).toContainText("Try again");expect((await receipts(page)).filter((r:any)=>r.completedIdentity.repoKey===key)).toHaveLength(0);
for (const name of ["Moon Factory","Factorio","Red Alert","Red Alert 2","Civilization"]) { await page.getByRole("group",{name:"World perspective"}).getByRole("button",{name:new RegExp(name+"$")}).click();await expect(challenge(page).getByRole("radio",{name:"This proves the service is healthy in production.",exact:true})).toBeChecked(); }
await challenge(page).getByRole("radio",{name:"The map records this directory source; its role is inferred and runtime behavior is unknown.",exact:true}).check();await challenge(page).getByRole("button",{name:"Submit source answers"}).click();await expect(challenge(page).getByRole("status")).toHaveText("Exploration star earned. Saved on this device.");
Expand Down Expand Up @@ -99,14 +99,14 @@ test("F4 SYNTHETIC confirmed clear removes corrupt v1 rows atomically but reject

test("F6 SYNTHETIC unsaved receipt stays session-only after Back/read, recovery saves original once and reload drops only unsaved",async({page,api})=>{
await fixtures(api);await page.addInitScript(()=>{const original=IDBObjectStore.prototype.add;let fail=true;IDBObjectStore.prototype.add=function(...args:any[]){if(this.name==="completions"&&fail){fail=false;throw new DOMException("SYNTHETIC save failure","QuotaExceededError");}return original.apply(this,args as any);};});
await page.goto(basePath+"/atlas");await page.locator(".atlas-list-rows").getByRole("button",{name:new RegExp(keyA)}).click();await page.getByRole("link",{name:"Enter cached world"}).click();await answer(page);await expect(challenge(page).getByRole("status")).toContainText("Session progress — not saved");expect(await receipts(page)).toHaveLength(0);
await page.goto(basePath+"/atlas");await page.locator(".atlas-list-rows").getByRole("button",{name:new RegExp(keyA)}).click();await answer(page);await expect(challenge(page).getByRole("status")).toContainText("Session progress — not saved");expect(await receipts(page)).toHaveLength(0);
await page.getByRole("link",{name:"Back to Atlas",exact:true}).click();await expect(page.locator(".atlas-progress-controls")).toContainText("0 saved Exploration stars · 1 session Exploration stars — not saved");await page.getByRole("button",{name:"Reload local progress"}).click();await expect(page.locator(".atlas-progress-controls")).toContainText("0 saved Exploration stars · 1 session");
await page.getByRole("link",{name:"Enter cached world"}).click();await answer(page);await expect(challenge(page).getByRole("status")).toContainText("Saved on this device");const saved=await receipts(page);expect(saved).toHaveLength(1);await answer(page);expect(await receipts(page)).toEqual(saved);
await page.getByRole("link",{name:"Back to Atlas",exact:true}).click();await expect(page.locator(".atlas-progress-controls")).toContainText("1 saved Exploration stars · 0 session");await page.reload();await expect(page.locator(".atlas-progress-controls")).toContainText("1 saved Exploration stars · 0 session");
});

test("F6 SYNTHETIC unsaved discovery/visit are labelled session-only and disappear after reload",async({page,api})=>{
await fixtures(api);await page.addInitScript(()=>{const original=IDBObjectStore.prototype.put;IDBObjectStore.prototype.put=function(...args:any[]){if(this.name==="repoProgress")throw new DOMException("SYNTHETIC flag save failure","QuotaExceededError");return original.apply(this,args as any);};});await page.goto(basePath+"/atlas");await page.locator(".atlas-list-rows").getByRole("button",{name:new RegExp(keyA)}).click();await expect(page.locator(".atlas-observation")).toContainText("Discovered this session");await page.getByRole("link",{name:"Enter cached world"}).click();await expect(page.locator(".explorer-visit-status")).toContainText("Visited this session — not saved");await answer(page);await expect(challenge(page).getByRole("status")).toContainText("Session progress — not saved");await page.getByRole("link",{name:"Back to Atlas",exact:true}).click();await expect(page.locator(".atlas-progress-controls")).toContainText("0 saved Exploration stars · 1 session");await expect(page.locator(".atlas-observation")).toContainText("Visited this session");await page.reload();await expect(page.locator(".atlas-progress-controls")).toContainText("Saved Exploration star count unknown · 0 session");expect(await receipts(page)).toHaveLength(0);
await fixtures(api);await page.addInitScript(()=>{const original=IDBObjectStore.prototype.put;IDBObjectStore.prototype.put=function(...args:any[]){if(this.name==="repoProgress")throw new DOMException("SYNTHETIC flag save failure","QuotaExceededError");return original.apply(this,args as any);};});await page.goto(basePath+"/atlas");await page.locator(".atlas-list-rows").getByRole("button",{name:new RegExp(keyA)}).click();await expect(page.locator(".explorer-visit-status")).toContainText("Visited this session — not saved");await answer(page);await expect(challenge(page).getByRole("status")).toContainText("Session progress — not saved");await page.getByRole("link",{name:"Back to Atlas",exact:true}).click();await expect(page.locator(".atlas-progress-controls")).toContainText("0 saved Exploration stars · 1 session");await expect(page.locator(".atlas-observation")).toContainText("Visited this session");await page.reload();await expect(page.locator(".atlas-progress-controls")).toContainText("Saved Exploration star count unknown · 0 session");expect(await receipts(page)).toHaveLength(0);
});

test("F5 SYNTHETIC malformed cached graph is unavailable in Atlas and Explorer without an error boundary",async({page,api})=>{
Expand Down
Loading
Loading