Files
star-map/e2e/plan-view.spec.ts
T
SenrokaiandClaude Fable 5 8ceea02875 Wait for the boot as long as the boot takes
The specs added over this series each opened with an untimed check that the
canvas was there, which gives it Playwright's default five seconds. That is
the one wait in this suite that cannot be made faster: eight workers share a
software rasterizer, and what they are all waiting on is the same first paint.
Under a full parallel run five seconds is a coin toss, and it came up wrong on
the route-plotting spec.

Thirty, like every other wait in here that crosses a camera flight.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-08-21 15:20:00 +02:00

67 lines
3.2 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { openSearch } from './support/open-search';
test.describe('Plan view', () => {
test('flattens a system onto its own orbital plane, and unflattens it', async ({ page }) => {
test.setTimeout(120_000);
await page.goto('/?stars=4000');
const searchInput = await openSearch(page);
await searchInput.fill('Sol');
await page.getByRole('button', { name: /^Sol\b/ }).first().click();
await expect(page.getByTestId('hud-title')).toHaveText('Sol', { timeout: 45_000 });
// Where the planets are on screen before and after: under a plan view they lie on one
// circle around the star, so the spread of their distances from it collapses.
const spread = async () =>
page.evaluate(() => {
const labels = [...document.querySelectorAll('.map-label:not(.map-label--ghost)')];
const centre = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
const radii = labels.map((label) => {
const box = label.getBoundingClientRect();
return Math.hypot(box.left - centre.x, box.top + box.height / 2 - centre.y);
});
return radii.length;
});
await expect.poll(spread, { timeout: 30_000 }).toBeGreaterThan(2);
await page.getByRole('tab', { name: 'Display' }).click();
const plan = page.getByRole('button', { name: 'Plan view', exact: true });
await expect(plan).toHaveAttribute('aria-pressed', 'false');
await plan.click();
await expect(plan).toHaveAttribute('aria-pressed', 'true');
// The scene survives the swap: it is still this system, still labelled, still readable.
// Generously timed on purpose: this suite shares one software rasterizer, and the boot
// it waits on is the slowest thing in it. The default five seconds is a coin toss
// under a full parallel run.
await expect(page.getByTestId('scene-canvas')).toBeVisible({ timeout: 30_000 });
await expect.poll(spread, { timeout: 30_000 }).toBeGreaterThan(2);
await page.getByRole('tab', { name: 'Readout' }).click();
await expect(page.getByTestId('hud-title')).toHaveText('Sol');
await page.getByRole('tab', { name: 'Display' }).click();
await plan.click();
await expect(plan).toHaveAttribute('aria-pressed', 'false');
await expect.poll(spread, { timeout: 30_000 }).toBeGreaterThan(2);
});
test('keeps the scale ladder honest about how far out the view is', async ({ page }) => {
test.setTimeout(90_000);
await page.goto('/?stars=4000');
await expect(page.getByTestId('scene-canvas')).toBeVisible({ timeout: 30_000 });
await expect(page.getByTestId('hud-current-level')).toHaveText('Solar Neighbourhood', { timeout: 30_000 });
await page.getByRole('tab', { name: 'Display' }).click();
await page.getByRole('button', { name: 'Plan view', exact: true }).click();
// Under an orthographic camera the distance from the origin no longer sets what is in
// frame, so the level would be read from a number that stopped meaning anything.
await expect(page.getByTestId('hud-current-level')).toHaveText('Solar Neighbourhood');
await page.getByRole('button', { name: 'Milky Way' }).click();
await expect(page.getByTestId('hud-current-level')).toHaveText('Milky Way', { timeout: 45_000 });
});
});