import { readFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; const source = readFileSync( join(import.meta.dirname, "../src/tailwind.css"), "utf8" ); function block(selector: string): string { const at = source.indexOf(`\n${selector} {`); if (at === -1) { return ""; } const open = source.indexOf("{", at); const close = source.indexOf("\n}", open); return source.slice(open, close); } describe("theme aliases", () => { const OBSIDIAN_VARS = [ "--background-primary", "--background-secondary", "--background-modifier-border", "--text-normal", "--text-muted", "--color-accent", "--text-on-accent", "--text-error", ]; it("are declared on .beaver-root, not :root", () => { const root = block(".beaver-root"); expect(root).not.toBe(""); for (const name of OBSIDIAN_VARS) { expect(root, `${name} must be aliased on .beaver-root`).toContain(name); } }); it("never reference Obsidian variables from :root", () => { const rootBlocks = [...source.matchAll(/(^|\n):root\s*\{([^}]*)\}/g)]; for (const [, , body] of rootBlocks) { for (const name of OBSIDIAN_VARS) { expect(body, `:root must not reference ${name}`).not.toContain(name); } } }); it("scopes the dark override under the view root", () => { expect(source).toContain(".theme-dark .beaver-root"); expect(source).not.toMatch(/\n\.theme-dark\s*\{/); }); it("keeps the msos palette out: the live accent is Obsidian's", () => { const root = block(".beaver-root"); expect(root).toContain("--signal: var(--color-accent)"); expect(root).toContain("--primary: var(--color-accent)"); expect(root).not.toMatch(/oklch\([^)]*\s34[0-2]\)/); }); }); describe("reset specificity", () => { it("uses a doubled class to outrank app and theme styles", () => { expect(source).toContain(".beaver-root.beaver-root"); }); it("gives every control Obsidian's corner language", () => { expect(source).toContain('[data-slot="button"]'); expect(source).toContain("var(--button-radius"); expect(source).toContain('[data-slot="input"]'); }); }); describe("cascade against Obsidian", () => { it("marks utilities important so they outrank app.css", () => { expect(source).toMatch( /@import "tailwindcss\/utilities\.css"[^;]*\bimportant\b/ ); }); it("scans the shared panel sources", () => { expect(source).toContain('@source "../../beaver-gateway/ui/src/lib"'); expect(source).toContain("panel/panel.css"); }); it("imports only the theme and utility layers", () => { expect(source).toContain('@import "tailwindcss/theme.css"'); expect(source).toContain('@import "tailwindcss/utilities.css"'); expect(source).not.toMatch(/@import "tailwindcss"\s*[;l]/); expect(source).not.toMatch(/@import\s+"tailwindcss\/preflight/); }); });