mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
111 lines
4.4 KiB
TypeScript
111 lines
4.4 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { serveExport } from './export'
|
|
import { signIn } from '../session'
|
|
|
|
/**
|
|
* EVERY ROOM, AT EVERY WIDTH.
|
|
*
|
|
* `workspace.spec` measures two rooms on a phone, so five of the seven were
|
|
* never read at any size — and a room is exactly where this fails: the sidebar
|
|
* covering the pane was found at 1440 and again at 834, each time after the
|
|
* previous fix was written against the width it was found at.
|
|
*
|
|
* TWO THINGS, and they are the two ways a room stops being readable:
|
|
*
|
|
* unreachable something sits past the right edge with nothing that scrolls
|
|
* between it and the window. base.css clips the body, so
|
|
* such content is not merely off screen — there is no gesture
|
|
* that brings it back.
|
|
*
|
|
* crowded out `main` has been squeezed under a fifth of the window by
|
|
* whatever shares the row with it.
|
|
*
|
|
* TWO KINDS OF BOX ARE NOT DEFECTS, and both were found by measuring rather
|
|
* than by reasoning:
|
|
*
|
|
* inside a scroller that is what a scroller is for, and the board's column
|
|
* strip is the case. Without reading the ancestors, the
|
|
* board reported three false failures.
|
|
*
|
|
* carrying nothing a glow anchored to a card corner sits at `right: -64px`
|
|
* by design and the body clips it. Nothing is out of
|
|
* reach, because there was nothing in it — /pricing
|
|
* reported two of these.
|
|
*
|
|
* So the subject is CONTENT past the edge: a box with words in it, or one a
|
|
* reader could press.
|
|
*/
|
|
|
|
const SIZES = [
|
|
{ name: 'phone', w: 390, h: 844 },
|
|
{ name: 'tablet', w: 834, h: 1112 },
|
|
{ name: 'laptop', w: 1440, h: 900 },
|
|
{ name: 'desktop', w: 1920, h: 1080 },
|
|
]
|
|
|
|
/**
|
|
* A PHONE IS ALSO A THUMB, and that is a different measurement.
|
|
*
|
|
* `@hanzo/design`'s base.css grows every control to a 44px floor under `pointer: coarse`, so
|
|
* a room measured in a 390px DESKTOP window is a room whose controls are still
|
|
* their small size — the widths that ship to an actual phone were never read.
|
|
* Twice now the difference has mattered: the organization switcher was 28px
|
|
* until a coarse run showed it, and the composer's controls only reach 44 here.
|
|
*
|
|
* A separate file rather than a fifth entry above, because the pointer is a
|
|
* property of the CONTEXT and Playwright fixes that per file.
|
|
*/
|
|
|
|
const ROOMS = ['/chat', '/home', '/board', '/drive', '/inbox', '/work']
|
|
|
|
for (const room of ROOMS) {
|
|
test(`${room} is readable at every width`, async ({ page }) => {
|
|
test.setTimeout(90_000)
|
|
await signIn(page)
|
|
const site = await serveExport()
|
|
try {
|
|
for (const s of SIZES) {
|
|
await page.setViewportSize({ width: s.w, height: s.h })
|
|
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
|
|
}
|
|
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]}`)
|
|
}
|
|
const box = document.querySelector('main')?.getBoundingClientRect()
|
|
return { past: past.slice(0, 3), main: box ? Math.round(box.width) : -1 }
|
|
}, s.w)
|
|
|
|
expect(found.past, `${room} puts something out of reach at ${s.name}`).toEqual([])
|
|
expect(found.main, `${room} leaves its pane no room at ${s.name}`).toBeGreaterThan(
|
|
s.w * 0.2,
|
|
)
|
|
}
|
|
} finally {
|
|
await site.close()
|
|
}
|
|
})
|
|
}
|