| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // 票 56(第二/三轮):所有面板顶部摘要统一折叠,**只有点击**展开/收起。
- // 离线闸门:静态断言渲染层 + 用真实注册表做说明字段的**行为层双向完备性普查**。
- import fs from 'node:fs'
- import assert from 'node:assert/strict'
- import { MONITORING_FAULT_GAP, monitoringSummaryPanel } from '../../../src/modules/cockpit/domain/overviewPanels.js'
- import { implementedPanelIds, panelView } from '../../../src/modules/cockpit/domain/panelViews.js'
- const ROOT = new URL('../../../', import.meta.url)
- const panelBlocks = fs.readFileSync(new URL('src/modules/cockpit/components/PanelBlocks.vue', ROOT), 'utf8')
- const monitoringPanels = fs.readFileSync(new URL('src/modules/cockpit/domain/monitoringPanels.js', ROOT), 'utf8')
- const overviewPanels = fs.readFileSync(new URL('src/modules/cockpit/domain/overviewPanels.js', ROOT), 'utf8')
- /**
- * 把每个已实现面板的视图真的算一遍,收集「视图级说明字段」(`*Note` / `note` / `gap`)。
- * 走注册表而不是正则扫源码:正则会被换缩进/换行写法静默绕过(票 43 的"守卫比要守的宽"教训)。
- */
- function panelViewRegistryProbe() {
- const found = new Set()
- const built = []
- for (const panelId of implementedPanelIds()) {
- let view = null
- try {
- view = panelView(panelId, {}, null, undefined)
- } catch {
- view = null
- }
- if (!view) continue
- built.push(panelId)
- for (const key of Object.keys(view)) {
- if (key === 'gap' || key === 'note' || /Note$/.test(key)) found.add(key)
- }
- }
- return { fields: [...found], built }
- }
- const registry = panelViewRegistryProbe()
- let n = 0
- const ok = (cond, msg) => { assert.ok(cond, `A${++n} ${msg}`); console.log(`PASS A${n} ${msg}`) }
- // A 组:折叠入口只有点击一条路径
- ok(/summaryOpen = ref\(false\)/.test(panelBlocks), '默认折叠(summaryOpen 初值 false)')
- ok(/@click="summaryOpen = !summaryOpen"/.test(panelBlocks), '点击是唯一 toggle 路径')
- ok(!/summaryHover|summaryFocus|summaryPinned|@mouseenter="summary|@focusin="summary/.test(panelBlocks), 'hover/focus 自动展开已撤销(第二轮维护者裁定)')
- ok(/:aria-expanded="summaryOpen"/.test(panelBlocks), 'aria-expanded 绑定同一个状态')
- ok(/:aria-controls="summaryDetailsId"/.test(panelBlocks) && /panel-summary-details-\$\{props\.view\.name/.test(panelBlocks), 'aria-controls 按面板名唯一(多面板共存不串 target)')
- ok(!/@keydown\.(enter|space)/.test(panelBlocks), '不写显式 keydown:原生 button 的 Enter/Space 已触发 click,重复绑定会双触发互相抵消')
- // B 组:摘要条目完备 —— 每条保留原 data-* 断言面
- const EXPECTED = [
- ['industryNote', 'data-panel-industry'],
- ['typeNote', 'data-panel-type-note'],
- ['eventNote', 'data-panel-event-note'],
- ['rangeNote', 'data-panel-range-note'],
- ['gap', 'data-panel-gap'],
- ['offlineNote', 'data-panel-offline-note'],
- ['pageNote', 'data-panel-page-note'],
- ['locateNote', 'data-locate-note'],
- ['excludedNote', 'data-panel-excluded-note'],
- ['linkNote', 'data-panel-link-note'],
- ['note', 'data-panel-note'],
- // 票 64:运行信息新增「数据来源与口径」说明。**这条是普查自己抓出来的**——
- // 加进 domain 而没加进本表时 A18 当场判红(漏网即隐形),按成例补条目并保留断言面。
- ['sourceNote', 'data-panel-source-note'],
- ]
- for (const [field, hook] of EXPECTED) {
- ok(
- panelBlocks.includes(`field: '${field}', hook: '${hook}'`),
- `摘要条目 ${field} 折叠并保留 ${hook}(走查脚本 t17/t18/t20 选择器不变)`,
- )
- }
- // C 组:**行为层双向完备性普查**(t44 的机制,不靠人记得去查,也不靠正则匹缩进)。
- // 用真实注册表算出全部 15 个面板的视图,收集「视图级说明字段」的并集:
- // · domain 新增了说明字段而不进折叠表 → 漏网判红(它会在界面上隐形);
- // · 折叠表里有字段而任何面板都不再声明 → 死接线判红(无消费点的接线早晚漂移)。
- const declared = new Set(registry.fields)
- const tabled = new Set(EXPECTED.map(([field]) => field))
- const missing = [...declared].filter((f) => !tabled.has(f))
- ok(missing.length === 0, `domain 视图声明的说明字段全部进折叠表(漏网:${missing.join(', ') || '无'})`)
- const dead = [...tabled].filter((f) => !declared.has(f))
- ok(dead.length === 0, `折叠表内字段仍有面板在声明(死接线:${dead.join(', ') || '无'})`)
- ok(
- ['gap', 'note', 'linkNote', 'excludedNote', 'offlineNote', 'pageNote'].every((f) => declared.has(f)),
- `普查真的见到这六类(当前并集 ${declared.size} 条,守卫面没被写窄)`,
- )
- ok(
- registry.built.length >= 12,
- `普查覆盖到 12+ 个面板视图(实际 ${registry.built.length} 个:${registry.built.join(', ')})`,
- )
- // D 组:用户点名的「故障口径」真的落到运行监测面板的摘要里(行为层,不是正则)
- {
- const view = monitoringSummaryPanel({}, null)
- ok(view.gap === MONITORING_FAULT_GAP, '运行监测视图仍由 domain 单源给出故障口径 gap')
- ok(view.gap.includes('故障'), '故障口径文案未被动过')
- ok(tabled.has('gap'), '故障口径经折叠表的 gap 条目进入摘要(第三轮诉求)')
- }
- // E 组:旧的独立渲染必须清零(否则折叠形同虚设:同一句话画两遍或仍在头部外裸奔)
- ok(!/v-if="view\.(gap|offlineNote|pageNote|rangeNote|industryNote|typeNote|eventNote|locateNote|note|linkNote|excludedNote|sourceNote)\b/.test(panelBlocks), '没有任何说明字段在折叠入口之外独立渲染')
- ok(/v-show="summaryOpen"/.test(panelBlocks), '折叠用 v-show:文本仍在 DOM(信息不丢,只改呈现)')
- ok(/<header v-if="summaryItems\.length"/.test(panelBlocks), '没有摘要的面板不画空头部')
- // F 组:折叠态读数不误导
- ok(/有离线设备/.test(panelBlocks) && /当前窗口没有离线设备/.test(panelBlocks), '离线摘要在折叠态仍区分「有离线」与「无离线」')
- ok(/view\.gap \|\| view\.note \|\| view\.excludedNote/.test(panelBlocks), '三类口径说明(gap/note/excludedNote)都计入「有口径提示」')
- // G 组:domain 数据与措辞零改动(折叠只归渲染层)
- ok(/rangeNote: current\.rangeStart && current\.rangeEnd/.test(monitoringPanels), '运行概况统计窗口措辞仍由 domain 单源')
- ok(/offlineNote: offlineDevices\.length/.test(monitoringPanels), '离线设备摘要仍由 domain 从异常清单挑选,不推断')
- ok(/gap: MONITORING_FAULT_GAP/.test(overviewPanels), '总体概览-运行监测的故障口径缺口仍是 MONITORING_FAULT_GAP 单源')
- console.log(`t56 panel summary disclosure: ${n}/${n} passed`)
|