import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { writeFileSync, mkdirSync, rmSync } from 'fs'; import { resolve } from 'path'; import { runCheck } from '../src/index'; const TMP = resolve(__dirname, 'tmp-integration'); function clean() { try { rmSync(TMP, { recursive: true, force: true }); } catch {} } vi.mock('../src/git', () => ({ getChangedFiles: vi.fn(), getCommitMessage: vi.fn(), getPrDescription: vi.fn(), })); import * as gitModule from '../src/git'; describe('integration', () => { beforeEach(() => { clean(); mkdirSync(TMP, { recursive: true }); vi.resetAllMocks(); }); afterEach(() => { clean(); }); it('passes with no config and no changed files', async () => { vi.mocked(gitModule.getChangedFiles).mockReturnValue([]); vi.mocked(gitModule.getCommitMessage).mockReturnValue('feat: #123'); writeFileSync(resolve(TMP, 'REQUIREMENTS.md'), '- [x] Done\n'); const result = await runCheck({ cwd: TMP }); expect(result.passed).toBe(true); }); it('fails when disclosure is missing', async () => { vi.mocked(gitModule.getChangedFiles).mockReturnValue([resolve(TMP, 'bad.ts')]); vi.mocked(gitModule.getCommitMessage).mockReturnValue('feat: #123'); writeFileSync(resolve(TMP, 'bad.ts'), 'no marker'); writeFileSync(resolve(TMP, 'REQUIREMENTS.md'), '- [x] Done\n'); const result = await runCheck({ cwd: TMP }); expect(result.passed).toBe(false); const disclosure = result.gateResults.find(g => g.name === 'disclosure'); expect(disclosure?.passed).toBe(false); }); it('fails when rfc is missing', async () => { vi.mocked(gitModule.getChangedFiles).mockReturnValue([]); vi.mocked(gitModule.getCommitMessage).mockReturnValue('just a commit'); writeFileSync(resolve(TMP, 'REQUIREMENTS.md'), '- [x] Done\n'); const result = await runCheck({ cwd: TMP }); expect(result.passed).toBe(false); const rfc = result.gateResults.find(g => g.name === 'rfc'); expect(rfc?.passed).toBe(false); }); it('fails when checklist is incomplete', async () => { vi.mocked(gitModule.getChangedFiles).mockReturnValue([]); vi.mocked(gitModule.getCommitMessage).mockReturnValue('feat: #123'); writeFileSync(resolve(TMP, 'REQUIREMENTS.md'), '- [ ] Not done\n'); const result = await runCheck({ cwd: TMP }); expect(result.passed).toBe(false); const checklist = result.gateResults.find(g => g.name === 'checklist'); expect(checklist?.passed).toBe(false); }); it('skips quality gate when not required', async () => { vi.mocked(gitModule.getChangedFiles).mockReturnValue([]); vi.mocked(gitModule.getCommitMessage).mockReturnValue('feat: #123'); writeFileSync(resolve(TMP, 'REQUIREMENTS.md'), '- [x] Done\n'); const result = await runCheck({ cwd: TMP }); const quality = result.gateResults.find(g => g.name === 'quality'); expect(quality).toBeUndefined(); expect(result.passed).toBe(true); }); it('honors disabled gates via config', async () => { writeFileSync(resolve(TMP, '.codegov.json'), JSON.stringify({ enabled: true, gates: { disclosure: { required: false }, rfc: { required: false }, checklist: { required: false }, }, })); vi.mocked(gitModule.getChangedFiles).mockReturnValue([]); const result = await runCheck({ cwd: TMP }); expect(result.passed).toBe(true); expect(result.gateResults.length).toBe(0); }); });