Files
Jyotisha/frontend/tests/starter-entry-soften.test.ts
T
jesse-uxandClaude Code 36a737616c
Independent Staging Quality Gate / validate (push) Failing after 12m24s
Independent Staging Quality Gate / publish (push) Skipped
fix(frontend): repair staging breakpoint and focus contracts
Merge entry overflow rules into the existing 480px breakpoint, restore picker focus without scrolling, and sync composer and entry contracts without changing page logic. Add AST generation-state guard and both picker close-path regressions.

Validation: targeted 33/33; Chrome isolated components 145 checks; tsc and lint zero errors. Node22 full suite 3706 tests, no lost names or new failures; three target failures fixed, 88 baseline environment/contract failures unchanged. Windows build remains blocked by symlink EPERM. Changed-file privacy check: 11 files, no findings, not a full-repository pass. BUG-1011 remains separate.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:31:10 +08:00

43 lines
2.6 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const starterHome = readFileSync(new URL("../src/components/starter-home.tsx", import.meta.url), "utf8");
const css = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
const design = readFileSync(new URL("../DESIGN.md", import.meta.url), "utf8");
function starterEntryBlock(): string {
const start = css.indexOf(".starter-entry {");
const end = css.indexOf(".starter-entry > svg");
assert.ok(start >= 0 && end > start);
return css.slice(start, end);
}
test("starter entries stay native buttons with a 36px pill and a 44px hit area", () => {
assert.match(starterHome, /<button[\s\S]*className="starter-entry"/);
assert.equal(starterHome.match(/className="starter-entry"/g)?.length, 2);
assert.doesNotMatch(starterHome, /starter-hero|product-entrypoint|daily-starlanguage-card|birth-rectification-card/);
assert.doesNotMatch(starterHome, /正在加载|InlineSpinner|animate-spin/);
const block = starterEntryBlock();
assert.match(block, /min-height:\s*36px/);
assert.match(block, /--starter-entry-border:\s*color-mix\(in srgb, var\(--color-border\) 62%, transparent\)/);
assert.match(block, /border:\s*1px solid var\(--starter-entry-border\)/);
assert.doesNotMatch(block, /border:\s*1px solid var\(--color-border-strong\)/);
assert.match(css, /\.starter-entry::after\s*\{[^}]*inset:\s*-4px/);
});
test("starter entry hover stays softer than the action color and focus is a 3px ring", () => {
const hover = css.slice(css.indexOf(".starter-entry:not(:disabled):hover"), css.indexOf(".starter-entry:focus-visible"));
assert.match(hover, /color-mix\(in srgb, var\(--color-border-strong\) 45%, var\(--color-border\)\)/);
assert.doesNotMatch(hover, /border-color:\s*var\(--color-action\)/);
assert.match(css, /\.starter-entry:focus-visible\s*\{[^}]*outline:\s*3px solid color-mix\(in srgb, var\(--color-focus\) 80%, transparent\)/);
assert.match(css, /\.starter-entry\[data-opening="true"\]\s*\{\s*cursor:\s*progress/);
// 原值:入口行 max-width: 100% 位于 max-width: 375px 媒体块。
// 新值:同一防溢出规则位于既有 max-width: 480px 媒体块。
// 原因:BUG-1012 按 BUG-697 收敛断点,不扩白名单;按钮尺寸、焦点与防溢出要求不变。
assert.match(css, /@media \(max-width:\s*480px\)\s*\{[^}]*\.starter-entry-row\s*\{\s*max-width:\s*100%/);
assert.match(css, /@media \(prefers-reduced-motion:\s*reduce\)[\s\S]*transition-duration:\s*\.01ms !important/);
assert.match(design, /--starter-entry-border/);
assert.match(design, /inset: -4px/);
});