import test from 'node:test'; import assert from 'node:assert/strict'; import { TEST_CASE_STATUS_LABEL, aggregateTestCaseHours, calcTestProgress, getTestCaseEstimateHours, normalizeTestCase, } from './test-case'; import { DEFAULT_TEST_CATEGORY_ID } from './task-category'; test('normalizeTestCase backfills missing categoryId', () => { const tc = normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '登录正常', priority: 'P2', status: 'pending', createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any); assert.equal(tc.categoryId, DEFAULT_TEST_CATEGORY_ID); }); test('normalizeTestCase keeps existing categoryId', () => { const tc = normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '登录正常', priority: 'P2', status: 'pending', categoryId: 'cat-test-api', createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any); assert.equal(tc.categoryId, 'cat-test-api'); }); test('normalizeTestCase keeps missing executor estimate empty', () => { const tc = normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '登录正常', priority: 'P2', status: 'pending', categoryId: 'cat-test-api', createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any); assert.equal(tc.estimateHours, undefined); assert.equal(getTestCaseEstimateHours(tc), 0); }); test('getTestCaseEstimateHours prefers executor estimate over AI estimate', () => { const tc = normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '登录正常', priority: 'P2', status: 'pending', categoryId: 'cat-test-api', estimateHours: 0.7, aiEstimateHours: 0.2, createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any); assert.equal(getTestCaseEstimateHours(tc), 0.7); }); test('getTestCaseEstimateHours falls back to AI estimate', () => { const tc = normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '登录正常', priority: 'P2', status: 'pending', categoryId: 'cat-test-api', aiEstimateHours: 0.2, createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any); assert.equal(getTestCaseEstimateHours(tc), 0.2); }); test('test case status labels use waiting and testing wording', () => { assert.equal(TEST_CASE_STATUS_LABEL.pending, '待测试'); assert.equal(TEST_CASE_STATUS_LABEL.running, '测试中'); assert.equal(TEST_CASE_STATUS_LABEL.failed, '不通过'); }); test('calcTestProgress uses estimate-weighted completion', () => { const progress = calcTestProgress([ normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '待测试', priority: 'P2', status: 'pending', categoryId: 'cat-test-functional', estimateHours: 1, createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any), normalizeTestCase({ id: 'tc-2', caseNo: 'TC-002', versionId: 'v1', title: '已通过', priority: 'P2', status: 'passed', categoryId: 'cat-test-functional', estimateHours: 3, createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any), ]); assert.equal(progress.completionRate, 75); }); test('aggregateTestCaseHours returns estimate and actual totals', () => { const hours = aggregateTestCaseHours([ normalizeTestCase({ id: 'tc-1', caseNo: 'TC-001', versionId: 'v1', title: '测试中', priority: 'P2', status: 'running', categoryId: 'cat-test-functional', estimateHours: 1, startedAt: '2026-06-25T01:00:00.000Z', createdBy: 'tester', createdAt: '2026-06-25', updatedAt: '2026-06-25', } as any), ], new Date('2026-06-25T02:00:00.000Z')); assert.equal(hours.estimate, 1); assert.equal(hours.actual, 1); });