Replace bash mosaic-init with a modern 9-stage wizard: - SOUL.md identity, USER.md profile, TOOLS.md configuration - Runtime detection (Claude, Codex, OpenCode) + MCP setup - Skills catalog with categorized selection - Quick Start and Advanced modes - HeadlessPrompter for --non-interactive and CI usage - ConfigService abstraction layer for future DB migration - Bundled as single dist/mosaic-wizard.mjs via tsdown - mosaic init now prefers wizard when Node.js is available - 30 tests covering stages, templates, and integration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { renderTemplate } from '../../src/template/engine.js';
|
|
|
|
describe('renderTemplate', () => {
|
|
it('replaces all placeholders', () => {
|
|
const template = 'You are **{{AGENT_NAME}}**, role: {{ROLE_DESCRIPTION}}';
|
|
const result = renderTemplate(template, {
|
|
AGENT_NAME: 'Jarvis',
|
|
ROLE_DESCRIPTION: 'steward',
|
|
});
|
|
expect(result).toBe('You are **Jarvis**, role: steward');
|
|
});
|
|
|
|
it('preserves ${ENV_VAR} references', () => {
|
|
const template = 'Path: ${HOME}/.config, Agent: {{AGENT_NAME}}';
|
|
const result = renderTemplate(template, { AGENT_NAME: 'Test' });
|
|
expect(result).toBe('Path: ${HOME}/.config, Agent: Test');
|
|
});
|
|
|
|
it('handles multi-line values', () => {
|
|
const template = '{{PRINCIPLES}}';
|
|
const result = renderTemplate(template, {
|
|
PRINCIPLES: '1. First\n2. Second\n3. Third',
|
|
});
|
|
expect(result).toBe('1. First\n2. Second\n3. Third');
|
|
});
|
|
|
|
it('replaces unset vars with empty string by default', () => {
|
|
const template = 'Before {{MISSING}} After';
|
|
const result = renderTemplate(template, {});
|
|
expect(result).toBe('Before After');
|
|
});
|
|
|
|
it('throws in strict mode for missing vars', () => {
|
|
const template = '{{MISSING}}';
|
|
expect(() => renderTemplate(template, {}, { strict: true })).toThrow(
|
|
'Template variable not provided: {{MISSING}}',
|
|
);
|
|
});
|
|
|
|
it('handles multiple occurrences of same placeholder', () => {
|
|
const template = '{{NAME}} says hello, {{NAME}}!';
|
|
const result = renderTemplate(template, { NAME: 'Jarvis' });
|
|
expect(result).toBe('Jarvis says hello, Jarvis!');
|
|
});
|
|
|
|
it('preserves non-placeholder curly braces', () => {
|
|
const template = 'const x = { foo: {{VALUE}} }';
|
|
const result = renderTemplate(template, { VALUE: '"bar"' });
|
|
expect(result).toBe('const x = { foo: "bar" }');
|
|
});
|
|
});
|