aps-agent/apps/web/e2e/order-closed-loop-contract....

51 lines
2.5 KiB
TypeScript

// Round 65 W4: closed-loop APS order/MRP frontend contract guard.
// Source-level by design: validates backward-compatible typing and no-fake-success UI copy
// without mutating a live APS world or requiring authentication.
import { expect, test } from '@playwright/test';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
const webRoot = path.resolve(process.cwd());
test('订单面板消费 closedLoop 证据并明确六阶段门禁', async () => {
const source = await readFile(path.join(webRoot, 'src/orders/OrderPanel.tsx'), 'utf8');
expect(source).toContain('setClosedLoop(res.result?.closedLoop ?? null)');
for (const label of ['商务订单', 'BOM/供需净算', '制造需求准入', '排产草案', 'P2 发布', 'P3 MES']) {
expect(source).toContain(label);
}
expect(source).toContain('它们仍是制造需求,不是已释放生产订单');
expect(source).toContain('不会自动转采购');
expect(source).toContain('待独立确认');
expect(source).toContain('closed-loop-manufacturing-demands');
expect(source).toContain('closed-loop-blockers');
});
test('MRP 分解类型保持旧清单并可选扩展 closedLoop 契约', async () => {
const source = await readFile(path.join(webRoot, 'src/api/types.ts'), 'utf8');
expect(source).toContain('make: MakeSuggestion[];');
expect(source).toContain('purchase: PurchaseSuggestion[];');
expect(source).toContain('outsource: OutsourceSuggestion[];');
expect(source).toContain('closedLoop?: MrpClosedLoopDecomposition;');
for (const field of [
'problemId: string;', 'sourceHash: string;', 'businessDate: string;',
'summary: ClosedLoopSummary;', 'projection: ClosedLoopProjection;',
'manufacturingDemands: ClosedLoopManufacturingDemand[];',
'supplyEvents: ClosedLoopSupplyEvent[];', 'blockers: ClosedLoopBlocker[];',
'schedulingProblemV2: SchedulingProblemV2Projection;',
]) {
expect(source).toContain(field);
}
});
test('订单选择展示关联产物并在主世界刷新后补拉订单数据', async () => {
const source = await readFile(path.join(webRoot, 'src/orders/OrderPanel.tsx'), 'utf8');
expect(source).toContain('data-testid="order-linked-detail"');
expect(source).toContain('onClick: () => setSelectedId(o.id)');
expect(source).toContain('采购或委外为 0 可能是库存覆盖或未配置外协,并非刷新失败');
expect(source).toContain('worldRefreshRef.current = props.onWorldRefresh');
expect(source).toContain("setView('make')");
});