test(mobile): read PHONE_MAX as an exclusive bound everywhere, drop the stale 430px baselines

Follow-up to #390. PHONE_MAX had become 599, an inclusive bound, while
three of its four consumers still read it as exclusive (width < PHONE_MAX
for phone); the one site that switched to <= disagreed with
getDeviceType(). It is 600 again with < at every site. The breakpoint
table in docs/mobile-testing-report.md says 600, and the three 430px
visual baselines are removed: they depict the tablet tier now, and the
visual suite recreates a missing baseline on its next run on the machine
that owns them. device-matrix.test.ts is also run through Prettier, which
the commit hook demanded and the format gate (src/ only) never did.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-09-14 15:53:22 +02:00
parent dff7aeef3f
commit c9c8ffddde
6 changed files with 89 additions and 98 deletions
+2 -2
View File
@@ -156,8 +156,8 @@ There is no dedicated help button in the mobile UI. Help is accessible via:
| Breakpoint | Class | Description |
|------------|-------|-------------|
| < 430px | `device-mobile` | Phone - most features hidden/simplified |
| 430-768px | `device-tablet` | Tablet - intermediate layout |
| < 600px | `device-mobile` | Phone - most features hidden/simplified |
| 600-768px | `device-tablet` | Tablet - intermediate layout |
| > 768px | `device-desktop` | Desktop - full features |
Touch devices also get `touch-device` class regardless of screen size.
+12 -21
View File
@@ -15,12 +15,7 @@ import {
getCSSProperty,
getCSSNumericValue,
} from './helpers/assertions.js';
import {
REPRESENTATIVE_DEVICES,
DEVICE_REGISTRY,
type DeviceEntry,
type DeviceCategory,
} from './devices.js';
import { REPRESENTATIVE_DEVICES, DEVICE_REGISTRY, type DeviceEntry, type DeviceCategory } from './devices.js';
const PORT = PORTS.DEVICE_MATRIX;
const BASE_URL = `http://localhost:${PORT}`;
@@ -37,10 +32,7 @@ const PHONE_HIDDEN_SELECTORS = [
];
// Visible only on phones
const PHONE_ONLY_SELECTORS = [
SELECTORS.SETTINGS_MOBILE,
SELECTORS.CASE_MOBILE,
];
const PHONE_ONLY_SELECTORS = [SELECTORS.SETTINGS_MOBILE, SELECTORS.CASE_MOBILE];
describe('Device Matrix', () => {
beforeAll(async () => {
@@ -54,9 +46,9 @@ describe('Device Matrix', () => {
// ─── Representative Devices ───────────────────────────────────────────────
describe.each(
Object.entries(REPRESENTATIVE_DEVICES) as [DeviceCategory, DeviceEntry][],
)('Representative: %s', (category, device) => {
describe.each(Object.entries(REPRESENTATIVE_DEVICES) as [DeviceCategory, DeviceEntry][])(
'Representative: %s',
(category, device) => {
let context: BrowserContext;
let page: Page;
@@ -93,7 +85,7 @@ describe('Device Matrix', () => {
it('toolbar positioning matches breakpoint', async () => {
const { width } = device.viewport;
const position = await getCSSProperty(page, SELECTORS.TOOLBAR, 'position');
if (width <= BREAKPOINTS.PHONE_MAX) {
if (width < BREAKPOINTS.PHONE_MAX) {
// Phone (max-width: 599px): fixed toolbar
expect(position).toBe('fixed');
} else {
@@ -106,8 +98,8 @@ describe('Device Matrix', () => {
const { width } = device.viewport;
const isPhone = width < BREAKPOINTS.PHONE_MAX;
// Skip strict assertions for devices at the phone/tablet boundary (±10px)
const atBoundary = Math.abs(width - BREAKPOINTS.PHONE_MAX) <= 10
|| Math.abs(width - BREAKPOINTS.TABLET_MAX) <= 10;
const atBoundary =
Math.abs(width - BREAKPOINTS.PHONE_MAX) <= 10 || Math.abs(width - BREAKPOINTS.TABLET_MAX) <= 10;
if (atBoundary) return;
@@ -133,19 +125,18 @@ describe('Device Matrix', () => {
if (violations.length > 0) {
console.warn(
`[${device.name}] Touch target violations (${violations.length}):\n` +
violations.map(v => ` ${v.selector}: ${v.width}x${v.height}px`).join('\n'),
violations.map((v) => ` ${v.selector}: ${v.width}x${v.height}px`).join('\n')
);
}
// Larger viewports show more UI elements, so allow more violations.
// Known violators: notification action buttons (26x26), some icon buttons.
const { width } = device.viewport;
// Larger viewports show more elements; scale threshold accordingly
const maxViolations = width >= BREAKPOINTS.TABLET_MAX ? 25
: width >= BREAKPOINTS.PHONE_MAX ? 20
: 15;
const maxViolations = width >= BREAKPOINTS.TABLET_MAX ? 25 : width >= BREAKPOINTS.PHONE_MAX ? 20 : 15;
expect(violations.length).toBeLessThanOrEqual(maxViolations);
});
});
}
);
// ─── Full Device Matrix (skip with CI_QUICK=1) ───────────────────────────
+1 -1
View File
@@ -59,7 +59,7 @@ export const SELECTORS = {
// Device breakpoints (match app.js MobileDetection)
export const BREAKPOINTS = {
PHONE_MAX: 599,
PHONE_MAX: 600,
TABLET_MAX: 768,
} as const;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB