feat: TypeScript installation wizard with @clack/prompts TUI (#1)
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #1.
This commit is contained in:
99
tests/template/builders.test.ts
Normal file
99
tests/template/builders.test.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
buildSoulTemplateVars,
|
||||
buildUserTemplateVars,
|
||||
buildToolsTemplateVars,
|
||||
} from '../../src/template/builders.js';
|
||||
|
||||
describe('buildSoulTemplateVars', () => {
|
||||
it('builds direct style correctly', () => {
|
||||
const vars = buildSoulTemplateVars({
|
||||
agentName: 'Jarvis',
|
||||
communicationStyle: 'direct',
|
||||
});
|
||||
expect(vars.AGENT_NAME).toBe('Jarvis');
|
||||
expect(vars.BEHAVIORAL_PRINCIPLES).toContain('Clarity over performance theater');
|
||||
expect(vars.COMMUNICATION_STYLE).toContain('Be direct, concise, and concrete');
|
||||
});
|
||||
|
||||
it('builds friendly style correctly', () => {
|
||||
const vars = buildSoulTemplateVars({
|
||||
communicationStyle: 'friendly',
|
||||
});
|
||||
expect(vars.BEHAVIORAL_PRINCIPLES).toContain('Be helpful and approachable');
|
||||
expect(vars.COMMUNICATION_STYLE).toContain('Be warm and conversational');
|
||||
});
|
||||
|
||||
it('builds formal style correctly', () => {
|
||||
const vars = buildSoulTemplateVars({
|
||||
communicationStyle: 'formal',
|
||||
});
|
||||
expect(vars.BEHAVIORAL_PRINCIPLES).toContain('Maintain professional, structured');
|
||||
expect(vars.COMMUNICATION_STYLE).toContain('Use professional, structured language');
|
||||
});
|
||||
|
||||
it('appends accessibility to principles', () => {
|
||||
const vars = buildSoulTemplateVars({
|
||||
communicationStyle: 'direct',
|
||||
accessibility: 'ADHD-friendly chunking',
|
||||
});
|
||||
expect(vars.BEHAVIORAL_PRINCIPLES).toContain('6. ADHD-friendly chunking.');
|
||||
});
|
||||
|
||||
it('does not append accessibility when "none"', () => {
|
||||
const vars = buildSoulTemplateVars({
|
||||
communicationStyle: 'direct',
|
||||
accessibility: 'none',
|
||||
});
|
||||
expect(vars.BEHAVIORAL_PRINCIPLES).not.toContain('6.');
|
||||
});
|
||||
|
||||
it('formats custom guardrails', () => {
|
||||
const vars = buildSoulTemplateVars({
|
||||
customGuardrails: 'Never auto-commit',
|
||||
});
|
||||
expect(vars.CUSTOM_GUARDRAILS).toBe('- Never auto-commit');
|
||||
});
|
||||
|
||||
it('uses defaults when config is empty', () => {
|
||||
const vars = buildSoulTemplateVars({});
|
||||
expect(vars.AGENT_NAME).toBe('Assistant');
|
||||
expect(vars.ROLE_DESCRIPTION).toBe('execution partner and visibility engine');
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildUserTemplateVars', () => {
|
||||
it('maps all fields', () => {
|
||||
const vars = buildUserTemplateVars({
|
||||
userName: 'Jason',
|
||||
pronouns: 'He/Him',
|
||||
timezone: 'America/Chicago',
|
||||
});
|
||||
expect(vars.USER_NAME).toBe('Jason');
|
||||
expect(vars.PRONOUNS).toBe('He/Him');
|
||||
expect(vars.TIMEZONE).toBe('America/Chicago');
|
||||
});
|
||||
|
||||
it('uses defaults for missing fields', () => {
|
||||
const vars = buildUserTemplateVars({});
|
||||
expect(vars.PRONOUNS).toBe('They/Them');
|
||||
expect(vars.TIMEZONE).toBe('UTC');
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildToolsTemplateVars', () => {
|
||||
it('builds git providers table', () => {
|
||||
const vars = buildToolsTemplateVars({
|
||||
gitProviders: [
|
||||
{ name: 'GitHub', url: 'https://github.com', cli: 'gh', purpose: 'OSS' },
|
||||
],
|
||||
});
|
||||
expect(vars.GIT_PROVIDERS_TABLE).toContain('| GitHub |');
|
||||
expect(vars.GIT_PROVIDERS_TABLE).toContain('`gh`');
|
||||
});
|
||||
|
||||
it('uses default table when no providers', () => {
|
||||
const vars = buildToolsTemplateVars({});
|
||||
expect(vars.GIT_PROVIDERS_TABLE).toContain('add your git providers here');
|
||||
});
|
||||
});
|
||||
52
tests/template/engine.test.ts
Normal file
52
tests/template/engine.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
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" }');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user