Files
Portfolio/tests/browser/scene-controls.spec.ts

141 lines
7.0 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('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: 'Start the drive' }).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%');
});