import { describe, expect, it } from "vitest"; import { BUILTIN_ROUTINE_VARIABLE_NAMES, extractRoutineVariableNames, getBuiltinRoutineVariableValues, interpolateRoutineTemplate, isBuiltinRoutineVariable, syncRoutineVariablesWithTemplate, } from "./routine-variables.js"; describe("routine variable helpers", () => { it("extracts placeholder names in first-appearance order", () => { expect( extractRoutineVariableNames("Review {{repo}} and {{priority}} for {{repo}}"), ).toEqual(["repo", "priority"]); }); it("deduplicates placeholder names across the routine title and description", () => { expect( extractRoutineVariableNames([ "Triage {{repo}}", "Review {{repo}} for {{priority}} bugs", ]), ).toEqual(["repo", "priority"]); }); it("preserves existing metadata when syncing variables from a template", () => { expect( syncRoutineVariablesWithTemplate(["Triage {{repo}}", "Review {{repo}} and {{priority}}"], [ { name: "repo", label: "Repository", type: "text", defaultValue: "paperclip", required: true, options: [] }, ]), ).toEqual([ { name: "repo", label: "Repository", type: "text", defaultValue: "paperclip", required: true, options: [] }, { name: "priority", label: null, type: "text", defaultValue: null, required: true, options: [] }, ]); }); it("interpolates provided variable values into the routine template", () => { expect( interpolateRoutineTemplate("Review {{repo}} for {{priority}}", { repo: "paperclip", priority: "high", }), ).toBe("Review paperclip for high"); }); it("identifies built-in variable names", () => { expect(isBuiltinRoutineVariable("date")).toBe(true); expect(isBuiltinRoutineVariable("timestamp")).toBe(true); expect(isBuiltinRoutineVariable("repo")).toBe(false); expect(BUILTIN_ROUTINE_VARIABLE_NAMES.has("date")).toBe(true); expect(BUILTIN_ROUTINE_VARIABLE_NAMES.has("timestamp")).toBe(true); }); it("getBuiltinRoutineVariableValues returns date in YYYY-MM-DD format", () => { const values = getBuiltinRoutineVariableValues(); expect(values.date).toMatch(/^\d{4}-\d{2}-\d{2}$/); expect(values.date).toBe(new Date().toISOString().slice(0, 10)); }); it("getBuiltinRoutineVariableValues returns a human-readable timestamp with year, time, and UTC", () => { const values = getBuiltinRoutineVariableValues(); const year = String(new Date().getUTCFullYear()); expect(values.timestamp).toContain(year); expect(values.timestamp).toMatch(/\d{1,2}:\d{2}\s?(AM|PM)/); expect(values.timestamp).toContain("UTC"); }); it("excludes built-in variables from syncRoutineVariablesWithTemplate", () => { const result = syncRoutineVariablesWithTemplate( "Daily report for {{date}} at {{timestamp}} — {{repo}}", [], ); expect(result).toEqual([ { name: "repo", label: null, type: "text", defaultValue: null, required: true, options: [] }, ]); }); it("extracts snake_case variable names", () => { expect(extractRoutineVariableNames("Open {{pr_url}} for review")).toEqual(["pr_url"]); }); it("extracts variable names whose underscores were markdown-escaped by a WYSIWYG editor", () => { // MDXEditor / mdast-util-to-markdown defensively escape intraword underscores // when serializing rich-text back to markdown, so `{{pr_url}}` is stored as `{{pr\_url}}`. expect(extractRoutineVariableNames("Open {{pr\\_url}} for review")).toEqual(["pr_url"]); expect(extractRoutineVariableNames("{{pr\\_url\\_v2}}")).toEqual(["pr_url_v2"]); }); it("syncRoutineVariablesWithTemplate handles markdown-escaped underscores", () => { expect( syncRoutineVariablesWithTemplate("Open {{pr\\_url}}", []), ).toEqual([ { name: "pr_url", label: null, type: "text", defaultValue: null, required: true, options: [] }, ]); }); it("interpolates variables that appear with markdown-escaped underscores", () => { expect( interpolateRoutineTemplate("Open {{pr\\_url}}", { pr_url: "https://example.com" }), ).toBe("Open https://example.com"); }); it("interpolates built-in variables alongside user variables", () => { const builtins = getBuiltinRoutineVariableValues(); const allVars = { ...builtins, repo: "paperclip" }; expect( interpolateRoutineTemplate("Report for {{date}} ({{timestamp}}) on {{repo}}", allVars), ).toBe(`Report for ${builtins.date} (${builtins.timestamp}) on paperclip`); }); });