227 lines
8.3 KiB
TypeScript
227 lines
8.3 KiB
TypeScript
import { expect, test } from "../helpers/serve-dist";
|
|
|
|
test("keeps the decorative world separate from the semantic reading path", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
|
|
await expect(page.locator("#journey-scene-description")).toContainText(
|
|
"night",
|
|
);
|
|
await expect(page.locator(".journey-world")).toHaveAttribute(
|
|
"aria-hidden",
|
|
"true",
|
|
);
|
|
await expect(page.locator(".journey-poster")).toHaveAttribute("alt", "");
|
|
await expect(page.locator(".journey-poster")).toHaveAttribute(
|
|
"width",
|
|
"1600",
|
|
);
|
|
await expect(page.locator("main#portfolio-content")).toBeVisible();
|
|
});
|
|
|
|
test("keeps the hero and navigation in paint layers above the world", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.setViewportSize({ width: 1440, height: 900 });
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
|
|
const layers = await page.evaluate(() => {
|
|
const world = document.querySelector<HTMLElement>(".journey-world");
|
|
const shell = document.querySelector<HTMLElement>(".portfolio-shell");
|
|
const hero = document.querySelector<HTMLElement>(".hero-journey__content");
|
|
const heading = document.querySelector<HTMLElement>(".hero-journey h1");
|
|
const navigation = document.querySelector<HTMLElement>(".site-navigation");
|
|
if (!world || !shell || !hero || !heading || !navigation)
|
|
throw new Error("Missing top-screen structure");
|
|
const worldStyle = getComputedStyle(world);
|
|
const heroStyle = getComputedStyle(hero);
|
|
const navigationStyle = getComputedStyle(navigation);
|
|
return {
|
|
worldZ: Number(worldStyle.zIndex),
|
|
shellZ: Number(getComputedStyle(shell).zIndex),
|
|
navigationZ: Number(navigationStyle.zIndex),
|
|
navigationPosition: navigationStyle.position,
|
|
headingVisible:
|
|
heading.getBoundingClientRect().width > 0 &&
|
|
heading.getBoundingClientRect().height > 0,
|
|
navigationVisible:
|
|
navigation.getBoundingClientRect().width > 0 &&
|
|
navigation.getBoundingClientRect().height > 0,
|
|
heroOpacity: Number.parseFloat(
|
|
heroStyle.backgroundColor.match(/[\d.]+(?=\))/gu)?.at(-1) ?? "1",
|
|
),
|
|
};
|
|
});
|
|
|
|
expect(layers).toMatchObject({
|
|
navigationPosition: "fixed",
|
|
headingVisible: true,
|
|
navigationVisible: true,
|
|
});
|
|
expect(layers.shellZ).toBeGreaterThan(layers.worldZ);
|
|
expect(layers.navigationZ).toBeGreaterThan(layers.worldZ);
|
|
expect(layers.heroOpacity).toBeGreaterThanOrEqual(0.94);
|
|
});
|
|
|
|
test("resets the navigation disclosure when crossing the compact breakpoint", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.setViewportSize({ width: 1440, height: 900 });
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
|
|
const disclosure = page.locator(".site-navigation details");
|
|
const summary = page.locator(".site-navigation summary");
|
|
const startLink = page.locator('.site-navigation a[href="#start"]');
|
|
await expect(disclosure).toHaveAttribute("open", "");
|
|
await expect(startLink).toBeVisible();
|
|
|
|
await page.setViewportSize({ width: 630, height: 900 });
|
|
await expect(summary).toBeVisible();
|
|
await expect(disclosure).not.toHaveAttribute("open", "");
|
|
await expect(startLink).toBeHidden();
|
|
|
|
await summary.click();
|
|
await expect(disclosure).toHaveAttribute("open", "");
|
|
await page.setViewportSize({ width: 1440, height: 900 });
|
|
await expect(summary).toBeHidden();
|
|
await expect(disclosure).toHaveAttribute("open", "");
|
|
await expect(startLink).toBeVisible();
|
|
});
|
|
|
|
test("keeps a scrolled content panel in a geometry-safe paint layer above the world", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.setViewportSize({ width: 1440, height: 900 });
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
const profileLink = page.locator('nav a[href="#profile"]');
|
|
if (!(await profileLink.isVisible()))
|
|
await page.locator(".site-navigation summary").click();
|
|
await profileLink.click();
|
|
await expect(page).toHaveURL(`${distUrl}/#profile`);
|
|
await expect(page.locator("#profile-heading")).toBeInViewport();
|
|
|
|
const layers = await page.evaluate(() => {
|
|
const world = document.querySelector<HTMLElement>(".journey-world");
|
|
const main = document.querySelector<HTMLElement>(".portfolio-main");
|
|
const panel = document.querySelector<HTMLElement>("#profile");
|
|
const heading = document.querySelector<HTMLElement>("#profile-heading");
|
|
if (!world || !main || !panel || !heading)
|
|
throw new Error("Missing scrolled panel structure");
|
|
const mainStyle = getComputedStyle(main);
|
|
const panelStyle = getComputedStyle(panel);
|
|
const headingRect = heading.getBoundingClientRect();
|
|
return {
|
|
worldZ: Number(getComputedStyle(world).zIndex),
|
|
mainIsolation: mainStyle.isolation,
|
|
mainPosition: mainStyle.position,
|
|
headingVisible:
|
|
headingRect.width > 0 &&
|
|
headingRect.height > 0 &&
|
|
headingRect.bottom > 0 &&
|
|
headingRect.top < window.innerHeight,
|
|
panelOpacity: Number.parseFloat(
|
|
panelStyle.backgroundColor.match(/[\d.]+(?=\))/gu)?.at(-1) ?? "1",
|
|
),
|
|
};
|
|
});
|
|
|
|
expect(layers).toMatchObject({
|
|
worldZ: 0,
|
|
mainIsolation: "isolate",
|
|
mainPosition: "static",
|
|
headingVisible: true,
|
|
});
|
|
expect(layers.panelOpacity).toBeGreaterThanOrEqual(0.94);
|
|
});
|
|
|
|
test("provides native motion and quality controls with visible state", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
|
|
await page.getByRole("button", { name: "Drive settings" }).click();
|
|
const quality = page.getByLabel("Quality control");
|
|
await expect(quality).toBeVisible();
|
|
await expect(page.getByRole("status")).toHaveCount(0);
|
|
await page.keyboard.press("Escape");
|
|
await page.getByRole("button", { name: "Play soundtrack" }).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Pause motion" }),
|
|
).toBeVisible();
|
|
const canvas = page.locator(".journey-canvas");
|
|
const originalCanvas = await canvas.elementHandle();
|
|
const originalGeneration = await page
|
|
.locator(".journey-world")
|
|
.getAttribute("data-scene-generation");
|
|
|
|
await page.getByRole("button", { name: "Pause motion" }).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Resume motion" }),
|
|
).toBeVisible();
|
|
await expect(canvas).toHaveCount(1);
|
|
await expect(page.locator(".journey-world")).toHaveAttribute(
|
|
"data-scene-generation",
|
|
originalGeneration ?? "",
|
|
);
|
|
expect(await originalCanvas?.evaluate((element) => element.isConnected)).toBe(
|
|
true,
|
|
);
|
|
|
|
await page.getByRole("button", { name: "Resume motion" }).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Pause motion" }),
|
|
).toBeVisible();
|
|
await expect(canvas).toHaveCount(1);
|
|
await expect(page.locator(".journey-world")).toHaveAttribute(
|
|
"data-scene-generation",
|
|
originalGeneration ?? "",
|
|
);
|
|
expect(await originalCanvas?.evaluate((element) => element.isConnected)).toBe(
|
|
true,
|
|
);
|
|
|
|
await page.getByRole("button", { name: "Drive settings" }).click();
|
|
await page.getByLabel("Quality control").selectOption("static");
|
|
await expect(
|
|
page.getByRole("button", { name: "Enable motion" }),
|
|
).toBeVisible();
|
|
await expect(page.locator(".journey-canvas")).toHaveCount(0);
|
|
await expect(page.getByRole("status")).toContainText("Motion: static");
|
|
});
|
|
|
|
test("never creates a canvas when the system requests reduced motion", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.emulateMedia({ reducedMotion: "reduce" });
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
|
|
await expect(page.locator(".journey-canvas")).toHaveCount(0);
|
|
await page.getByRole("button", { name: "Drive settings" }).click();
|
|
await expect(page.getByRole("status")).toContainText(
|
|
"reduced motion requested",
|
|
);
|
|
await expect(page.getByLabel("Quality control")).toBeVisible();
|
|
});
|
|
|
|
test("shows ARRIVED from the authoritative section snapshot at Contact", async ({
|
|
page,
|
|
distUrl,
|
|
}) => {
|
|
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
|
|
const contactLink = page.locator('nav a[href="#contact"]');
|
|
if (!(await contactLink.isVisible()))
|
|
await page.locator(".site-navigation summary").click();
|
|
await contactLink.click();
|
|
|
|
await expect(page.locator(".journey-hud")).toContainText("Contact");
|
|
await expect(page.locator(".journey-hud")).toContainText("ARRIVED");
|
|
await expect(page.locator(".journey-hud")).toContainText("100%");
|
|
});
|