/* Unit tests for effects covering namedEffectTargetSchema; effectTargetSchema; glassEffectSchema. It also guards the documented public contract and regression-sensitive edge cases. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the effects suite's contract for test-file scaffold coverage. */ import { describe, it, expect } from "vitest"; import { namedEffectTargetSchema, effectTargetSchema, glassEffectSchema, effectSchema, effectAssignmentSchema, EFFECT_KIND_META, allowedKindsForTarget, resolveEffectsForTarget, hasEnabledGlassEffect, } from "../effects.ts"; import type { EffectAssignment } from "../effects.ts"; import type { z } from "zod"; type ParsedEffect = z.infer; describe("namedEffectTargetSchema", () => { it("accepts valid targets", () => { expect(namedEffectTargetSchema.parse("section")).toBe("section"); expect(namedEffectTargetSchema.parse("heading")).toBe("heading"); }); it("rejects invalid target", () => { expect(() => namedEffectTargetSchema.parse("unknown")).toThrow(); }); }); describe("effectTargetSchema", () => { it("accepts slot targets", () => { expect(effectTargetSchema.parse("slot:my-slot")).toBe("slot:my-slot"); }); it("rejects invalid slot format", () => { expect(() => effectTargetSchema.parse("slot:")).toThrow(); }); }); describe("glassEffectSchema", () => { it("accepts valid glass effect", () => { const result = glassEffectSchema.safeParse({ kind: "glass", enabled: true }); expect(result.success).toBe(true); }); it("rejects missing required fields", () => { expect(() => glassEffectSchema.parse({ kind: "glass" })).toThrow(); }); it("rejects extra keys (strict)", () => { expect(() => glassEffectSchema.parse({ kind: "glass", enabled: true, extra: true })).toThrow(); }); }); describe("effectSchema (discriminated union)", () => { it("accepts glass effect", () => { const result = effectSchema.safeParse({ kind: "glass", enabled: true }); expect(result.success).toBe(true); }); it("accepts shadow effect", () => { const result = effectSchema.safeParse({ kind: "shadow", enabled: true }); expect(result.success).toBe(true); }); it("accepts inset shadow effect", () => { const result = effectSchema.safeParse({ kind: "shadow", enabled: true, inset: true, offsetY: -24, }); expect(result.success).toBe(true); }); it("accepts fade effect", () => { const result = effectSchema.safeParse({ kind: "fade", enabled: true }); expect(result.success).toBe(true); }); it("rejects unknown kind", () => { expect(() => effectSchema.parse({ kind: "unknown", enabled: true })).toThrow(); }); }); describe("fadeEffectSchema", () => { it("accepts a bottom edge fade with all fields", () => { const result = effectSchema.safeParse({ kind: "fade", enabled: true, edge: "bottom", color: "surface", opacity: 0.9, extent: 0.4, }); expect(result.success).toBe(true); }); it("rejects extent above 0.5", () => { const result = effectSchema.safeParse({ kind: "fade", enabled: true, extent: 0.6 }); expect(result.success).toBe(false); }); it("rejects invalid edge", () => { const result = effectSchema.safeParse({ kind: "fade", enabled: true, edge: "diagonal" }); expect(result.success).toBe(false); }); }); describe("EFFECT_KIND_META", () => { it("has metadata for all effect kinds", () => { expect(EFFECT_KIND_META.glass.strategy).toBe("surface"); // shadow renders as text-shadow on text targets and as box-shadow on // surface targets (e.g. a cast shadow under `section`). expect(EFFECT_KIND_META.shadow.strategy).toBe("both"); }); }); describe("allowedKindsForTarget", () => { it("returns text kinds for heading", () => { const kinds = allowedKindsForTarget("heading"); expect(kinds).toContain("shadow"); expect(kinds).not.toContain("glass"); }); it("returns glass-only default for body", () => { const kinds = allowedKindsForTarget("body"); expect(kinds).toEqual(["glass"]); }); it("accepts lighten and fade on background", () => { const kinds = allowedKindsForTarget("background"); expect(kinds).toContain("lighten"); expect(kinds).toContain("fade"); }); it("accepts glass and shadow on section", () => { const kinds = allowedKindsForTarget("section"); expect(kinds).toContain("glass"); expect(kinds).toContain("shadow"); }); it("accepts a shadow assignment on section via effectAssignmentSchema", () => { const result = effectAssignmentSchema.safeParse({ target: "section", stack: [{ kind: "shadow", enabled: true, offsetY: 24, blur: 48, spread: -16 }], }); expect(result.success).toBe(true); }); it("rejects shadow on background via effectAssignmentSchema", () => { const result = effectAssignmentSchema.safeParse({ target: "background", stack: [{ kind: "shadow", enabled: true }], }); expect(result.success).toBe(false); }); it("rejects fade on heading via effectAssignmentSchema", () => { const result = effectAssignmentSchema.safeParse({ target: "heading", stack: [{ kind: "fade", enabled: true }], }); expect(result.success).toBe(false); }); it("accepts the generic surface pair on component-defined slot targets", () => { const kinds = allowedKindsForTarget("slot:footer-below"); expect(kinds).toEqual(["glass", "shadow"]); }); it("accepts a shadow assignment on a slot target via effectAssignmentSchema", () => { const result = effectAssignmentSchema.safeParse({ target: "slot:footer-below", stack: [{ kind: "shadow", enabled: true, offsetY: 24, blur: 48, spread: -16 }], }); expect(result.success).toBe(true); }); it("rejects typographic kinds on slot targets", () => { const result = effectAssignmentSchema.safeParse({ target: "slot:card-title", stack: [{ kind: "glow", enabled: true }], }); expect(result.success).toBe(false); }); }); describe("resolveEffectsForTarget", () => { it("returns empty array when no assignments", () => { expect(resolveEffectsForTarget(undefined, "section")).toEqual([]); }); it("returns effects for matching target", () => { const glassEffect: ParsedEffect = effectSchema.parse({ kind: "glass", enabled: true }); const assignments: EffectAssignment[] = [{ target: "section", stack: [glassEffect] }]; const effects = resolveEffectsForTarget(assignments, "section"); expect(effects).toHaveLength(1); }); }); describe("hasEnabledGlassEffect", () => { it("returns true when glass effect is enabled", () => { const e: ParsedEffect = effectSchema.parse({ kind: "glass", enabled: true }); expect(hasEnabledGlassEffect([e])).toBe(true); }); it("returns false when glass effect is disabled", () => { const e: ParsedEffect = effectSchema.parse({ kind: "glass", enabled: false }); expect(hasEnabledGlassEffect([e])).toBe(false); }); it("returns false when no effects", () => { expect(hasEnabledGlassEffect(undefined)).toBe(false); }); });