takt/src/__tests__/qualityGateOverrides.test.ts
nrs f838a0e656
takt: github-issue-382-feat-purojeku (#384)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-03 00:10:02 +09:00

195 lines
7.4 KiB
TypeScript

/**
* Tests for quality gate override logic
*/
import { describe, it, expect } from 'vitest';
import { applyQualityGateOverrides } from '../infra/config/loaders/qualityGateOverrides.js';
import type { PieceOverrides } from '../core/models/persisted-global-config.js';
describe('applyQualityGateOverrides', () => {
it('returns undefined when no gates are defined', () => {
const result = applyQualityGateOverrides('implement', undefined, true, undefined, undefined);
expect(result).toBeUndefined();
});
it('returns YAML gates when no overrides are defined', () => {
const yamlGates = ['Test passes'];
const result = applyQualityGateOverrides('implement', yamlGates, true, undefined, undefined);
expect(result).toEqual(['Test passes']);
});
it('returns empty array when yamlGates is empty array and no overrides', () => {
const yamlGates: string[] = [];
const result = applyQualityGateOverrides('implement', yamlGates, true, undefined, undefined);
expect(result).toEqual([]);
});
it('merges global override gates with YAML gates (additive)', () => {
const yamlGates = ['Unit tests pass'];
const globalOverrides: PieceOverrides = {
qualityGates: ['E2E tests pass'],
};
const result = applyQualityGateOverrides('implement', yamlGates, true, undefined, globalOverrides);
expect(result).toEqual(['E2E tests pass', 'Unit tests pass']);
});
it('applies movement-specific override from global config', () => {
const yamlGates = ['Unit tests pass'];
const globalOverrides: PieceOverrides = {
qualityGates: ['Global gate'],
movements: {
implement: {
qualityGates: ['Movement-specific gate'],
},
},
};
const result = applyQualityGateOverrides('implement', yamlGates, true, undefined, globalOverrides);
expect(result).toEqual(['Global gate', 'Movement-specific gate', 'Unit tests pass']);
});
it('applies project overrides with higher priority than global', () => {
const yamlGates = ['YAML gate'];
const globalOverrides: PieceOverrides = {
qualityGates: ['Global gate'],
};
const projectOverrides: PieceOverrides = {
qualityGates: ['Project gate'],
};
const result = applyQualityGateOverrides('implement', yamlGates, true, projectOverrides, globalOverrides);
expect(result).toEqual(['Global gate', 'Project gate', 'YAML gate']);
});
it('applies movement-specific override from project config', () => {
const yamlGates = ['YAML gate'];
const projectOverrides: PieceOverrides = {
movements: {
implement: {
qualityGates: ['Project movement gate'],
},
},
};
const result = applyQualityGateOverrides('implement', yamlGates, true, projectOverrides, undefined);
expect(result).toEqual(['Project movement gate', 'YAML gate']);
});
it('filters global gates when qualityGatesEditOnly=true and edit=false', () => {
const yamlGates = ['YAML gate'];
const globalOverrides: PieceOverrides = {
qualityGates: ['Global gate'],
qualityGatesEditOnly: true,
};
const result = applyQualityGateOverrides('review', yamlGates, false, undefined, globalOverrides);
expect(result).toEqual(['YAML gate']); // Global gate excluded because edit=false
});
it('includes global gates when qualityGatesEditOnly=true and edit=true', () => {
const yamlGates = ['YAML gate'];
const globalOverrides: PieceOverrides = {
qualityGates: ['Global gate'],
qualityGatesEditOnly: true,
};
const result = applyQualityGateOverrides('implement', yamlGates, true, undefined, globalOverrides);
expect(result).toEqual(['Global gate', 'YAML gate']);
});
it('filters project global gates when qualityGatesEditOnly=true and edit=false', () => {
const yamlGates = ['YAML gate'];
const projectOverrides: PieceOverrides = {
qualityGates: ['Project gate'],
qualityGatesEditOnly: true,
};
const result = applyQualityGateOverrides('review', yamlGates, false, projectOverrides, undefined);
expect(result).toEqual(['YAML gate']); // Project gate excluded because edit=false
});
it('applies movement-specific gates regardless of qualityGatesEditOnly flag', () => {
const yamlGates = ['YAML gate'];
const projectOverrides: PieceOverrides = {
qualityGates: ['Project global gate'],
qualityGatesEditOnly: true,
movements: {
review: {
qualityGates: ['Review-specific gate'],
},
},
};
const result = applyQualityGateOverrides('review', yamlGates, false, projectOverrides, undefined);
// Project global gate excluded (edit=false), but movement-specific gate included
expect(result).toEqual(['Review-specific gate', 'YAML gate']);
});
it('handles complex priority scenario with all override types', () => {
const yamlGates = ['YAML gate'];
const globalOverrides: PieceOverrides = {
qualityGates: ['Global gate'],
movements: {
implement: {
qualityGates: ['Global movement gate'],
},
},
};
const projectOverrides: PieceOverrides = {
qualityGates: ['Project gate'],
movements: {
implement: {
qualityGates: ['Project movement gate'],
},
},
};
const result = applyQualityGateOverrides('implement', yamlGates, true, projectOverrides, globalOverrides);
expect(result).toEqual([
'Global gate',
'Global movement gate',
'Project gate',
'Project movement gate',
'YAML gate',
]);
});
it('returns YAML gates only when other movements are specified in overrides', () => {
const yamlGates = ['YAML gate'];
const projectOverrides: PieceOverrides = {
movements: {
review: {
qualityGates: ['Review gate'],
},
},
};
const result = applyQualityGateOverrides('implement', yamlGates, true, projectOverrides, undefined);
expect(result).toEqual(['YAML gate']); // No override for 'implement', only for 'review'
});
describe('deduplication', () => {
it('removes duplicate gates from multiple sources', () => {
const yamlGates = ['Test 1', 'Test 2'];
const globalOverrides: PieceOverrides = {
qualityGates: ['Test 2', 'Test 3'],
};
const projectOverrides: PieceOverrides = {
qualityGates: ['Test 1', 'Test 4'],
};
const result = applyQualityGateOverrides('implement', yamlGates, true, projectOverrides, globalOverrides);
// Duplicates removed: Test 1, Test 2 appear only once
expect(result).toEqual(['Test 2', 'Test 3', 'Test 1', 'Test 4']);
});
it('removes duplicate gates from single source', () => {
const projectOverrides: PieceOverrides = {
qualityGates: ['Test 1', 'Test 2', 'Test 1', 'Test 3', 'Test 2'],
};
const result = applyQualityGateOverrides('implement', undefined, true, projectOverrides, undefined);
expect(result).toEqual(['Test 1', 'Test 2', 'Test 3']);
});
it('removes duplicate gates from YAML and overrides', () => {
const yamlGates = ['npm run test', 'npm run lint'];
const projectOverrides: PieceOverrides = {
qualityGates: ['npm run test', 'npm run build'],
};
const result = applyQualityGateOverrides('implement', yamlGates, true, projectOverrides, undefined);
// 'npm run test' appears only once
expect(result).toEqual(['npm run test', 'npm run build', 'npm run lint']);
});
});
});