feat(平台): 补齐服务端持久化和AI拆解契约
This commit is contained in:
49
apps/web/lib/requirement-selector.test.ts
Normal file
49
apps/web/lib/requirement-selector.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { getProjectAdoptedRequirementCandidates, mergeSelectedRequirementOptions } from './requirement-selector';
|
||||
import type { Requirement } from './requirement';
|
||||
|
||||
const base = {
|
||||
description: '',
|
||||
productId: 'product-1',
|
||||
sourceType: 'internal',
|
||||
sourceTarget: '',
|
||||
platforms: [] as string[],
|
||||
typeId: '',
|
||||
priority: 'P2',
|
||||
effort: 'M',
|
||||
creator: 'tester',
|
||||
createdAt: '2026-06-25',
|
||||
};
|
||||
|
||||
function req(id: string, projectId: string, status: Requirement['status']): Requirement {
|
||||
return {
|
||||
...base,
|
||||
id,
|
||||
code: id.toUpperCase(),
|
||||
title: `Requirement ${id}`,
|
||||
projectId,
|
||||
status,
|
||||
} as Requirement;
|
||||
}
|
||||
|
||||
test('returns only adopted requirements from current project', () => {
|
||||
const result = getProjectAdoptedRequirementCandidates([
|
||||
req('r1', 'project-1', 'adopted'),
|
||||
req('r2', 'project-1', 'pending_review'),
|
||||
req('r3', 'project-2', 'adopted'),
|
||||
], 'project-1');
|
||||
|
||||
assert.deepEqual(result.map((r: Requirement) => r.id), ['r1']);
|
||||
});
|
||||
|
||||
test('keeps historical selected requirements as non-candidate options', () => {
|
||||
const options = mergeSelectedRequirementOptions(
|
||||
[req('r1', 'project-1', 'adopted')],
|
||||
[req('r1', 'project-1', 'adopted'), req('r2', 'project-1', 'developing')],
|
||||
['r1', 'r2'],
|
||||
);
|
||||
|
||||
assert.equal(options.find((o: { id: string; isHistorical?: boolean }) => o.id === 'r2')?.isHistorical, true);
|
||||
});
|
||||
Reference in New Issue
Block a user