Files
ftb-project-management/apps/web/lib/test-case-workflow.ts
2026-06-25 14:13:32 +08:00

60 lines
1.6 KiB
TypeScript

import type { TestCase, TestCaseStatus } from './test-case';
import { canTcTransition } from './test-case';
export interface TestCaseWorkflowResult {
ok: boolean;
patch?: Partial<TestCase>;
message?: string;
}
export interface TestCaseTransitionOptions {
now?: Date;
failReason?: string;
blockReason?: string;
}
export function normalizeTestCaseOnCreate(testCase: TestCase): TestCase {
return {
...testCase,
status: 'pending',
startedAt: undefined,
completedAt: undefined,
executedAt: undefined,
failReason: undefined,
blockReason: undefined,
};
}
export function applyTestCaseTransition(
testCase: TestCase,
to: TestCaseStatus,
options: TestCaseTransitionOptions = {},
): TestCaseWorkflowResult {
if (!canTcTransition(testCase.status, to)) {
return { ok: false, message: `不允许从「${testCase.status}」流转到「${to}` };
}
const nowIso = (options.now ?? new Date()).toISOString();
const patch: Partial<TestCase> = {
status: to,
aiDraft: false,
executedAt: nowIso,
};
if (to === 'running') {
if (!testCase.startedAt) patch.startedAt = nowIso;
patch.completedAt = undefined;
patch.failReason = undefined;
patch.blockReason = undefined;
}
if (to === 'passed' || to === 'failed' || to === 'blocked') {
patch.completedAt = nowIso;
}
if (to === 'failed' && options.failReason?.trim()) patch.failReason = options.failReason.trim();
if (to === 'blocked' && options.blockReason?.trim()) patch.blockReason = options.blockReason.trim();
return { ok: true, patch };
}