Files
Codeman/test/templates.test.ts
T
arkonandClaude Fable 5 beeec63f72 fix(terminal): linear-time link-provider regex; always allow blob workers in CSP
cmdPattern's empty-matchable unbounded arg group backtracked exponentially
on wrapped heredoc/table lines — hovering one froze the tab for minutes.
Non-empty tokens + bounded reps make it O(n); regression test extracts the
shipped patterns and pins timing on the real killer shapes.

worker-src 'self' blob: is now unconditional so terminal-ui's _safeYield
tick worker (throttling escape) isn't CSP-blocked on non-gesture installs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 18:06:45 +02:00

161 lines
5.1 KiB
TypeScript

/**
* @fileoverview Tests for template generation functions
*
* Tests the CLAUDE.md template generation including
* default template and custom template loading.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { existsSync, writeFileSync, unlinkSync, mkdirSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { generateClaudeMd } from '../src/templates/claude-md.js';
describe('generateClaudeMd', () => {
const testDir = join(tmpdir(), 'codeman-template-test-' + Date.now());
beforeEach(() => {
if (!existsSync(testDir)) {
mkdirSync(testDir, { recursive: true });
}
});
afterEach(() => {
try {
rmSync(testDir, { recursive: true, force: true });
} catch (e) {
// Ignore cleanup errors
}
});
describe('default template', () => {
it('should generate template with case name', () => {
const result = generateClaudeMd('my-project');
expect(result).toContain('**Project Name**: my-project');
});
it('should generate template with description', () => {
const result = generateClaudeMd('my-project', 'A test project description');
expect(result).toContain('**Description**: A test project description');
});
it('should use default description when not provided', () => {
const result = generateClaudeMd('my-project');
expect(result).toContain('**Description**: A new project');
});
it('should include current date', () => {
const today = new Date().toISOString().split('T')[0];
const result = generateClaudeMd('my-project');
expect(result).toContain(`Generated by Codeman on ${today}`);
});
it('should include Codeman environment section', () => {
const result = generateClaudeMd('my-project');
expect(result).toContain('## Codeman Environment');
expect(result).toContain('CODEMAN_MUX=1');
});
it('should include workflow rules', () => {
const result = generateClaudeMd('my-project');
expect(result).toContain('## Workflow');
expect(result).toContain('conventional commits');
});
it('should stay under the 200-line CLAUDE.md guidance', () => {
const result = generateClaudeMd('my-project');
expect(result.split('\n').length).toBeLessThan(200);
});
it('should not include legacy bloat sections', () => {
const result = generateClaudeMd('my-project');
expect(result).not.toContain('## Session Log');
expect(result).not.toContain('TodoWrite');
expect(result).not.toContain('## Planning Mode');
expect(result).not.toContain('[TECHNOLOGIES_USED]');
// Ralph loop instructions live in the loop prompt (wizard) and plugin,
// not in every project's CLAUDE.md
expect(result).not.toContain('RALPH_STATUS');
expect(result).not.toContain('/ralph-loop:');
});
});
describe('custom template', () => {
it('should use custom template when provided and exists', () => {
const templatePath = join(testDir, 'custom-template.md');
writeFileSync(
templatePath,
`
# [PROJECT_NAME]
Description: [PROJECT_DESCRIPTION]
Date: [DATE]
Custom content here.
`
);
const result = generateClaudeMd('my-project', 'Test desc', templatePath);
expect(result).toContain('# my-project');
expect(result).toContain('Description: Test desc');
expect(result).toContain('Custom content here.');
});
it('should replace all placeholder occurrences', () => {
const templatePath = join(testDir, 'multi-placeholder.md');
writeFileSync(
templatePath,
`
[PROJECT_NAME] is a project.
The name is [PROJECT_NAME].
About [PROJECT_NAME]: [PROJECT_DESCRIPTION]
`
);
const result = generateClaudeMd('awesome-app', 'Cool stuff', templatePath);
expect(result).toContain('awesome-app is a project.');
expect(result).toContain('The name is awesome-app.');
expect(result).toContain('About awesome-app: Cool stuff');
});
it('should use default description in template when not provided', () => {
const templatePath = join(testDir, 'desc-template.md');
writeFileSync(templatePath, 'Description: [PROJECT_DESCRIPTION]');
const result = generateClaudeMd('my-project', '', templatePath);
expect(result).toContain('Description: A new project');
});
it('should fall back to default template if custom file does not exist', () => {
const result = generateClaudeMd('my-project', 'desc', '/nonexistent/template.md');
// Should get default template content
expect(result).toContain('## Codeman Environment');
expect(result).toContain('**Project Name**: my-project');
});
it('should fall back to default template if custom path is empty', () => {
const result = generateClaudeMd('my-project', 'desc', '');
expect(result).toContain('## Codeman Environment');
});
it('should fall back to default template if custom path is undefined', () => {
const result = generateClaudeMd('my-project', 'desc', undefined);
expect(result).toContain('## Codeman Environment');
});
});
});