Files
claude-task-master/tests/unit/profiles/rule-transformer-kiro.test.js
Ralph Khreish 75a36ea99a feat: add kiro profile (#1001)
* feat: add kiro profile

* chore: fix format

* chore: implement requested changes

* chore: fix CI
2025-07-18 00:02:30 +02:00

216 lines
6.4 KiB
JavaScript

import { jest } from '@jest/globals';
// Mock fs module before importing anything that uses it
jest.mock('fs', () => ({
readFileSync: jest.fn(),
writeFileSync: jest.fn(),
existsSync: jest.fn(),
mkdirSync: jest.fn()
}));
// Import modules after mocking
import fs from 'fs';
import { convertRuleToProfileRule } from '../../../src/utils/rule-transformer.js';
import { kiroProfile } from '../../../src/profiles/kiro.js';
describe('Kiro Rule Transformer', () => {
// Set up spies on the mocked modules
const mockReadFileSync = jest.spyOn(fs, 'readFileSync');
const mockWriteFileSync = jest.spyOn(fs, 'writeFileSync');
const mockExistsSync = jest.spyOn(fs, 'existsSync');
const mockMkdirSync = jest.spyOn(fs, 'mkdirSync');
const mockConsoleError = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
beforeEach(() => {
jest.clearAllMocks();
// Setup default mocks
mockReadFileSync.mockReturnValue('');
mockWriteFileSync.mockImplementation(() => {});
mockExistsSync.mockReturnValue(true);
mockMkdirSync.mockImplementation(() => {});
});
afterAll(() => {
jest.restoreAllMocks();
});
it('should correctly convert basic terms', () => {
const testContent = `---
description: Test Cursor rule for basic terms
globs: **/*
alwaysApply: true
---
This is a Cursor rule that references cursor.so and uses the word Cursor multiple times.
Also has references to .mdc files.`;
// Mock file read to return our test content
mockReadFileSync.mockReturnValue(testContent);
// Mock file system operations
mockExistsSync.mockReturnValue(true);
// Call the function
const result = convertRuleToProfileRule(
'test-source.mdc',
'test-target.md',
kiroProfile
);
// Verify the result
expect(result).toBe(true);
expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
// Get the transformed content
const transformedContent = mockWriteFileSync.mock.calls[0][1];
// Verify Cursor -> Kiro transformations
expect(transformedContent).toContain('kiro.dev');
expect(transformedContent).toContain('Kiro');
expect(transformedContent).not.toContain('cursor.so');
expect(transformedContent).not.toContain('Cursor');
expect(transformedContent).toContain('.md');
expect(transformedContent).not.toContain('.mdc');
});
it('should handle URL transformations', () => {
const testContent = `Visit https://cursor.so/docs for more information.
Also check out cursor.so and www.cursor.so for updates.`;
mockReadFileSync.mockReturnValue(testContent);
mockExistsSync.mockReturnValue(true);
const result = convertRuleToProfileRule(
'test-source.mdc',
'test-target.md',
kiroProfile
);
expect(result).toBe(true);
const transformedContent = mockWriteFileSync.mock.calls[0][1];
// Verify URL transformations
expect(transformedContent).toContain('https://kiro.dev');
expect(transformedContent).toContain('kiro.dev');
expect(transformedContent).not.toContain('cursor.so');
});
it('should handle file extension transformations', () => {
const testContent = `This rule references file.mdc and another.mdc file.
Use the .mdc extension for all rule files.`;
mockReadFileSync.mockReturnValue(testContent);
mockExistsSync.mockReturnValue(true);
const result = convertRuleToProfileRule(
'test-source.mdc',
'test-target.md',
kiroProfile
);
expect(result).toBe(true);
const transformedContent = mockWriteFileSync.mock.calls[0][1];
// Verify file extension transformations
expect(transformedContent).toContain('file.md');
expect(transformedContent).toContain('another.md');
expect(transformedContent).toContain('.md extension');
expect(transformedContent).not.toContain('.mdc');
});
it('should handle case variations', () => {
const testContent = `CURSOR, Cursor, cursor should all be transformed.`;
mockReadFileSync.mockReturnValue(testContent);
mockExistsSync.mockReturnValue(true);
const result = convertRuleToProfileRule(
'test-source.mdc',
'test-target.md',
kiroProfile
);
expect(result).toBe(true);
const transformedContent = mockWriteFileSync.mock.calls[0][1];
// Verify case transformations
// Due to regex order, the case-insensitive rule runs first:
// CURSOR -> Kiro (because it starts with 'C'), Cursor -> Kiro, cursor -> kiro
expect(transformedContent).toContain('Kiro');
expect(transformedContent).toContain('kiro');
expect(transformedContent).not.toContain('CURSOR');
expect(transformedContent).not.toContain('Cursor');
expect(transformedContent).not.toContain('cursor');
});
it('should create target directory if it does not exist', () => {
const testContent = 'Test content';
mockReadFileSync.mockReturnValue(testContent);
mockExistsSync.mockReturnValue(false);
const result = convertRuleToProfileRule(
'test-source.mdc',
'nested/path/test-target.md',
kiroProfile
);
expect(result).toBe(true);
expect(mockMkdirSync).toHaveBeenCalledWith('nested/path', {
recursive: true
});
});
it('should handle file system errors gracefully', () => {
mockReadFileSync.mockImplementation(() => {
throw new Error('File not found');
});
const result = convertRuleToProfileRule(
'test-source.mdc',
'test-target.md',
kiroProfile
);
expect(result).toBe(false);
expect(mockConsoleError).toHaveBeenCalledWith(
'Error converting rule file: File not found'
);
});
it('should handle write errors gracefully', () => {
mockReadFileSync.mockReturnValue('Test content');
mockWriteFileSync.mockImplementation(() => {
throw new Error('Write permission denied');
});
const result = convertRuleToProfileRule(
'test-source.mdc',
'test-target.md',
kiroProfile
);
expect(result).toBe(false);
expect(mockConsoleError).toHaveBeenCalledWith(
'Error converting rule file: Write permission denied'
);
});
it('should verify profile configuration', () => {
expect(kiroProfile.profileName).toBe('kiro');
expect(kiroProfile.displayName).toBe('Kiro');
expect(kiroProfile.profileDir).toBe('.kiro');
expect(kiroProfile.mcpConfig).toBe(true);
expect(kiroProfile.mcpConfigName).toBe('settings/mcp.json');
expect(kiroProfile.mcpConfigPath).toBe('.kiro/settings/mcp.json');
expect(kiroProfile.includeDefaultRules).toBe(true);
expect(kiroProfile.fileMap).toEqual({
'rules/cursor_rules.mdc': 'kiro_rules.md',
'rules/dev_workflow.mdc': 'dev_workflow.md',
'rules/self_improve.mdc': 'self_improve.md',
'rules/taskmaster.mdc': 'taskmaster.md'
});
});
});