From dd6973e48f22ada2c5b3e2f6f3c055dc26d855d7 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 1 Feb 2026 01:04:42 +0000 Subject: [PATCH] Add test suite for CLI, analyzers, and generators --- .../tests/cli.test.ts | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 app/ai-context-generator-cli/tests/cli.test.ts diff --git a/app/ai-context-generator-cli/tests/cli.test.ts b/app/ai-context-generator-cli/tests/cli.test.ts new file mode 100644 index 0000000..4af8029 --- /dev/null +++ b/app/ai-context-generator-cli/tests/cli.test.ts @@ -0,0 +1,181 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { execSync } from 'child_process'; + +describe('CLI', () => { + let testDir: string; + const projectPath = path.join(__dirname, '..'); + const cliPath = path.join(projectPath, 'dist', 'index.js'); + + beforeAll(async () => { + if (!fs.existsSync(cliPath)) { + throw new Error('CLI not built. Run npm run build first.'); + } + }); + + beforeEach(async () => { + testDir = path.join(__dirname, 'test-projects', `test-${Date.now()}`); + await fs.promises.mkdir(testDir, { recursive: true }); + }); + + afterEach(async () => { + if (await fs.promises.stat(testDir).catch(() => null)) { + await fs.promises.rm(testDir, { recursive: true }); + } + }); + + describe('--version', () => { + it('should display version information', () => { + const output = execSync(`node ${cliPath} --version`, { encoding: 'utf-8' }); + expect(output).toContain('1.0.0'); + }); + }); + + describe('--help', () => { + it('should display help information', () => { + const output = execSync(`node ${cliPath} --help`, { encoding: 'utf-8' }); + expect(output).toContain('Usage:'); + expect(output).toContain('Options:'); + }); + }); + + describe('--dir option', () => { + it('should analyze specified directory', async () => { + await fs.promises.writeFile( + path.join(testDir, 'tsconfig.json'), + JSON.stringify({}) + ); + await fs.promises.writeFile( + path.join(testDir, 'index.ts'), + 'const x = 1;' + ); + + const outputPath = path.join(testDir, 'output.json'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --no-conventions`, + { encoding: 'utf-8' } + ); + + expect(fs.existsSync(outputPath)).toBe(true); + const content = fs.readFileSync(outputPath, 'utf-8'); + expect(() => JSON.parse(content)).not.toThrow(); + }); + }); + + describe('--output option', () => { + it('should save to specified file path', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const customPath = path.join(testDir, 'custom-context'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${customPath}" --format json --no-conventions`, + { encoding: 'utf-8' } + ); + + expect(fs.existsSync(`${customPath}.json`)).toBe(true); + }); + }); + + describe('--format option', () => { + it('should generate JSON output', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const outputPath = path.join(testDir, 'output'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --format json --no-conventions`, + { encoding: 'utf-8' } + ); + + const content = fs.readFileSync(`${outputPath}.json`, 'utf-8'); + expect(() => JSON.parse(content)).not.toThrow(); + }); + + it('should generate YAML output', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const outputPath = path.join(testDir, 'output'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --format yaml --no-conventions`, + { encoding: 'utf-8' } + ); + + const content = fs.readFileSync(`${outputPath}.yaml`, 'utf-8'); + expect(content).toContain('projectInfo:'); + }); + }); + + describe('--template option', () => { + it('should accept default template', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const outputPath = path.join(testDir, 'output'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --template default --no-conventions`, + { encoding: 'utf-8' } + ); + + expect(fs.existsSync(`${outputPath}.json`)).toBe(true); + }); + + it('should accept cursor template', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const outputPath = path.join(testDir, 'output'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --template cursor --no-conventions`, + { encoding: 'utf-8' } + ); + + expect(fs.existsSync(`${outputPath}.json`)).toBe(true); + }); + + it('should accept copilot template', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const outputPath = path.join(testDir, 'output'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --template copilot --no-conventions`, + { encoding: 'utf-8' } + ); + + expect(fs.existsSync(`${outputPath}.json`)).toBe(true); + }); + }); + + describe('--no-conventions option', () => { + it('should skip convention analysis', async () => { + await fs.promises.writeFile(path.join(testDir, 'tsconfig.json'), '{}'); + + const outputPath = path.join(testDir, 'output'); + execSync( + `node ${cliPath} --dir "${testDir}" --output "${outputPath}" --no-conventions`, + { encoding: 'utf-8' } + ); + + const content = fs.readFileSync(`${outputPath}.json`, 'utf-8'); + const parsed = JSON.parse(content); + expect(parsed.projectInfo.conventions).toBeNull(); + }); + }); + + describe('--verbose option', () => { + it('should output verbose information', () => { + const output = execSync( + `node ${cliPath} --dir . --output /dev/null --format json --verbose --no-conventions 2>&1 || true`, + { encoding: 'utf-8' } + ); + expect(output).toContain('Analyzing directory'); + }); + }); + + describe('error handling', () => { + it('should handle non-existent directory', () => { + expect(() => { + execSync( + `node ${cliPath} --dir "/non/existent/path" --output /dev/null --no-conventions`, + { encoding: 'utf-8' } + ); + }).toThrow(); + }); + }); +});