feat(小宝预警): 增加日报证据与风险趋势
This commit is contained in:
163
apps/web/lib/xiaobao-risk-evidence.test.ts
Normal file
163
apps/web/lib/xiaobao-risk-evidence.test.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
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']);
|
||||
});
|
||||
Reference in New Issue
Block a user