mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 22:26:38 +03:00
189 lines
6.2 KiB
JavaScript
189 lines
6.2 KiB
JavaScript
import { describe, test, expect, beforeEach, afterEach, mock } from 'bun:test';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { transformCursor } from '../../../scripts/lib/transformers/cursor.js';
|
|
|
|
const TEST_DIR = path.join(process.cwd(), 'test-tmp-cursor');
|
|
|
|
describe('transformCursor', () => {
|
|
beforeEach(() => {
|
|
if (fs.existsSync(TEST_DIR)) {
|
|
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (fs.existsSync(TEST_DIR)) {
|
|
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('should create correct directory structure', () => {
|
|
const commands = [];
|
|
const skills = [];
|
|
|
|
transformCursor(commands, skills, TEST_DIR);
|
|
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands'))).toBe(true);
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/rules'))).toBe(true);
|
|
});
|
|
|
|
test('should strip frontmatter from commands and output body only', () => {
|
|
const commands = [
|
|
{
|
|
name: 'test-command',
|
|
description: 'A test command',
|
|
args: [{ name: 'target', description: 'Target', required: false }],
|
|
body: 'This is the command body content.'
|
|
}
|
|
];
|
|
const skills = [];
|
|
|
|
transformCursor(commands, skills, TEST_DIR);
|
|
|
|
const outputPath = path.join(TEST_DIR, 'cursor/commands/test-command.md');
|
|
expect(fs.existsSync(outputPath)).toBe(true);
|
|
|
|
const content = fs.readFileSync(outputPath, 'utf-8');
|
|
expect(content).toBe('This is the command body content.');
|
|
expect(content).not.toContain('---');
|
|
expect(content).not.toContain('name:');
|
|
expect(content).not.toContain('description:');
|
|
});
|
|
|
|
test('should strip frontmatter from skills and output body only', () => {
|
|
const commands = [];
|
|
const skills = [
|
|
{
|
|
name: 'test-skill',
|
|
description: 'A test skill',
|
|
license: 'MIT',
|
|
body: 'These are the skill instructions.'
|
|
}
|
|
];
|
|
|
|
transformCursor(commands, skills, TEST_DIR);
|
|
|
|
const outputPath = path.join(TEST_DIR, 'cursor/rules/test-skill.md');
|
|
expect(fs.existsSync(outputPath)).toBe(true);
|
|
|
|
const content = fs.readFileSync(outputPath, 'utf-8');
|
|
expect(content).toBe('These are the skill instructions.');
|
|
expect(content).not.toContain('---');
|
|
expect(content).not.toContain('license:');
|
|
});
|
|
|
|
test('should handle multiple commands', () => {
|
|
const commands = [
|
|
{ name: 'cmd1', description: 'Command 1', args: [], body: 'Body 1' },
|
|
{ name: 'cmd2', description: 'Command 2', args: [], body: 'Body 2' },
|
|
{ name: 'cmd3', description: 'Command 3', args: [], body: 'Body 3' }
|
|
];
|
|
const skills = [];
|
|
|
|
transformCursor(commands, skills, TEST_DIR);
|
|
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands/cmd1.md'))).toBe(true);
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands/cmd2.md'))).toBe(true);
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands/cmd3.md'))).toBe(true);
|
|
});
|
|
|
|
test('should handle multiple skills', () => {
|
|
const commands = [];
|
|
const skills = [
|
|
{ name: 'skill1', description: 'Skill 1', license: 'MIT', body: 'Skill body 1' },
|
|
{ name: 'skill2', description: 'Skill 2', license: 'Apache', body: 'Skill body 2' }
|
|
];
|
|
|
|
transformCursor(commands, skills, TEST_DIR);
|
|
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/rules/skill1.md'))).toBe(true);
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/rules/skill2.md'))).toBe(true);
|
|
});
|
|
|
|
test('should clean existing directory before writing', () => {
|
|
// Create a pre-existing file
|
|
fs.mkdirSync(path.join(TEST_DIR, 'cursor/commands'), { recursive: true });
|
|
fs.writeFileSync(path.join(TEST_DIR, 'cursor/commands/old-file.md'), 'old content');
|
|
|
|
const commands = [
|
|
{ name: 'new-cmd', description: 'New', args: [], body: 'New body' }
|
|
];
|
|
|
|
transformCursor(commands, [], TEST_DIR);
|
|
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands/old-file.md'))).toBe(false);
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands/new-cmd.md'))).toBe(true);
|
|
});
|
|
|
|
test('should handle commands with placeholder args in body', () => {
|
|
const commands = [
|
|
{
|
|
name: 'normalize',
|
|
description: 'Normalize design',
|
|
args: [{ name: 'target', description: 'Target', required: false }],
|
|
body: 'Please normalize {{target}} to match the design system.'
|
|
}
|
|
];
|
|
|
|
transformCursor(commands, [], TEST_DIR);
|
|
|
|
const content = fs.readFileSync(path.join(TEST_DIR, 'cursor/commands/normalize.md'), 'utf-8');
|
|
// Cursor transformer should preserve the body as-is
|
|
expect(content).toBe('Please normalize {{target}} to match the design system.');
|
|
});
|
|
|
|
test('should log correct summary', () => {
|
|
const consoleMock = mock(() => {});
|
|
const originalLog = console.log;
|
|
console.log = consoleMock;
|
|
|
|
const commands = [{ name: 'cmd1', description: '', args: [], body: 'body1' }];
|
|
const skills = [{ name: 'skill1', description: '', license: '', body: 'body1' }];
|
|
|
|
transformCursor(commands, skills, TEST_DIR);
|
|
|
|
console.log = originalLog;
|
|
|
|
expect(consoleMock).toHaveBeenCalledWith('✓ Cursor: 1 commands, 1 skills (downgraded)');
|
|
});
|
|
|
|
test('should handle empty commands and skills arrays', () => {
|
|
transformCursor([], [], TEST_DIR);
|
|
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/commands'))).toBe(true);
|
|
expect(fs.existsSync(path.join(TEST_DIR, 'cursor/rules'))).toBe(true);
|
|
|
|
const commandFiles = fs.readdirSync(path.join(TEST_DIR, 'cursor/commands'));
|
|
const ruleFiles = fs.readdirSync(path.join(TEST_DIR, 'cursor/rules'));
|
|
|
|
expect(commandFiles).toHaveLength(0);
|
|
expect(ruleFiles).toHaveLength(0);
|
|
});
|
|
|
|
test('should preserve line breaks and formatting in body', () => {
|
|
const commands = [
|
|
{
|
|
name: 'formatted',
|
|
description: 'Test',
|
|
args: [],
|
|
body: `Line 1
|
|
|
|
Line 3 after blank line
|
|
|
|
- Bullet 1
|
|
- Bullet 2
|
|
|
|
End.`
|
|
}
|
|
];
|
|
|
|
transformCursor(commands, [], TEST_DIR);
|
|
|
|
const content = fs.readFileSync(path.join(TEST_DIR, 'cursor/commands/formatted.md'), 'utf-8');
|
|
expect(content).toContain('Line 1\n\nLine 3');
|
|
expect(content).toContain('- Bullet 1\n- Bullet 2');
|
|
});
|
|
});
|
|
|