import { afterEach, describe, expect, it } from "vitest"; import { defaultConfig } from "@tamagui/config/v5"; import { defaultHeadingFont } from "../theme/defaults/fonts"; import { defaultKnobs } from "../theme/knobs"; import { resolveKnobs } from "../theme/resolveKnobs"; import { GAP_KNOB, GAP_LG_KNOB, runConstraintAudit } from "./constraintAudit"; afterEach(() => { document.body.innerHTML = ""; }); // Deliberately loses module scope, like Playwright page.evaluate. const audit = new Function( `return (${runConstraintAudit.toString()})()`, ) as typeof runConstraintAudit; function specimen(style: string, attrs: Record = {}) { const el = document.createElement("div"); el.id = "specimen"; el.style.cssText = style; for (const [key, value] of Object.entries(attrs)) el.setAttribute(key, value); document.body.append(el); return el; } function measured() { return audit().elements.find((el) => el.id === "specimen"); } function card(radius: string, space: string, tier = "content") { return { "data-constraint-container": "Card", "data-tier": tier, "data-radius-knob": radius, "data-space-knob": space, }; } describe("Card container cap, independently measured against canonical stops", () => { for (const tier of ["content", "elevated"]) { for (const [radius, stop] of Object.entries({ none: 0, small: 5, medium: 9, large: 16, full: 50, })) { for (const [space, inset] of Object.entries({ small: 13, medium: 18, large: 32 })) { it(`${tier}/${radius}/${space} accepts all four capped corners`, () => { specimen( `border-radius:${Math.min(stop, inset)}px;padding:${inset}px`, card(radius, space, tier), ); expect(measured()?.violations).toEqual([]); expect(measured()?.paddingTop?.value).toBe(inset); }); } } } it.each([ ["unrelated 13px", "border-radius:13px;padding:13px", {}], [ "tier alone is not Card provenance", "border-radius:13px;padding:13px", { "data-tier": "content" }, ], ["16 exceeds 13 inset", "border-radius:16px;padding:13px", card("large", "small")], ["wrong last corner", "border-radius:13px 13px 13px 9px;padding:13px", card("full", "small")], ["nonzero at none", "border-radius:5px;padding:13px", card("none", "small")], ["arbitrary matching inset", "border-radius:14px;padding:14px", card("full", "small")], ["wrong canonical inset", "border-radius:18px;padding:18px", card("full", "small")], ["missing inset", "border-radius:0;padding:0", card("none", "small")], [ "wrong individual inset", "border-radius:13px;padding:13px 18px 13px 13px", card("full", "small"), ], ["percent radius cannot bypass cap", "border-radius:50%;padding:13px", card("full", "small")], [ "elliptical corner cannot bypass cap", "border-radius:13px / 16px;padding:13px", card("full", "small"), ], ])("rejects %s", (_label, style, attrs) => { specimen(style, attrs); expect(measured()?.violations.length).toBeGreaterThan(0); }); it("leaves ordinary control radius rules intact", () => { specimen("border-radius:16px;padding:13px"); expect(measured()?.violations).toEqual([]); }); it.each([ "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius", ])("rejects a wrong %s even when every radius is on the generic scale", (corner) => { const el = specimen("border-radius:9px;padding:13px", card("medium", "small")); el.style.setProperty(corner, "5px"); expect(measured()?.borderRadius?.offScale).toBe(true); expect(measured()?.violations).toHaveLength(1); }); }); describe("canonical gapLg parity in the serialized audit", () => { for (const space of ["small", "medium", "large"] as const) { it(space, () => { const token = resolveKnobs({ ...defaultKnobs, space }).knobProps.gapLg.gap; const px = defaultConfig.tokens.space[token as keyof typeof defaultConfig.tokens.space]; expect(GAP_LG_KNOB[space]).toBe(px); const gapToken = resolveKnobs({ ...defaultKnobs, space }).knobProps.gap.gap; const gapPx = defaultConfig.tokens.space[gapToken as keyof typeof defaultConfig.tokens.space]; expect(GAP_KNOB[space]).toBe(gapPx); specimen(`row-gap:${px}px;column-gap:${gapPx}px`); expect(measured()?.rowGap?.offScale).toBe(false); expect(measured()?.columnGap?.offScale).toBe(false); }); } it.each([22, 25, 31, 33])("rejects non-recipe gap %i", (gap) => { specimen(`row-gap:${gap}px`); expect(measured()?.rowGap?.offScale).toBe(true); }); }); describe("font weight provenance", () => { it("pins the configured heading source behind the self-contained whitelist", () => { expect([...new Set(Object.values(defaultHeadingFont.weight).map(Number))].sort()).toEqual([ 600, 700, 800, ]); }); it.each([600, 800])("accepts configured heading weight %i as unitless", (weight) => { expect(Object.values(defaultConfig.fonts.heading.weight)).toContain(String(weight)); specimen(`font-weight:${weight}`, { class: "font_heading" }); expect(measured()?.fontWeight).toMatchObject({ value: weight, unit: "", offScale: false }); expect(measured()?.fontWeight?.knob).toContain("configured heading"); }); it.each([500, 650, 900])("rejects unconfigured weight %i", (weight) => { specimen(`font-weight:${weight}`, { class: "font_heading" }); expect(measured()?.fontWeight?.offScale).toBe(true); expect(measured()?.violations.join(" ")).not.toContain(`${weight}px`); }); it("does not grant arbitrary elements heading weights", () => { specimen("font-weight:800"); expect(measured()?.fontWeight?.offScale).toBe(true); }); it.each([ ["regular", 700], ["bold", 800], ["bold", 400], ])("checks explicit %s recipe against %i even when configured", (knob, weight) => { specimen(`font-weight:${weight}`, { class: "font_heading", "data-font-weight-knob": knob }); expect(measured()?.fontWeight?.offScale).toBe(true); }); });