Phase 14: desktop e2e coverage (add blocking Desktop Chrome Playwright gate) #10
@@ -7,9 +7,10 @@
|
|||||||
* Rule 3: Critical elements visible and in-viewport on initial load
|
* Rule 3: Critical elements visible and in-viewport on initial load
|
||||||
* Rule 4: Accessible names on all interactive elements (role+name locators)
|
* Rule 4: Accessible names on all interactive elements (role+name locators)
|
||||||
*
|
*
|
||||||
* Runs on both device profiles automatically (playwright.config.ts matrix):
|
* Runs on all three device profiles automatically (playwright.config.ts matrix):
|
||||||
* iphone: iPhone 14 / WebKit / 390×844
|
* iphone: iPhone 14 / WebKit / 390×844
|
||||||
* pixel: Pixel 7 / Chromium / 412×915
|
* pixel: Pixel 7 / Chromium / 412×915
|
||||||
|
* desktop: Desktop Chrome / Chromium / 1280×720 (mobile-only geometry tests skipped)
|
||||||
*
|
*
|
||||||
* STRICT-MODE NOTE:
|
* STRICT-MODE NOTE:
|
||||||
* On mobile viewports (≤767px), AppNav renders PhoneNav as a <header> element
|
* On mobile viewports (≤767px), AppNav renders PhoneNav as a <header> element
|
||||||
@@ -59,7 +60,8 @@ test.describe('Rule 1/3/4 — BottomTabBar tap targets and in-viewport position'
|
|||||||
expect(box!.height, 'Lists tab height ≥ 44px').toBeGreaterThanOrEqual(44);
|
expect(box!.height, 'Lists tab height ≥ 44px').toBeGreaterThanOrEqual(44);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('BottomTabBar is fully in-viewport (Rule 3 — safe-area-inset)', async ({ page }) => {
|
test('BottomTabBar is fully in-viewport (Rule 3 — safe-area-inset)', async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.name === 'desktop', 'On desktop the Main navigation landmark resolves to the DesktopNav sidebar; the safe-area-inset bottom-edge assertion is semantically wrong for a sidebar (BottomTabBar returns null at ≥768px)');
|
||||||
// The bar uses env(safe-area-inset-bottom, 0px). In emulation there is no
|
// The bar uses env(safe-area-inset-bottom, 0px). In emulation there is no
|
||||||
// safe-area-inset, so the bar's bottom edge must be ≤ viewport height.
|
// safe-area-inset, so the bar's bottom edge must be ≤ viewport height.
|
||||||
const nav = page.getByRole('navigation', { name: 'Main navigation' });
|
const nav = page.getByRole('navigation', { name: 'Main navigation' });
|
||||||
@@ -88,7 +90,8 @@ test.describe('Rule 1/3/4 — BottomTabBar tap targets and in-viewport position'
|
|||||||
expect(box!.height, 'Settings button height ≥ 44px').toBeGreaterThanOrEqual(44);
|
expect(box!.height, 'Settings button height ≥ 44px').toBeGreaterThanOrEqual(44);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('New Event FAB meets 56×56px touch-target minimum (Rule 1)', async ({ page }) => {
|
test('New Event FAB meets 56×56px touch-target minimum (Rule 1)', async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.name === 'desktop', 'On desktop getByRole(button, New Event) resolves to the toolbar button (CalendarShell.tsx:436-457), not the 56×56 FAB; FAB geometry assertion does not apply to the toolbar button');
|
||||||
// Phone-only FAB — aria-label="New Event", fixed 56×56px (CalendarShell.tsx)
|
// Phone-only FAB — aria-label="New Event", fixed 56×56px (CalendarShell.tsx)
|
||||||
const fab = page.getByRole('button', { name: 'New Event' });
|
const fab = page.getByRole('button', { name: 'New Event' });
|
||||||
const box = await fab.boundingBox();
|
const box = await fab.boundingBox();
|
||||||
@@ -96,6 +99,17 @@ test.describe('Rule 1/3/4 — BottomTabBar tap targets and in-viewport position'
|
|||||||
expect(box!.width, 'New Event FAB width ≥ 56px').toBeGreaterThanOrEqual(56);
|
expect(box!.width, 'New Event FAB width ≥ 56px').toBeGreaterThanOrEqual(56);
|
||||||
expect(box!.height, 'New Event FAB height ≥ 56px').toBeGreaterThanOrEqual(56);
|
expect(box!.height, 'New Event FAB height ≥ 56px').toBeGreaterThanOrEqual(56);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// D-04 parity: desktop toolbar "New Event" button meets ≥44px minimum (Rule 1)
|
||||||
|
// CalendarShell.tsx:443 sets minHeight:'44px' on the desktop toolbar button.
|
||||||
|
// Guarded to run only on desktop — the FAB test above covers mobile profiles.
|
||||||
|
test('New Event toolbar button meets 44px touch-target minimum on desktop (Rule 1 — D-04 parity)', async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.name !== 'desktop', 'Desktop parity assertion — toolbar button only renders at ≥768px (Desktop Chrome); FAB test covers iphone/pixel');
|
||||||
|
const toolbarBtn = page.getByRole('button', { name: 'New Event' });
|
||||||
|
const box = await toolbarBtn.boundingBox();
|
||||||
|
expect(box, 'New Event toolbar button bounding box must not be null').not.toBeNull();
|
||||||
|
expect(box!.height, 'New Event toolbar button height ≥ 44px (Rule 1 desktop parity)').toBeGreaterThanOrEqual(44);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Rule 1/3/4 repeated on /lists ──
|
// ── Rule 1/3/4 repeated on /lists ──
|
||||||
@@ -127,7 +141,8 @@ test.describe('Rule 1/3/4 — BottomTabBar on /lists', () => {
|
|||||||
expect(box!.height).toBeGreaterThanOrEqual(44);
|
expect(box!.height).toBeGreaterThanOrEqual(44);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('BottomTabBar is fully in-viewport on /lists (Rule 3)', async ({ page }) => {
|
test('BottomTabBar is fully in-viewport on /lists (Rule 3)', async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.name === 'desktop', 'On desktop the Main navigation landmark resolves to the DesktopNav sidebar; the safe-area-inset bottom-edge assertion is semantically wrong for a sidebar (BottomTabBar returns null at ≥768px)');
|
||||||
const nav = page.getByRole('navigation', { name: 'Main navigation' });
|
const nav = page.getByRole('navigation', { name: 'Main navigation' });
|
||||||
await expect(nav).toBeVisible();
|
await expect(nav).toBeVisible();
|
||||||
const box = await nav.boundingBox();
|
const box = await nav.boundingBox();
|
||||||
|
|||||||
Reference in New Issue
Block a user