import { promises as fsp } from 'node:fs'; import path from 'node:path'; import os from 'node:os'; import { expect } from '../../../test-utils'; import { writeSkillFiles } from '../write-skill-files'; import { SkillFilesResponse } from '../fetch-skill-files'; describe('writeSkillFiles', function () { let tmpDir: string; beforeEach(async function () { tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'skill-files-test-')); }); afterEach(async function () { await fsp.rm(tmpDir, { recursive: true, force: true }); }); const skillFiles: SkillFilesResponse = { overview: '# Overview\n\nTask map content here.\n', skills: [ { domain: 'schema-form', filename: 'overview-and-rules.mdc', content: '---\ndescription: Schema form overview\n---\n' }, { domain: 'claim-blocks', filename: 'inputs-and-selections.mdc', content: '---\ndescription: Claim block inputs\n---\n' }, ], }; it('should create .cursor/rules/ directory and write skill files with domain--filename convention', async function () { await writeSkillFiles({ directory: tmpDir, skillFiles, productModuleName: 'Test Module' }); const rulesDir = path.join(tmpDir, '.cursor', 'rules'); const files = await fsp.readdir(rulesDir); expect(files).to.include('schema-form--overview-and-rules.mdc'); expect(files).to.include('claim-blocks--inputs-and-selections.mdc'); }); it('should write skill file contents correctly', async function () { await writeSkillFiles({ directory: tmpDir, skillFiles, productModuleName: 'Test Module' }); const content = await fsp.readFile( path.join(tmpDir, '.cursor', 'rules', 'schema-form--overview-and-rules.mdc'), 'utf-8', ); expect(content).to.include('Schema form overview'); }); it('should write docs/overview.md from the overview field', async function () { await writeSkillFiles({ directory: tmpDir, skillFiles, productModuleName: 'Test Module' }); const overviewContent = await fsp.readFile(path.join(tmpDir, 'docs', 'overview.md'), 'utf-8'); expect(overviewContent).to.include('Task map content here'); }); it('should write CLAUDE.md with the product module name', async function () { await writeSkillFiles({ directory: tmpDir, skillFiles, productModuleName: 'My Funeral Product' }); const claudeMd = await fsp.readFile(path.join(tmpDir, 'CLAUDE.md'), 'utf-8'); expect(claudeMd).to.include('# My Funeral Product - AI Agent Instructions'); }); it('should skip overview.md when overview is empty', async function () { const noOverview: SkillFilesResponse = { overview: '', skills: skillFiles.skills }; await writeSkillFiles({ directory: tmpDir, skillFiles: noOverview, productModuleName: 'Test Module' }); const docsFiles = await fsp.readdir(path.join(tmpDir, 'docs')); expect(docsFiles).to.not.include('overview.md'); }); it('should still write CLAUDE.md and rules when overview is missing', async function () { const noOverview: SkillFilesResponse = { overview: '', skills: skillFiles.skills }; await writeSkillFiles({ directory: tmpDir, skillFiles: noOverview, productModuleName: 'Test Module' }); const claudeExists = await fsp.stat(path.join(tmpDir, 'CLAUDE.md')).then(() => true).catch(() => false); expect(claudeExists).to.equal(true); const rulesFiles = await fsp.readdir(path.join(tmpDir, '.cursor', 'rules')); expect(rulesFiles).to.have.length(2); }); it('should create directories recursively even when parent does not exist', async function () { const nestedDir = path.join(tmpDir, 'nested', 'product-module'); await fsp.mkdir(path.join(tmpDir, 'nested'), { recursive: true }); await writeSkillFiles({ directory: nestedDir, skillFiles, productModuleName: 'Test Module' }); const rulesFiles = await fsp.readdir(path.join(nestedDir, '.cursor', 'rules')); expect(rulesFiles).to.have.length(2); }); });