Files
hanzo.ai/e2e/gates/thumbrooms.spec.ts

70 lines
2.7 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { serveExport } from './export'
import { signIn } from '../session'
/**
* EVERY ROOM ON AN ACTUAL THUMB.
*
* `readable.spec` measures the same four widths with a FINE pointer, which is a
* different page: `@hanzo/design`'s base.css grows every control to a 44px floor under
* `pointer: coarse`, so a 390px desktop window reads rooms whose controls are
* still their small size. The widths that ship to a phone were never measured.
*
* The difference is not theoretical. It has mattered twice — the organization
* switcher sat at 28px until a coarse run showed it, and the composer's row only
* reaches the floor here — and a taller control is exactly what pushes a row
* past the edge.
*
* The pointer is a property of the CONTEXT, which Playwright fixes per file, so
* this is a file rather than a fifth size in the other one.
*/
test.use({ viewport: { width: 390, height: 844 }, hasTouch: true, isMobile: true })
const ROOMS = ['/chat', '/home', '/board', '/drive', '/inbox', '/work']
for (const room of ROOMS) {
test(`${room} is readable on a thumb`, async ({ page }) => {
test.setTimeout(60_000)
await signIn(page)
const site = await serveExport()
try {
await page.goto(`${site.url}${room}`)
await expect(page.locator('main')).toBeVisible({ timeout: 20_000 })
const found = await page.evaluate((width) => {
const scrolls = (el: Element | null): boolean => {
for (let n = el; n; n = n.parentElement) {
const o = getComputedStyle(n).overflowX
if (o === 'auto' || o === 'scroll') return true
}
return false
}
// Content, not any box — a glow drawn to bleed off a card corner is not
// something a reader cannot reach. See readable.spec.
const speaks = (el: Element): boolean =>
(el.textContent || '').trim().length > 0 ||
el.matches('button,[role=button],a[href],select,input,textarea') ||
el.querySelector('button,[role=button],a[href],select,input,textarea') !== null
const past: string[] = []
for (const el of Array.from(document.querySelectorAll('body *'))) {
const b = el.getBoundingClientRect()
if (
b.width > 0 &&
b.height > 0 &&
b.right > width + 1 &&
!scrolls(el.parentElement) &&
speaks(el)
)
past.push(`${el.tagName}.${(el.className || '').toString().split(' ')[0]}`)
}
return past.slice(0, 3)
}, 390)
expect(found, `${room} puts something out of reach on a thumb`).toEqual([])
} finally {
await site.close()
}
})
}