127 lines
6.1 KiB
TypeScript
127 lines
6.1 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 desktop identity and navigation in a paint layer 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 header = document.querySelector<HTMLElement>('.site-header');
|
|
const heading = document.querySelector<HTMLElement>('.site-header h1');
|
|
const navigation = document.querySelector<HTMLElement>('.site-navigation');
|
|
if (!world || !header || !heading || !navigation) throw new Error('Missing top-screen structure');
|
|
const worldStyle = getComputedStyle(world);
|
|
const headerStyle = getComputedStyle(header);
|
|
return {
|
|
worldZ: Number(worldStyle.zIndex),
|
|
headerZ: Number(headerStyle.zIndex),
|
|
headerPosition: headerStyle.position,
|
|
headingVisible: heading.getBoundingClientRect().width > 0 && heading.getBoundingClientRect().height > 0,
|
|
navigationVisible: navigation.getBoundingClientRect().width > 0 && navigation.getBoundingClientRect().height > 0,
|
|
headerOpacity: Number.parseFloat(headerStyle.backgroundColor.match(/[\d.]+(?=\))/gu)?.at(-1) ?? '1'),
|
|
};
|
|
});
|
|
|
|
expect(layers).toMatchObject({
|
|
headerPosition: 'relative',
|
|
headingVisible: true,
|
|
navigationVisible: true,
|
|
});
|
|
expect(layers.headerZ).toBeGreaterThan(layers.worldZ);
|
|
expect(layers.headerOpacity).toBeGreaterThanOrEqual(0.94);
|
|
});
|
|
|
|
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' });
|
|
await page.locator('nav a[href="#profile"]').click();
|
|
|
|
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);
|
|
await expect(page).toHaveURL(`${distUrl}/#profile`);
|
|
});
|
|
|
|
test('provides native motion and quality controls with visible state', async ({ page, distUrl }) => {
|
|
await page.goto(distUrl, { waitUntil: 'domcontentloaded' });
|
|
|
|
const quality = page.getByLabel('Quality control');
|
|
await expect(quality).toBeVisible();
|
|
await expect(page.getByRole('button', { name: 'Pause motion' })).toBeVisible();
|
|
await expect(page.getByRole('status')).toContainText('Motion:');
|
|
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 quality.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 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' });
|
|
await page.locator('nav a[href="#contact"]').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%');
|
|
});
|