import type { Locator, Page } from 'playwright-core'; import { expect } from 'vitest'; /** * Assert that an element meets the minimum touch target size (44x44px per WCAG). */ export async function assertMinTouchTarget(locator: Locator, minSize = 44) { const box = await locator.boundingBox(); expect(box, 'Element must be visible and have a bounding box').toBeTruthy(); expect(box!.width).toBeGreaterThanOrEqual(minSize); expect(box!.height).toBeGreaterThanOrEqual(minSize); } /** * Assert the gap between two elements in a given direction. */ export async function assertGapBetween( locatorA: Locator, locatorB: Locator, options: { min?: number; max?: number; direction?: 'vertical' | 'horizontal' }, ) { const { min = 0, max = Infinity, direction = 'vertical' } = options; const boxA = await locatorA.boundingBox(); const boxB = await locatorB.boundingBox(); expect(boxA, 'Element A must be visible').toBeTruthy(); expect(boxB, 'Element B must be visible').toBeTruthy(); let gap: number; if (direction === 'vertical') { gap = boxB!.y - (boxA!.y + boxA!.height); } else { gap = boxB!.x - (boxA!.x + boxA!.width); } expect(gap).toBeGreaterThanOrEqual(min); expect(gap).toBeLessThanOrEqual(max); } /** * Assert that an element is fully within the viewport (not clipped). */ export async function assertWithinViewport(locator: Locator, page: Page) { const box = await locator.boundingBox(); expect(box, 'Element must be visible').toBeTruthy(); const viewport = page.viewportSize(); expect(viewport, 'Page must have a viewport').toBeTruthy(); expect(box!.x).toBeGreaterThanOrEqual(0); expect(box!.y).toBeGreaterThanOrEqual(0); expect(box!.x + box!.width).toBeLessThanOrEqual(viewport!.width); expect(box!.y + box!.height).toBeLessThanOrEqual(viewport!.height); }