Repository navigation
Expand file tree
/
Copy pathtest-stress-render.ts
More file actions
100 lines (91 loc) · 5.1 KB
/
Copy pathtest-stress-render.ts
File metadata and controls
100 lines (91 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Phase 24 slice D — stress through a real render: a rigid fixture must break
// under perturbation, a fluid fixture must stay clean. Chrome required.
//
// Usage: npx tsx test-stress-render.ts
import './test-env.js';
import { createCanvas } from './src/scene-graph.js';
import { parseAndExecute } from './src/operations.js';
import { resolveVariables } from './src/variables.js';
import { renderToHtml } from './src/renderer.js';
import { computeLayout, shutdown } from './src/screenshot.js';
import { applyPerturbation, compareLayouts, type PerturbationName } from './src/stress.js';
import type { Canvas } from './src/types.js';
let allPass = true;
function check(name: string, cond: boolean, extra?: string) {
if (!cond) allPass = false;
console.log(`${cond ? 'PASS' : 'FAIL'} ${name}${extra ? ` — ${extra}` : ''}`);
}
const W = 800;
const H = 600;
async function stress(canvas: Canvas, name: PerturbationName) {
const baselineHtml = renderToHtml(resolveVariables(structuredClone(canvas.root), {}), W, H, canvas);
const baseline = await computeLayout(baselineHtml, undefined, 25, { width: W, height: H });
const { root, touched } = applyPerturbation(name, canvas.root);
if (touched.length === 0) return { findings: [], skipped: true };
const html = renderToHtml(resolveVariables(structuredClone(root), {}), W, H, canvas);
const layout = await computeLayout(html, undefined, 25, { width: W, height: H });
return { findings: compareLayouts(baseline, layout, touched, W), skipped: false };
}
try {
// RIGID: fixed height + overflow hidden → long text must clip.
const rigid = createCanvas('stress-rigid');
rigid.root.width = W; rigid.root.height = H;
parseAndExecute(rigid.root, `
card=I("document", { type: "frame", width: 320, height: 44, overflow: "hidden", padding: 12 })
I(card, { type: "text", content: "Customer display name", fontSize: 14 })
`, rigid);
const r1 = await stress(rigid, 'long-text');
check('rigid fixture: long-text → clip warning', !r1.skipped && r1.findings.some((f) => f.kind === 'clip' && f.severity === 'warning'), JSON.stringify(r1.findings));
// RIGID numbers: a tight fixed-width badge must break under 999+.
const badge = createCanvas('stress-badge');
badge.root.width = W; badge.root.height = H;
parseAndExecute(badge.root, `
row=I("document", { type: "frame", layout: "horizontal", width: 200, gap: 8 })
I(row, { type: "text", content: "Inbox", fontSize: 14 })
b=I(row, { type: "frame", width: 22, height: 18, cornerRadius: 9, fill: "#111827", alignItems: "center", justifyContent: "center", overflow: "hidden" })
I(b, { type: "text", content: "9", fontSize: 11, color: "#FFFFFF" })
`, badge);
const r2 = await stress(badge, 'big-numbers');
check('badge fixture: big-numbers → breakage', !r2.skipped && r2.findings.some((f) => f.severity === 'warning'), JSON.stringify(r2.findings));
// FLUID: fit-content height, fluid width, wrapping allowed → clean under everything.
const fluid = createCanvas('stress-fluid');
fluid.root.width = W; fluid.root.height = H;
parseAndExecute(fluid.root, `
card=I("document", { type: "frame", width: "100%", layout: "vertical", gap: 8, padding: 16 })
I(card, { type: "text", content: "Customer display name", fontSize: 14 })
I(card, { type: "text", content: "$1.52M", fontSize: 20, fontWeight: 600 })
`, fluid);
for (const name of ['long-text', 'i18n', 'big-numbers'] as PerturbationName[]) {
const r = await stress(fluid, name);
check(`fluid fixture: ${name} → clean`, !r.skipped && r.findings.filter((f) => f.severity === 'warning').length === 0, JSON.stringify(r.findings));
}
// TABLE: empty/many render without breakage on a fluid table.
const tbl = createCanvas('stress-table');
tbl.root.width = W; tbl.root.height = H;
parseAndExecute(tbl.root, `
t=I("document", { type: "frame", layout: "vertical", width: "100%", gap: 0 })
h=I(t, { type: "frame", layout: "horizontal", gap: 16, padding: 8 })
h1=I(h, { type: "frame", width: "60%" })
I(h1, { type: "text", content: "NAME" })
h2=I(h, { type: "frame", width: "40%" })
I(h2, { type: "text", content: "STATUS" })
r1=I(t, { type: "frame", layout: "horizontal", gap: 16, padding: 8 })
c1=I(r1, { type: "frame", width: "60%" })
I(c1, { type: "text", content: "Live stream" })
c2=I(r1, { type: "frame", width: "40%" })
I(c2, { type: "text", content: "active" })
r2=I(t, { type: "frame", layout: "horizontal", gap: 16, padding: 8 })
c3=I(r2, { type: "frame", width: "60%" })
I(c3, { type: "text", content: "VOD library" })
c4=I(r2, { type: "frame", width: "40%" })
I(c4, { type: "text", content: "paused" })
`, tbl);
const rEmpty = await stress(tbl, 'empty');
check('table fixture: empty perturbation renders clean', !rEmpty.skipped && rEmpty.findings.filter((f) => f.severity === 'warning').length === 0, JSON.stringify(rEmpty.findings));
const rMany = await stress(tbl, 'many');
check('table fixture: many perturbation renders clean', !rMany.skipped && rMany.findings.filter((f) => f.severity === 'warning').length === 0, JSON.stringify(rMany.findings));
} finally {
await shutdown();
}
console.log(allPass ? '\nAll stress-render tests passed.' : '\nSOME TESTS FAILED');
process.exit(allPass ? 0 : 1);