Files
lms-sb/src/lib/tools/__tests__/callout.test.ts
T
admins b6d555ab3b Add Obsidian Toolbox — 4 syntax generators under /tools
Inside-LMS toolbox for registered students: callout-CSS, YAML-frontmatter,
theme CSS-variables, Style Settings generators. Auth inherited from (student)
route group; no public surface, no email gate.

- Pure generators in src/lib/tools/* with Vitest (33 tests)
- Shared YAML-safe scalar quoter (_shared/yaml.ts) used by frontmatter +
  style-settings: unquoted user input was silently breaking YAML (tags '#x'
  -> null, color default '#7C3AED' -> null, 'a: b' -> parse error)
- hex validation in callout (no NaN), date input constrained, clipboard +
  analytics calls guarded
- Prisma ToolUsage model + migration; logToolUsage Server Action (auth-first,
  10-min dedup window per user/tool)
- Tool index /tools + ToolCard (explicit lucide map, no import *) + header link

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 15:45:52 +05:00

36 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from "vitest";
import { buildCalloutCss, normalizeCalloutId } from "@/lib/tools/callout";
describe("normalizeCalloutId", () => {
it("слагифицирует пробелы и регистр", () => {
expect(normalizeCalloutId("My Note ")).toBe("my-note");
});
it("выкидывает недопустимые символы", () => {
expect(normalizeCalloutId("Идея!@# 2")).toBe("2");
});
});
describe("buildCalloutCss", () => {
it("генерирует css с data-callout и rgb", () => {
const r = buildCalloutCss({ id: "idea", title: "Идея", color: "#7C3AED", icon: "lightbulb" });
expect(r.css).toContain('[data-callout="idea"]');
expect(r.css).toContain("--callout-color: 124, 58, 237;");
expect(r.css).toContain("--callout-icon: lucide-lightbulb;");
});
it("поддерживает короткий hex", () => {
const r = buildCalloutCss({ id: "x", title: "X", color: "#fff", icon: "star" });
expect(r.css).toContain("--callout-color: 255, 255, 255;");
});
it("кидает на пустом id", () => {
expect(() => buildCalloutCss({ id: "!!!", title: "", color: "#000", icon: "x" })).toThrow();
});
it("markdown содержит [!id]", () => {
const r = buildCalloutCss({ id: "warn", title: "Внимание", color: "#f00", icon: "alert" });
expect(r.markdown).toContain("> [!warn] Внимание");
});
it("кидает на некорректном HEX (не отдаёт NaN)", () => {
expect(() => buildCalloutCss({ id: "x", title: "X", color: "#zz", icon: "star" })).toThrow();
expect(() => buildCalloutCss({ id: "x", title: "X", color: "#1234", icon: "star" })).toThrow();
});
});