164 lines
5.0 KiB
TypeScript
164 lines
5.0 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import type { Bug } from './bug';
|
|
import type { DevTask } from './dev-task';
|
|
import type { TestCase } from './test-case';
|
|
import type { TaskWorklog } from './task-worklog';
|
|
import type { VersionPlan } from './version-plan';
|
|
import type { WorkActivity } from './work-activity';
|
|
import { buildVersionDailyEvidence, buildXiaobaoWorkItems } from './xiaobao-risk-evidence';
|
|
|
|
function plan(patch: Partial<VersionPlan> = {}): VersionPlan {
|
|
return {
|
|
id: 'plan-1',
|
|
versionId: 'ver-1',
|
|
type: 'product',
|
|
title: 'Product plan',
|
|
owner: 'pm-1',
|
|
startTime: '2026-06-20T01:00:00.000Z',
|
|
endTime: '2026-06-25T10:00:00.000Z',
|
|
status: 'in_progress',
|
|
actualStartAt: '2026-06-20T01:00:00.000Z',
|
|
createdAt: '2026-06-20T01:00:00.000Z',
|
|
addedBy: 'pm-1',
|
|
...patch,
|
|
};
|
|
}
|
|
|
|
function devTask(patch: Partial<DevTask> = {}): DevTask {
|
|
return {
|
|
id: 'dev-1',
|
|
taskNo: 'DEV-001',
|
|
requirementId: 'req-1',
|
|
title: 'Build warning panel',
|
|
categoryId: 'frontend',
|
|
assigneeId: 'dev-other',
|
|
priority: 'P1',
|
|
expectedStartAt: '2026-06-20T01:00:00.000Z',
|
|
expectedEndAt: '2026-06-26T10:00:00.000Z',
|
|
status: 'in_progress',
|
|
isBlocked: false,
|
|
actualStartAt: '2026-06-20T01:00:00.000Z',
|
|
createdBy: 'pm-1',
|
|
createdAt: '2026-06-20T01:00:00.000Z',
|
|
updatedAt: '2026-06-24T02:00:00.000Z',
|
|
...patch,
|
|
};
|
|
}
|
|
|
|
function testCase(patch: Partial<TestCase> = {}): TestCase {
|
|
return {
|
|
id: 'tc-1',
|
|
caseNo: 'TC-001',
|
|
versionId: 'ver-1',
|
|
title: 'Verify warning panel',
|
|
categoryId: 'ui-interaction',
|
|
priority: 'P2',
|
|
assigneeId: 'qa-other',
|
|
status: 'running',
|
|
startedAt: '2026-06-20T03:00:00.000Z',
|
|
createdBy: 'qa-other',
|
|
createdAt: '2026-06-20T01:00:00.000Z',
|
|
updatedAt: '2026-06-24T02:00:00.000Z',
|
|
...patch,
|
|
};
|
|
}
|
|
|
|
function bug(patch: Partial<Bug> = {}): Bug {
|
|
return {
|
|
id: 'bug-1',
|
|
bugNo: 'BUG-001',
|
|
versionId: 'ver-1',
|
|
testCaseId: 'tc-1',
|
|
title: 'Warning count mismatch',
|
|
description: 'The count is wrong.',
|
|
severity: 'major',
|
|
priority: 'P1',
|
|
reportedBy: 'qa-other',
|
|
assigneeId: 'dev-other',
|
|
status: 'open',
|
|
createdAt: '2026-06-20T01:00:00.000Z',
|
|
updatedAt: '2026-06-24T02:00:00.000Z',
|
|
...patch,
|
|
};
|
|
}
|
|
|
|
test('buildVersionDailyEvidence groups version activity and detects no activity/no update', () => {
|
|
const workItems = buildXiaobaoWorkItems({
|
|
plans: [plan()],
|
|
devTasks: [devTask()],
|
|
testCases: [testCase()],
|
|
bugs: [bug()],
|
|
versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
|
|
requirementVersionMap: new Map([['req-1', 'ver-1']]),
|
|
});
|
|
const activities: WorkActivity[] = [
|
|
{
|
|
id: 'act-delivery',
|
|
actorId: 'dev-other',
|
|
date: '2026-06-29',
|
|
occurredAt: '2026-06-29T02:00:00.000Z',
|
|
sourceType: 'dev_task',
|
|
sourceId: 'dev-1',
|
|
action: 'dev_task_submitted',
|
|
category: 'delivery',
|
|
title: 'Build warning panel',
|
|
summary: 'Submitted development task',
|
|
},
|
|
{
|
|
id: 'act-risk',
|
|
actorId: 'qa-other',
|
|
date: '2026-06-29',
|
|
occurredAt: '2026-06-29T03:00:00.000Z',
|
|
sourceType: 'bug',
|
|
sourceId: 'bug-1',
|
|
action: 'bug_blocked',
|
|
category: 'risk',
|
|
title: 'Warning count mismatch',
|
|
summary: 'Blocked by missing data',
|
|
},
|
|
];
|
|
const worklogs: TaskWorklog[] = [
|
|
{
|
|
id: 'wl-note',
|
|
taskId: 'tc-1',
|
|
userId: 'qa-other',
|
|
date: '2026-06-29',
|
|
hours: 1,
|
|
workContent: 'Continued regression testing.',
|
|
createdAt: '2026-06-29T04:00:00.000Z',
|
|
},
|
|
];
|
|
|
|
const evidence = buildVersionDailyEvidence({
|
|
versionId: 'ver-1',
|
|
workItems,
|
|
activities,
|
|
worklogs,
|
|
now: new Date('2026-06-29T08:00:00.000Z'),
|
|
});
|
|
|
|
assert.deepEqual(evidence.todayDeliveries.map((item) => item.id), ['act-delivery']);
|
|
assert.deepEqual(evidence.todayRisks.map((item) => item.id), ['act-risk']);
|
|
assert.deepEqual(evidence.progressNotes.map((item) => item.id), ['wl-note']);
|
|
assert.equal(evidence.recentActivityCount, 3);
|
|
assert.equal(evidence.lastActivityAt, '2026-06-29T04:00:00.000Z');
|
|
assert.ok(evidence.silentRisks?.some((risk) => risk.key === 'no_update' && risk.itemId === 'plan-1'));
|
|
assert.ok(evidence.silentRisks?.some((risk) => risk.key === 'no_activity' && risk.itemId === 'plan-1'));
|
|
});
|
|
|
|
test('buildXiaobaoWorkItems keeps all version work without current-user filtering', () => {
|
|
const items = buildXiaobaoWorkItems({
|
|
plans: [plan({ owner: 'pm-other' })],
|
|
devTasks: [devTask({ assigneeId: 'dev-other' })],
|
|
testCases: [testCase({ assigneeId: 'qa-other' })],
|
|
bugs: [bug({ assigneeId: 'dev-other' })],
|
|
versions: [{ id: 'ver-1', name: 'V1.0', productName: 'FTB', projectName: 'PM' }],
|
|
requirementVersionMap: new Map([['req-1', 'ver-1']]),
|
|
});
|
|
|
|
assert.deepEqual(items.map((item) => item.id), ['plan-1', 'dev-1', 'tc-1', 'bug-1']);
|
|
assert.deepEqual(items.map((item) => item.versionId), ['ver-1', 'ver-1', 'ver-1', 'ver-1']);
|
|
});
|