floor-planner/e2e/usability.spec.ts
Andras Schmelczer 8bf3e3b705
Some checks failed
Deploy to Pages / build (push) Failing after 10m45s
Simplify
2026-09-11 23:27:29 +01:00

165 lines
8 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { defaultState } from '../src/lib/defaults';
import { decodeState, encodeState } from '../src/lib/url-state';
test.beforeEach(async ({ page }) => {
await page.goto('/?planner');
await expect(page.getByRole('heading', { name: 'Room measurements', exact: true })).toBeVisible();
});
test('new plans start random and guide custom measurements through to the cut plan', async ({
page,
}) => {
await expect(page.getByRole('button', { name: 'Random', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
await expect(page.locator('#custom-shape-help')).toContainText('Click Custom');
await page.getByRole('button', { name: 'Custom', exact: true }).click();
await expect(page.getByRole('button', { name: 'Custom', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
await expect(page.getByLabel('Wall 1 length', { exact: true })).toBeVisible();
await page.getByRole('button', { name: 'Add a wall', exact: true }).click();
await page.getByLabel('Wall 2 length', { exact: true }).fill('3000');
await page.getByLabel('Wall 2 length', { exact: true }).blur();
await page.getByRole('button', { name: 'Add a wall', exact: true }).click();
await page.getByLabel('Wall 3 length', { exact: true }).fill('4000');
await page.getByLabel('Wall 3 length', { exact: true }).blur();
await page.getByRole('button', { name: 'Add closing wall', exact: true }).click();
await expect(page.getByText('Outline closed', { exact: true })).toBeVisible();
await expect(page.getByLabel('Wall 4 length', { exact: true })).toBeVisible();
await expect(page.getByRole('button', { name: 'Custom', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
await page.getByRole('button', { name: 'Materials', exact: true }).click();
await expect(page.getByLabel('Board length', { exact: true })).toBeHidden();
await page.getByRole('button', { name: 'Materials', exact: true }).click();
await expect(page.getByRole('button', { name: 'Materials', exact: true })).toBeFocused();
await expect(page.getByLabel('Board length', { exact: true })).toBeVisible();
await expect(page.getByLabel('Saw kerf', { exact: true })).toBeHidden();
await page.getByText('Advanced flooring settings', { exact: true }).click();
await page.getByLabel('Saw kerf', { exact: true }).fill('4');
await page.getByLabel('Saw kerf', { exact: true }).blur();
expect(decodeState(new URL(page.url()).search).state.project.flooring.kerf).toBe(4);
await page.getByRole('button', { name: 'Cut plan', exact: true }).click();
await page.getByRole('button', { name: 'Cut plan', exact: true }).click();
await expect(page.getByRole('button', { name: 'Cut plan', exact: true })).toBeFocused();
await expect(page.getByLabel('Find a cut or room', { exact: true })).toBeVisible();
});
test('the top switch shows one material and preserves inputs and progress across reloads', async ({
page,
}) => {
const preview = page.getByRole('region', { name: 'Floor plan preview' });
const toggle = page.getByRole('group', { name: 'Plan view', exact: true });
await expect(toggle.getByRole('button', { name: 'Floorboards', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
expect(await preview.locator('.floor-piece').count()).toBeGreaterThan(0);
await expect(preview.locator('.skirt-piece')).toHaveCount(0);
await page.locator('.stock-cut-group input[type="checkbox"]').first().check();
const project = decodeState(new URL(page.url()).search).state.project;
await toggle.getByRole('button', { name: 'Skirting', exact: true }).click();
await expect(preview.locator('.floor-piece')).toHaveCount(0);
expect(await preview.locator('.skirt-piece').count()).toBeGreaterThan(0);
await expect(preview.getByText('Flooring cuts', { exact: true })).toHaveCount(0);
expect(decodeState(new URL(page.url()).search).state.project).toEqual(project);
await page.reload();
await expect(toggle.getByRole('button', { name: 'Skirting', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
await expect(preview.locator('.floor-piece')).toHaveCount(0);
await page.goto('/?planner');
await expect(toggle.getByRole('button', { name: 'Skirting', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
expect(decodeState(new URL(page.url()).search).state.project).toEqual(project);
await toggle.getByRole('button', { name: 'Floorboards', exact: true }).click();
expect(await preview.locator('.floor-piece').count()).toBeGreaterThan(0);
await expect(preview.locator('.skirt-piece')).toHaveCount(0);
});
test('saved brick plans keep their pattern and explicit links restore the selected material', async ({
page,
}) => {
const state = defaultState();
state.project.flooring.pattern = 'brick';
state.view.material = 'skirting';
await page.goto(`/${encodeState(state)}`);
await expect(page.getByRole('button', { name: 'Brick', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
await expect(
page
.getByRole('group', { name: 'Plan view' })
.getByRole('button', { name: 'Skirting', exact: true }),
).toHaveAttribute('aria-pressed', 'true');
await page.goto('/?planner');
await expect(page.getByRole('button', { name: 'Brick', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
});
test('locating cuts changes material automatically and printing includes both materials', async ({
page,
}) => {
const preview = page.getByRole('region', { name: 'Floor plan preview' });
const toggle = page.getByRole('group', { name: 'Plan view', exact: true });
await page.locator('.skirting-cuts .board-group-actions .board-locate').first().click();
await expect(toggle.getByRole('button', { name: 'Skirting', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
expect(await preview.locator('.skirt-piece[data-highlighted="true"]').count()).toBeGreaterThan(0);
await page.getByRole('button', { name: 'Show all pieces', exact: true }).click();
await page.getByLabel('Find a cut or room', { exact: true }).fill('F1');
await page.getByLabel('Find a cut or room', { exact: true }).blur();
await expect(toggle.getByRole('button', { name: 'Floorboards', exact: true })).toHaveAttribute(
'aria-pressed',
'true',
);
await expect(preview.locator('.floor-piece[data-piece-id="F1"]')).toHaveAttribute(
'data-highlighted',
'true',
);
await toggle.getByRole('button', { name: 'Skirting', exact: true }).click();
await expect(page.getByRole('button', { name: 'Show all pieces', exact: true })).toHaveCount(0);
await preview
.getByRole('button', { name: /^Select skirting cut / })
.first()
.click();
await expect(page.getByRole('dialog')).toBeVisible();
await page.keyboard.press('Escape');
await page.emulateMedia({ media: 'print' });
await expect(page.locator('.print-plan')).toBeVisible();
expect(await page.locator('.print-plan .floor-piece').count()).toBeGreaterThan(0);
expect(await page.locator('.print-plan .skirt-piece').count()).toBeGreaterThan(0);
});
test('setup and the pinned view switch fit a narrow phone', async ({ page }) => {
await page.setViewportSize({ width: 320, height: 844 });
await page.getByRole('button', { name: 'Materials', exact: true }).scrollIntoViewIfNeeded();
const heading = await page.getByRole('button', { name: 'Materials', exact: true }).boundingBox();
const drawing = await page.getByRole('complementary', { name: 'Room drawing' }).boundingBox();
expect(heading!.y).toBeGreaterThanOrEqual(drawing!.y + drawing!.height);
await page
.getByRole('group', { name: 'Plan view' })
.getByRole('button', { name: 'Skirting', exact: true })
.click();
await page.getByText('Advanced flooring settings', { exact: true }).click();
await page.getByText('Advanced skirting settings', { exact: true }).click();
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(320);
const toggle = await page.getByRole('group', { name: 'Plan view' }).boundingBox();
expect(toggle!.y).toBeGreaterThanOrEqual(0);
expect(toggle!.y + toggle!.height).toBeLessThan(844);
});