feat(小宝预警): 增加版本风险预测引擎
This commit is contained in:
106
apps/web/lib/xiaobao-risk.test.ts
Normal file
106
apps/web/lib/xiaobao-risk.test.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { calcXiaobaoVersionRisk } from './xiaobao-risk';
|
||||
import type { DevTask } from './dev-task';
|
||||
import type { TestCase } from './test-case';
|
||||
import type { Bug } from './bug';
|
||||
|
||||
function version(patch: any = {}) {
|
||||
return {
|
||||
id: 'ver-1',
|
||||
name: 'V1.0',
|
||||
status: 'developing',
|
||||
productName: 'FTB',
|
||||
projectName: '项目管理',
|
||||
expectedReleaseDate: '2026-07-03T10:00:00.000Z',
|
||||
members: [{ name: '张三', role: 'frontend' }],
|
||||
...patch,
|
||||
};
|
||||
}
|
||||
|
||||
function devTask(patch: Partial<DevTask> = {}): DevTask {
|
||||
return {
|
||||
id: 'dev-1',
|
||||
taskNo: 'DEV-001',
|
||||
requirementId: 'req-1',
|
||||
title: '实现版本风险页',
|
||||
categoryId: 'frontend',
|
||||
assigneeId: 'm-1',
|
||||
priority: 'P1',
|
||||
expectedStartAt: '2026-07-01T09:00:00.000Z',
|
||||
expectedEndAt: '2026-07-03T18:00:00.000Z',
|
||||
estimateHours: 40,
|
||||
status: 'todo',
|
||||
isBlocked: false,
|
||||
createdBy: 'm-1',
|
||||
createdAt: '2026-07-01T09:00:00.000Z',
|
||||
updatedAt: '2026-07-01T09:00:00.000Z',
|
||||
...patch,
|
||||
};
|
||||
}
|
||||
|
||||
function testCase(patch: Partial<TestCase> = {}): TestCase {
|
||||
return {
|
||||
id: 'tc-1',
|
||||
caseNo: 'TC-001',
|
||||
versionId: 'ver-1',
|
||||
title: '验收版本风险页',
|
||||
categoryId: 'ui-interaction',
|
||||
priority: 'P1',
|
||||
assigneeId: 'm-2',
|
||||
status: 'pending',
|
||||
estimateHours: 16,
|
||||
createdBy: 'm-2',
|
||||
createdAt: '2026-07-01T09:00:00.000Z',
|
||||
updatedAt: '2026-07-01T09:00:00.000Z',
|
||||
...patch,
|
||||
};
|
||||
}
|
||||
|
||||
function bug(patch: Partial<Bug> = {}): Bug {
|
||||
return {
|
||||
id: 'bug-1',
|
||||
bugNo: 'BUG-001',
|
||||
versionId: 'ver-1',
|
||||
testCaseId: 'tc-1',
|
||||
title: '发布阻断缺陷',
|
||||
description: '关键流程无法通过',
|
||||
severity: 'critical',
|
||||
priority: 'P1',
|
||||
reportedBy: 'm-2',
|
||||
assigneeId: 'm-1',
|
||||
status: 'open',
|
||||
createdAt: '2026-07-01T09:00:00.000Z',
|
||||
updatedAt: '2026-07-01T09:00:00.000Z',
|
||||
...patch,
|
||||
};
|
||||
}
|
||||
|
||||
test('calcXiaobaoVersionRisk predicts delay when remaining work exceeds release date', () => {
|
||||
const risk = calcXiaobaoVersionRisk({
|
||||
version: version(),
|
||||
devTasks: [devTask()],
|
||||
testCases: [testCase()],
|
||||
bugs: [],
|
||||
now: new Date('2026-07-02T01:00:00.000Z'),
|
||||
});
|
||||
|
||||
assert.equal(risk.riskLevel, 'likely_delayed');
|
||||
assert.ok(risk.riskScore >= 70);
|
||||
assert.ok(risk.delayDays > 0);
|
||||
assert.ok(risk.reasons.some((reason: { key: string }) => reason.key === 'remaining_work'));
|
||||
});
|
||||
|
||||
test('calcXiaobaoVersionRisk marks blocked when critical Bug / blocked dev task / failed test exist', () => {
|
||||
const risk = calcXiaobaoVersionRisk({
|
||||
version: version(),
|
||||
devTasks: [devTask({ isBlocked: true, blockReason: '依赖接口未完成' })],
|
||||
testCases: [testCase({ status: 'failed', failReason: '核心流程失败' })],
|
||||
bugs: [bug()],
|
||||
now: new Date('2026-07-02T01:00:00.000Z'),
|
||||
});
|
||||
|
||||
assert.equal(risk.riskLevel, 'blocked');
|
||||
assert.ok(risk.reasons.some((reason: { key: string }) => reason.key === 'critical_bug'));
|
||||
assert.ok(risk.reasons.some((reason: { key: string }) => reason.key === 'blocked_work'));
|
||||
});
|
||||
Reference in New Issue
Block a user