Some checks failed
Deploy Production / Build, push, deploy, verify (push) Has been cancelled
- 移除已迁移业务 AppData 运行时 fallback,改走领域 API 和关系表快读 - 补齐需求产品负责人、版本计划任务 JSON 和成员 username 回填迁移 - 统一治理字典入口,并补充 AI provider、数据源契约和领域服务测试 Co-Authored-By: Codex GPT-5 <codex@openai.com>
51 lines
2.1 KiB
TypeScript
51 lines
2.1 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import test from 'node:test';
|
|
|
|
const rootFile = (path: string) => readFileSync(join(process.cwd(), path), 'utf8');
|
|
|
|
test('plan auto-start effect only persists the same pending plan once', () => {
|
|
const text = rootFile('components/version/PlanTab.tsx');
|
|
|
|
assert.match(text, /useRef/);
|
|
assert.match(text, /autoStartedPlanIds/);
|
|
assert.match(text, /!autoStartedPlanIds\.current\.has\(plan\.id\)/);
|
|
assert.match(text, /autoStartedPlanIds\.current\.add\(plan\.id\)/);
|
|
});
|
|
|
|
test('plan owner UI resolves stored member ids to display names and filters transfer choices by member reference', () => {
|
|
const text = rootFile('components/version/PlanTab.tsx');
|
|
|
|
assert.match(text, /resolveMemberDisplayName/);
|
|
assert.match(text, /isMemberReference/);
|
|
assert.match(text, /ownerLabel/);
|
|
assert.doesNotMatch(text, />\{plan\.owner\}<\/span>/);
|
|
assert.doesNotMatch(text, />\{plan\.owner\}<\/dd>/);
|
|
assert.doesNotMatch(text, /member\.name !== plan\.owner/);
|
|
});
|
|
|
|
test('version detail passes relation-backed member candidates to plan tabs for id display resolution', () => {
|
|
const text = rootFile('app/versions/[id]/page.tsx');
|
|
|
|
assert.match(text, /username: member\.username/);
|
|
assert.match(text, /currentUserReference=\{user\?\.username/);
|
|
assert.match(text, /allMembers=\{memberCandidates\}/);
|
|
});
|
|
|
|
test('plan create response merge preserves optimistic auto-start fields from the current local row', () => {
|
|
const text = rootFile('stores/useVersionPlanStore.ts');
|
|
|
|
assert.match(text, /mergeCreatedVersionPlan/);
|
|
assert.doesNotMatch(text, /\{\s*\.\.\.plan,\s*\.\.\.result\.item,\s*tasks: plan\.tasks\s*\}/);
|
|
});
|
|
|
|
test('requirement product owner is sent to the relation API instead of staying as a local-only field', () => {
|
|
const requirementStore = rootFile('stores/useRequirementStore.ts');
|
|
const domainApi = rootFile('lib/domain-api.ts');
|
|
|
|
assert.doesNotMatch(requirementStore, /delete domainPatch\.productOwner/);
|
|
assert.match(domainApi, /productOwnerId/);
|
|
assert.match(domainApi, /data\.productOwner/);
|
|
});
|