92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
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 .bcal-root, not :root", () => {
|
|
const root = block(".bcal-root");
|
|
expect(root).not.toBe("");
|
|
for (const name of OBSIDIAN_VARS) {
|
|
expect(root, `${name} must be aliased on .bcal-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 .bcal-root");
|
|
expect(source).not.toMatch(/\n\.theme-dark\s*\{/);
|
|
});
|
|
});
|
|
|
|
describe("reset specificity", () => {
|
|
it("does not use :where() for element resets", () => {
|
|
expect(source).not.toMatch(/\.bcal-root\s+:where\(/);
|
|
});
|
|
|
|
it("uses a doubled class to outrank app and theme styles", () => {
|
|
expect(source).toContain(".bcal-root.bcal-root");
|
|
});
|
|
|
|
it("neutralises the native search affordance", () => {
|
|
expect(source).toContain("-webkit-search-cancel-button");
|
|
});
|
|
});
|
|
|
|
describe("cascade against Obsidian", () => {
|
|
it("marks utilities important so they outrank app.css", () => {
|
|
expect(source).toMatch(
|
|
/@import "tailwindcss\/utilities\.css"[^;]*\bimportant\b/,
|
|
);
|
|
});
|
|
|
|
it("keeps the element reset out of a cascade layer", () => {
|
|
const reset = source.indexOf(".bcal-root.bcal-root :is(button");
|
|
expect(reset).toBeGreaterThan(-1);
|
|
const before = source.slice(0, reset);
|
|
const opens = (before.match(/@layer[^;{]*\{/g) ?? []).length;
|
|
const closes = (before.match(/\n\}/g) ?? []).length;
|
|
expect(opens, "reset must be unlayered").toBeLessThanOrEqual(closes);
|
|
});
|
|
});
|
|
|
|
describe("preflight stays out", () => {
|
|
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/);
|
|
});
|
|
});
|