/**
* ACT-WORK-05 差异评估的包内自测 —— **只准 import @sdk / @contracts / @sfeel**。
* 案例活动没有 `run`,自测不跑回合;测的是清单本身与授权面对齐,结构照 E04 / I01。
*
* 七组:清单本身合规 / 台账声明 / 案例模型与清单的对齐 / 报告模版:编辑面与只读面各就各位 /
* 徽标别名与值域相关的坑(2026-08-27 实测账,回归网)/ 可编辑件的主键与必填列
* (2026-08-27 复审,回归网)/ 活动入口。
*/
import { describe, expect, it } from 'vitest';
import { activityManifestSchema } from '@contracts';
import { createMockHost } from '@sdk';
import { manifest, D } from '../src/manifest.ts';
import activity from '../src/index.ts';
/*
* 2026-08-29 Task 3 整体重写(spec §4):九步砍成四步,案例模型换成 CMMN + `case-model.ts` 里的
* `ASSESSMENT_STEPS` 四条剧本。这份包内自测原是照旧九步写的,`案例模型与清单的对齐` 这组的多数
* 断言在结构上仍然成立(CMMN humanTask id 与剧本 item 一一对应、除放行外每项恰属一个阶段…),
* 只是数字与名单要随新模型换 —— 下面这几处常量与断言标题已按 `case-model.ts` 的新四步同步更新。
*/
const ITEMS = ['S1_inputs', 'S2_assess', 'S3_review', 'T_release'];
/*
* 2026-08-29 Task 3:四步里只有 `S3_review`(审核,可循环)与 `T_release`(放行)不给
* `doneWhen`——判据不许摆在还欠一张卡的那一步眼前(2026-08-28 用户实测逼出的立墙,
* `humanWrites`/`acceptanceChecklist` 同一课)。`S1_inputs` / `S2_assess` 全 auto,
* 入库事实 / 分析结论一落地引擎就自己收步,不再需要人工激活等待。
*/
const NO_DONE_WHEN = new Set(['S3_review', 'T_release']);
/*
* 2026-08-29 Task 7:五张旧局面收成三张 —— `p08-master-create` / `p10-document-create` /
* `eval-input-list` 三张合并成一张 `input-supplement`(Task 7 已交付);
* `difference-review` / `landing-confirm` 由 Task 8 / 9 各自重做(同名)。
*/
const VIEWS = ['input-supplement', 'difference-review', 'landing-confirm'];
/** 运营中心 L2 沙箱里那张关键台账数据看板 —— 不是工单件,只在「都声明了」这一条里出现;自己那组断言在文件尾 */
const BOARD_VIEW = 'activity-ledger';
const byAddress = (domain: string, object: string) => manifest.declarations.ledger.find((l) => l.domain === domain && l.object === object);
const viewHtml = (name: string) => manifest.assets.viewTemplates.find((t) => t.name === name)?.html ?? '';
/* 「台账声明」组用的短写(2026-08-29 重写引入):地址是 `域.对象` 一整串,`byAddress` 拆两段 */
const ledgerOf = (address: string) => manifest.declarations.ledger.find((l) => `${l.domain}.${l.object}` === address);
const colOf = (address: string, name: string) => ledgerOf(address)?.fields.find((f) => f.name === name);
/**
* 从一段 CSS 文本里摘出**选择器里提到过的所有 class token**(2026-08-30 task-12,缺陷③用)。
* 只扫选择器,不扫规则体(`content:"…"` 这类属性值里的文字不算);`@media`/`@supports`
* 这类带嵌套一层规则体的 at-rule 会往里再走一遍(本仓三份件的 `@media(max-width:600px)` 与
* `@media (prefers-reduced-motion: reduce)` 都嵌着真正的选择器,不能漏)。
* 这是**存在性**扫描(选择器里出没出现过这个 class),不判断它是不是复合选择器的一部分 ——
* `.zic` 完全不存在是这份扫描要抓的那种漏(缺陷③的两个真实事故都是这一种:某个 class
* 在目标件自己的 `'));
expect(body).not.toContain('gateprog');
expect(body).not.toContain('class="viewarea"');
expect(body).not.toContain('class="editarea"');
/* .editarea{display:none} 还在 CSS 里 —— 谁把内容包进它,那块就永远消失 */
expect(html).toContain('.editarea{display:none}');
});
it('**保存即铺格之前的空态**:pvnull 按 parts_parameter_rows 的 v-0 档现身(零行才摆提示,有行不摆 —— 界面不撒谎)', () => {
expect(html).toContain('class="pv-empty pvnull" data-class-of="parts_parameter_rows"');
expect(html).toContain('.pvnull{display:none}');
expect(html).toContain('.pv-empty.pvnull.v-0{display:block}');
});
});
/*
* 件② 差异评估结论审核(2026-08-29,Task 8):S3 的验收工单,`view: 'difference-review'`
* 指向它,`cardVariant: 'review'`。绑定契约(spec §6.2):对决头(原 PN → 候选 PN、类型徽)+
* 四态分布带 + 推荐等级大徽章只读;逐条明细可就地改(四态 / 影响说明 / 判断依据 / UNKNOWN 去向);
* 收口四格(推荐理由 / 差异摘要 / 风险 / 验证要求)只读 —— 它们是配方按规则算的,人要改就去改
* 上面那一条四态,系统重算。复用文件顶部已有的 `viewHtml` 短写。
*/
describe('件② 差异评估结论审核', () => {
const html = viewHtml('difference-review');
it('在 viewTemplates 里,S3 指向它,面孔是审核卡', () => {
expect(html).not.toBe('');
const s3 = (manifest.assets.businessModel.steps as ReadonlyArray<{ item: string; view?: string; cardVariant?: string }>)
.find((s) => s.item === 'S3_review');
expect(s3?.view).toBe('difference-review');
expect(s3?.cardVariant).toBe('review');
});
it('逐条明细可改,且**改的是四态**', () => {
expect(html).toContain('data-rows="mine:substitution.difference_item"');
expect(html).toContain('data-edit="substitution.difference_item"');
expect(html).toContain('data-col="difference_status"');
for (const col of ['impact_statement', 'evidence_note', 'unknown_disposition']) {
expect(html).toContain(`data-col="${col}"`);
}
expect(html).toContain('data-col="difference_item_id"');
});
it('**推荐理由 / 摘要 / 风险 / 验证要求只读** —— 让人直接改摘要,等于让他给自己没做的判断盖章', () => {
for (const col of ['recommendation_reason', 'difference_summary', 'verification_requirement']) {
expect(html).toContain(`data-slot="${col}"`);
expect(html).not.toContain(`data-col="${col}"`);
}
expect(html).not.toContain('data-edit="substitution.relation"');
});
it('等级与四态用 data-class-of 上色 —— 判断留在样式表,模版不判', () => {
expect(html).toContain('data-class-of="recommendation_level"');
expect(html).not.toContain('