/** * Integration tests for all preset bundles. */ import { describe, expect, it } from "@suaveplan/testing/runner"; import type { createParseState } from "../src/engine/ParseState.js"; import { TemplateEngine } from "../src/engine/TemplateEngine.js"; import { fullPreset, fullPresetWithLoops } from "../src/presets/full.js"; import { minimalPreset } from "../src/presets/minimal.js"; import { standardPreset } from "../src/presets/standard.js"; type Ctx = Record; describe("minimalPreset", () => { it("resolves dot-notation", { timeout: 5000 }, () => { const e = new TemplateEngine().usePreset(minimalPreset()); expect(e.parse("{user.name}", { user: { name: "Alice" } })).toBe( "Alice" ); }); it("resolves array index", { timeout: 5000 }, () => { const e = new TemplateEngine().usePreset(minimalPreset()); expect(e.parse("{items[1]}", { items: ["a", "b"] })).toBe("b"); }); it("has 2 plugins", { timeout: 5000 }, () => { const e = new TemplateEngine().usePreset(minimalPreset()); expect(e.getPlugins()).toHaveLength(2); }); }); describe("standardPreset", () => { it("resolves variables, counter, case transform, conditional", { timeout: 5000, }, () => { const e = new TemplateEngine().usePreset(standardPreset()); const result = e.parse( "{if:active}Hello {name:title}! #{_counter}{/if}", { active: true, name: "john doe" } ); expect(result).toBe("Hello John Doe! #1"); }); it("generates UUID in standard preset", { timeout: 5000 }, () => { const e = new TemplateEngine().usePreset(standardPreset()); const result = e.parse("{_uuid}", {}); expect(result).toMatch( /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/ ); }); }); describe("fullPreset", () => { it("includes regex and string-split", { timeout: 5000 }, () => { const e = new TemplateEngine().usePreset(fullPreset()); expect( e.parse("{phone:/\\D/g:replace:}", { phone: "(123) 456-7890" }) ).toBe("1234567890"); expect(e.parse("{email:@[0]}", { email: "user@example.com" })).toBe( "user" ); }); }); describe("fullPresetWithLoops", () => { it("iterates array with loop plugin", { timeout: 5000 }, () => { const e = new TemplateEngine(); const preset = fullPresetWithLoops((tpl, ctx, state) => ( e as unknown as { parseInternal: ( t: string, c: Ctx, s: ReturnType ) => string; } ).parseInternal(tpl, ctx, state) ); e.usePreset(preset); const result = e.parse("{each:items}{item} {/each}", { items: ["X", "Y", "Z"], }); expect(result).toBe("X Y Z "); }); it("preset name is full-with-loops", { timeout: 5000 }, () => { const preset = fullPresetWithLoops((t, c) => t); expect(preset.name).toBe("full-with-loops"); }); }); describe("preset registration idempotency", () => { it("applying same preset twice does not duplicate plugins", { timeout: 5000, }, () => { const e = new TemplateEngine(); e.usePreset(minimalPreset()); const countAfterFirst = e.getPlugins().length; e.usePreset(minimalPreset()); expect(e.getPlugins()).toHaveLength(countAfterFirst); }); });