Files
Jyotisha/frontend/tests/touch-target-contract.test.ts
T
jesse-ux 6c748d86b0
Independent Staging Quality Gate / validate (push) Failing after 8m53s
Independent Staging Quality Gate / publish (push) Skipped
fix(ui): 44px coarse hits and align CSS breakpoints
Touch-screen message actions get a 44x44 hit once gap and bottom margin open to 20px; fine-pointer geometry stays 27x34. Tablet CSS cuts at 1023 to match sidebarViewportForWidth. Report centre/reader join the 767 mobile cut; TOC keeps 860. Occupies BUG-695/696/697.
2026-09-15 12:46:59 +08:00

61 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import { cssDeclarations } from "./css-contract-test-support.ts";
const globalStyles = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
function minHeightPx(selector: string) {
const matches = [...cssDeclarations(selector, globalStyles).matchAll(/min-height:\s*(\d+)px/g)]
.map((hit) => Number(hit[1]));
assert.ok(matches.length > 0, `${selector} must declare min-height`);
return Math.max(...matches);
}
function hasHitExpandPseudo(selector: string) {
const after = cssDeclarations(`${selector}::after`, globalStyles);
assert.match(after, /position:\s*absolute/);
assert.match(after, /content:\s*""/);
return after;
}
test("40px controls grow to a 44px box when that does not pack a scrolling list badly", () => {
assert.ok(minHeightPx(".select-item") >= 44);
assert.ok(minHeightPx(".birth-time-window-details .birth-time-skip-button") >= 44);
assert.ok(minHeightPx(".report-center-section-heading button") >= 44);
});
test("icon and chip controls keep their visual size and expand the hit with a pseudo-element", () => {
const actions = cssDeclarations(".message-actions button", globalStyles);
assert.match(actions, /width:\s*26px/);
assert.match(actions, /height:\s*26px/);
assert.match(cssDeclarations(".message-actions", globalStyles), /gap:\s*1px/);
const actionHit = hasHitExpandPseudo(".message-actions button");
// 原值: 热区锁 27×3444×44 会与相邻按钮和 follow-up 重叠)。
// 新值: 细指针仍是 27×34;粗指针见下一条,gap 20px + 底边 20px 后才放大到 44×44。
// 原因: BUG-695,触屏点赞容易点成点踩。
assert.match(actionHit, /width:\s*27px/);
assert.match(actionHit, /height:\s*34px/);
assert.equal(minHeightPx(".chart-nav-chip"), 32);
assert.match(hasHitExpandPseudo(".chart-nav-chip"), /inset:\s*-4px/);
const auth = cssDeclarations(".auth-links button", globalStyles);
assert.match(auth, /min-height:\s*32px/);
assert.match(hasHitExpandPseudo(".auth-links button"), /inset:\s*-4px/);
});
test("coarse pointers get a 44×44 message-action hit that does not overlap neighbours", () => {
const coarseStart = globalStyles.indexOf("@media (pointer: coarse)");
assert.notEqual(coarseStart, -1);
const coarse = globalStyles.slice(coarseStart, globalStyles.indexOf("}", globalStyles.indexOf(".markdown-code-copy", coarseStart)) + 1);
assert.match(coarse, /\.message-actions \{[\s\S]*gap:\s*var\(--space-5\)/);
assert.match(coarse, /margin-bottom:\s*var\(--space-5\)/);
assert.match(coarse, /\.message-actions button::after \{[\s\S]*width:\s*44px;[\s\S]*height:\s*44px;/);
assert.match(coarse, /\.markdown-code-copy \{[\s\S]*min-height:\s*44px;/);
const base = globalStyles.slice(0, coarseStart);
assert.match(base, /\.message-actions \{[\s\S]*gap:\s*1px;/);
assert.match(base, /\.message-actions button::after \{[\s\S]*width:\s*27px;[\s\S]*height:\s*34px;/);
});