import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import url from "node:url";
const repo = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), "../../..");
const gate = path.join(repo, "apps/site/tools/design-gate.mjs");
const work = fs.mkdtempSync(path.join(os.tmpdir(), "design-gate-contract-"));
const configFor = (page, extra = {}) => ({
pages: [{ name: "fixture", path: page, h1: "h1", ...extra }],
widths: [375, 390],
fontScales: [1, 1.3],
checks: {
meta: false,
contrast: false,
stack: false,
rhythm: false,
scaleMatrix: true,
tapTargets: false,
leftInset: false,
deadCss: false,
cssHygiene: false,
},
});
const run = (name, html, extra = {}) => {
const page = path.join(work, `${name}.html`);
const config = path.join(work, `${name}.json`);
fs.writeFileSync(page, html.replace("", ""));
fs.writeFileSync(config, JSON.stringify(configFor(page, extra)));
return spawnSync(process.execPath, [gate, `--config=${config}`], { cwd: work, encoding: "utf8" });
};
const outputOf = (result) => result.stdout + result.stderr;
try {
const flexible = run("flexible", `
A flexible display heading
`);
assert.equal(flexible.status, 0, outputOf(flexible));
assert.match(outputOf(flexible), /h1 보임 — [2-9]줄\(줄수 계약 없음\)/);
const capped = run("capped", `Heading that must wrap
`, { h1MaxLines: 1 });
assert.equal(capped.status, 1, outputOf(capped));
assert.match(outputOf(capped), /h1 — \d+줄\(최대 1줄\)/);
const expanded = run("expanded", `Scale tolerant design
`, { h1MaxLines: 1 });
assert.equal(expanded.status, 0, outputOf(expanded));
assert.match(outputOf(expanded), /375@1x:1줄/);
assert.match(outputOf(expanded), /375@1\.3x:[2-9]줄/);
const clipped = run("clipped", `Heading that is clipped when enlarged
`);
assert.equal(clipped.status, 1, outputOf(clipped));
assert.match(outputOf(clipped), /제목 텍스트 클리핑/);
const verticallyClipped = run("vertically-clipped", `Title that becomes vertically clipped
`);
assert.equal(verticallyClipped.status, 1, outputOf(verticallyClipped));
assert.match(outputOf(verticallyClipped), /제목 텍스트 클리핑 .+\(y\)/);
const missing = run("missing", `Existing heading
`, { h1: ".missing" });
assert.equal(missing.status, 1, outputOf(missing));
assert.match(outputOf(missing), /h1 선택자 없음 \(\.missing\)/);
const empty = run("empty", ``);
assert.equal(empty.status, 1, outputOf(empty));
assert.match(outputOf(empty), /h1 — 텍스트 없음/);
console.log("design-gate-contract: 7 passed");
} finally {
fs.rmSync(work, { recursive: true, force: true });
}