agent-rules-kit
Version:
CLI tool to bootstrap AI agent rules for multiple IDEs and frameworks. Generates optimized rules for Cursor, VS Code, Claude, and 6+ other AI coding assistants.
145 lines (115 loc) • 5.41 kB
JavaScript
import path from 'path';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { FileService } from '../../cli/services/file-service.js';
// Mock fs-extra
vi.mock('fs-extra', () => {
return {
default: {
readFileSync: vi.fn(),
copyFileSync: vi.fn(),
outputFileSync: vi.fn(),
existsSync: vi.fn(),
readdirSync: vi.fn()
},
readFileSync: vi.fn(),
copyFileSync: vi.fn(),
outputFileSync: vi.fn(),
existsSync: vi.fn(),
readdirSync: vi.fn()
};
});
// Import fs after mocking
import fs from 'fs-extra';
describe('File Helpers', () => {
let fileService;
beforeEach(() => {
vi.resetAllMocks();
fileService = new FileService({ debug: true });
// Mock los métodos base que no queremos probar directamente
fileService.readFile = vi.fn((path) => fs.readFileSync(path));
fileService.writeFile = vi.fn((path, content) => fs.outputFileSync(path, content));
fileService.directoryExists = vi.fn((path) => fs.existsSync(path));
fileService.getFilesInDirectory = vi.fn((path) => fs.readdirSync(path));
});
describe('addFrontMatter', () => {
it('should add front matter to markdown content', () => {
const body = '# Test Markdown';
const meta = { title: 'Test Title', stack: 'laravel', detectedVersion: '10' };
const result = fileService.addFrontMatter(body, meta);
expect(result).toContain('---');
expect(result).toContain('title: Test Title');
expect(result).toContain('stack: laravel');
expect(result).toContain('detectedVersion: 10');
expect(result).toContain('# Test Markdown');
});
});
describe('processTemplateVariables', () => {
it('should replace all template variables in content', () => {
const content = '# Project using {stack} {detectedVersion} in {projectPath} with {versionRange}';
const meta = {
stack: 'laravel',
detectedVersion: '10',
versionRange: 'v10-11',
projectPath: '/path/to/project'
};
const result = fileService.processTemplateVariables(content, meta);
expect(result).toBe('# Project using laravel 10 in /path/to/project with v10-11');
});
it('should handle missing variables gracefully', () => {
const content = 'Using {stack} version {detectedVersion}';
const meta = { stack: 'nextjs' };
const result = fileService.processTemplateVariables(content, meta);
expect(result).toBe('Using nextjs version {detectedVersion}');
});
it('should return original content when no meta provided', () => {
const content = 'Original content with {placeholders}';
const result = fileService.processTemplateVariables(content);
expect(result).toBe(content);
});
});
describe('wrapMdToMdc', () => {
it('should process template variables and add front matter', () => {
const sourceContent = '# Project using {detectedVersion} in {projectPath}';
const meta = {
detectedVersion: '10',
versionRange: 'v10-11',
projectPath: '/path/to/project'
};
fs.readFileSync.mockReturnValue(sourceContent);
fileService.wrapMdToMdc('source.md', 'dest.mdc', meta);
const expectedContent = `---\ndetectedVersion: 10\nversionRange: v10-11\nprojectPath: /path/to/project\n---\n# Project using 10 in /path/to/project`;
expect(fs.outputFileSync).toHaveBeenCalledWith('dest.mdc', expectedContent);
});
});
describe('copyRuleGroup', () => {
it('should copy files to docs directory with processed variables', () => {
fs.existsSync.mockReturnValue(true);
fs.readdirSync.mockReturnValue(['file1.md', 'file2.md']);
fs.readFileSync.mockReturnValue('# Doc for {stack}');
const meta = { stack: 'nextjs' };
fileService.copyRuleGroup('source/dir', 'docs/target/dir', meta);
expect(fs.outputFileSync).toHaveBeenCalledTimes(2);
expect(fs.outputFileSync).toHaveBeenCalledWith(
path.join('docs/target/dir', 'file1.md'),
'# Doc for nextjs'
);
});
it('should not copy anything if source directory does not exist', () => {
fs.existsSync.mockReturnValue(false);
fileService.copyRuleGroup('nonexistent/dir', 'target/dir');
expect(fs.readdirSync).not.toHaveBeenCalled();
expect(fs.outputFileSync).not.toHaveBeenCalled();
});
it('should convert to .mdc for non-docs directories', () => {
fs.existsSync.mockReturnValue(true);
fs.readdirSync.mockReturnValue(['file1.md']);
fs.readFileSync.mockReturnValue('# Test content');
fileService.copyRuleGroup('source/dir', 'rules/dir');
expect(fs.outputFileSync).toHaveBeenCalledTimes(1);
expect(fs.outputFileSync).toHaveBeenCalledWith(
path.join('rules/dir', 'file1.mdc'),
expect.any(String)
);
});
});
});