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>
90 lines
3.7 KiB
TypeScript
90 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import test from 'node:test';
|
|
|
|
function source(path: string) {
|
|
return readFileSync(join(process.cwd(), path), 'utf8');
|
|
}
|
|
|
|
function assertNoBroadBusinessFetches(path: string, allowedPatterns: RegExp[] = []) {
|
|
const text = allowedPatterns.reduce(
|
|
(current, pattern) => current.replace(pattern, ''),
|
|
source(path),
|
|
);
|
|
|
|
for (const method of [
|
|
'fetchRequirements',
|
|
'fetchPlans',
|
|
'fetchTasks',
|
|
'fetchDevTasks',
|
|
'fetchTestCases',
|
|
'fetchBugs',
|
|
]) {
|
|
assert.doesNotMatch(
|
|
text,
|
|
new RegExp(`\\b${method}\\(\\s*\\)`),
|
|
`${path} must not call ${method}() without a relation scope`,
|
|
);
|
|
}
|
|
}
|
|
|
|
test('version detail runtime loads requirements and work data by relation scope', () => {
|
|
const text = source('app/versions/[id]/page.tsx');
|
|
|
|
assert.match(text, /fetchRequirements\(\{ productId: version\.productId, versionId \}\)/);
|
|
assert.match(text, /fetchRequirements\(\{ productId: version\.productId, versionId, force: true \}\)/);
|
|
assertNoBroadBusinessFetches('app/versions/[id]/page.tsx');
|
|
});
|
|
|
|
test('version list hydrates visible versions through scoped relation partitions', () => {
|
|
const text = source('app/versions/page.tsx');
|
|
|
|
assert.match(text, /fetchRequirements\(\{ productId: version\.productId, versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchPlans\(\{ versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchDevTasks\(\{ versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchTestCases\(\{ versionId: version\.id \}\)/);
|
|
assertNoBroadBusinessFetches('app/versions/page.tsx');
|
|
});
|
|
|
|
test('workspace fallback and drawer hydration remain version scoped', () => {
|
|
const hook = source('hooks/useWorkspaceWorkItems.ts');
|
|
const page = source('app/workspace/page.tsx');
|
|
|
|
assert.match(hook, /hydrateWorkspaceStoreFallback/);
|
|
assert.match(page, /hydrateWorkspaceStoreFallback/);
|
|
assert.match(page, /fetchRequirements\(\{ productId: versionContext\.productId, versionId: item\.versionId \}\)/);
|
|
assertNoBroadBusinessFetches('hooks/useWorkspaceWorkItems.ts');
|
|
assertNoBroadBusinessFetches('app/workspace/page.tsx');
|
|
});
|
|
|
|
test('xiaobao fallback hydrates visible versions by relation scope only', () => {
|
|
const text = source('hooks/useXiaobaoWarningRisks.ts');
|
|
|
|
assert.match(text, /hydrateXiaobaoStoreFallback/);
|
|
assert.match(text, /fetchRequirements\(\{ productId: version\.productId, versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchPlans\(\{ versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchTasks\(\{ versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchTestCases\(\{ versionId: version\.id \}\)/);
|
|
assert.match(text, /fetchBugs\(\{ versionId: version\.id \}\)/);
|
|
assertNoBroadBusinessFetches('hooks/useXiaobaoWarningRisks.ts');
|
|
});
|
|
|
|
test('overtime modal loads selected version requirements through relation scope', () => {
|
|
const text = source('app/overtime/page.tsx');
|
|
|
|
assert.match(text, /onVersionChange=\{\(version\) => fetchRequirements\(\{ productId: version\.productId, versionId: version\.id \}\)\}/);
|
|
assertNoBroadBusinessFetches('app/overtime/page.tsx');
|
|
});
|
|
|
|
test('requirement pool fallback hydrates the selected relation scope', () => {
|
|
const text = source('app/requirements/page.tsx');
|
|
|
|
assert.match(text, /hydrateRequirementStoreFallback/);
|
|
assert.match(text, /fetchRequirements\(\{ productId: selectedScope\.productId \}\)/);
|
|
assert.match(text, /fetchRequirements\(\{ productId: project\.productId, projectId: selectedScope\.projectId \}\)/);
|
|
assert.match(text, /fetchRequirements\(\{ productId: product\.id \}\)/);
|
|
assert.match(text, /fetchDevTasks\(\{ versionId: version\.id \}\)/);
|
|
assertNoBroadBusinessFetches('app/requirements/page.tsx');
|
|
});
|