Files
ftb-project-management/apps/web/lib/ai-decompose-dedupe.test.ts
2026-07-02 18:01:38 +08:00

186 lines
5.5 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { filterDuplicateDecomposeDrafts } from './ai-decompose-dedupe';
import type { AgentDecomposeResult } from '@ftb/shared';
import type { DevTask } from './dev-task';
import type { TestCase } from './test-case';
import type { TaskCategory } from './task-category';
const categories: TaskCategory[] = [
{
id: 'cat-frontend',
code: 'frontend_interaction',
name: '前端交互',
group: 'development',
sortOrder: 1,
isSystem: true,
},
{
id: 'cat-test-functional',
code: 'test_functional',
name: '功能测试',
group: 'testing',
sortOrder: 2,
isSystem: true,
},
];
const requirements = [{ id: 'req-1', code: 'REQ001' }];
function makeResult(patch: Partial<AgentDecomposeResult>): AgentDecomposeResult {
return {
report: { matched: [], reqOnly: [], prototypeOnly: [], ambiguous: [] },
devTaskDrafts: [],
testCaseDrafts: [],
...patch,
};
}
test('filters dev task drafts already adopted into existing tasks', () => {
const existingDevTasks = [
{
id: 'task-1',
title: '实现拖拽排序',
categoryId: 'cat-frontend',
references: [
{ type: 'requirement', id: 'req-1', label: 'REQ001 拖拽排序' },
{ type: 'prototype_note', id: 'QY0001', label: 'QY0001' },
],
},
] as DevTask[];
const result = filterDuplicateDecomposeDrafts(
makeResult({
devTaskDrafts: [
{
title: '实现拖拽排序',
description: '实现范围:支持列表拖拽调整顺序。验收点:拖拽后顺序保持一致。',
taskTypeName: '前端交互',
categoryCode: 'frontend_interaction',
priority: 'P2',
aiEstimateHours: 0.25,
references: [
{ type: 'requirement', id: 'REQ001', label: 'REQ001 拖拽排序' },
{ type: 'prototype_note', id: 'QY0001', label: 'QY0001' },
],
},
],
}),
{ existingDevTasks, existingTestCases: [], categories, requirements },
);
assert.equal(result.removedDevTaskCount, 1);
assert.equal(result.result.devTaskDrafts.length, 0);
});
test('filters test case drafts already adopted into existing test cases', () => {
const existingTestCases = [
{
id: 'tc-1',
title: '验证拖拽排序成功',
categoryId: 'cat-test-functional',
references: [
{ type: 'requirement', id: 'req-1', label: 'REQ001 拖拽排序' },
{ type: 'prototype_note', id: 'QY0001', label: 'QY0001' },
],
},
] as TestCase[];
const result = filterDuplicateDecomposeDrafts(
makeResult({
testCaseDrafts: [
{
title: '验证拖拽排序成功',
description: '拖拽后顺序保存',
taskTypeName: '功能测试',
categoryCode: 'test_functional',
priority: 'P2',
aiEstimateHours: 0.2,
references: [
{ type: 'requirement', id: 'REQ001', label: 'REQ001 拖拽排序' },
{ type: 'prototype_note', id: 'QY0001', label: 'QY0001' },
],
},
],
}),
{ existingDevTasks: [], existingTestCases, categories, requirements },
);
assert.equal(result.removedTestCaseCount, 1);
assert.equal(result.result.testCaseDrafts.length, 0);
});
test('keeps drafts with same references but different normalized title', () => {
const existingDevTasks = [
{
id: 'task-1',
title: '实现拖拽排序',
categoryId: 'cat-frontend',
references: [{ type: 'prototype_note', id: 'QY0001', label: 'QY0001' }],
},
] as DevTask[];
const result = filterDuplicateDecomposeDrafts(
makeResult({
devTaskDrafts: [
{
title: '保存拖拽排序结果',
description: '实现范围:保存拖拽后的排序结果。验收点:刷新后顺序不丢失。',
taskTypeName: '前端交互',
categoryCode: 'frontend_interaction',
priority: 'P2',
aiEstimateHours: 0.5,
references: [{ type: 'prototype_note', id: 'QY0001', label: 'QY0001' }],
},
],
}),
{ existingDevTasks, existingTestCases: [], categories, requirements },
);
assert.equal(result.removedDevTaskCount, 0);
assert.equal(result.result.devTaskDrafts.length, 1);
});
test('filters adopted drafts by AI task type name even when categoryCode is unknown', () => {
const customCategories: TaskCategory[] = [
...categories,
{
id: 'cat-ai-name-card',
code: '人员名片交互',
name: '人员名片交互',
group: 'development',
sortOrder: 3,
isSystem: false,
},
];
const existingDevTasks = [
{
id: 'task-1',
title: '实现同名员工名片入口',
categoryId: 'cat-ai-name-card',
references: [{ type: 'prototype_note', id: 'QY0019', label: 'QY0019' }],
},
] as DevTask[];
const result = filterDuplicateDecomposeDrafts(
makeResult({
devTaskDrafts: [
{
title: '实现同名员工名片入口',
description: '实现范围:姓名后展示名片入口。验收点:点击后展示组织详情。',
taskTypeName: '人员名片交互',
categoryCode: 'ai_unknown',
priority: 'P2',
aiEstimateHours: 0.5,
references: [{ type: 'prototype_note', id: 'QY0019', label: 'QY0019' }],
},
],
}),
{ existingDevTasks, existingTestCases: [], categories: customCategories, requirements },
);
assert.equal(result.removedDevTaskCount, 1);
assert.equal(result.result.devTaskDrafts.length, 0);
});