t65-clickability-coverage.mjs 6.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /** Issue 65: exhaustive entity-card clickability coverage. Pure Node only. */
  2. import assert from 'node:assert/strict'
  3. import fs from 'node:fs'
  4. import { operationPanel, emergencyPanel, toEmergencySupport, toOperatingInformation } from '../src/modules/cockpit/domain/infrastructurePanels.js'
  5. import { operationOverviewPanel, monitoringPointLedgerPanel, toMonitoringOverview, toMonitoringDistribution } from '../src/modules/cockpit/domain/monitoringPanels.js'
  6. import { historyAnalysisPanel, workOrderCardRows } from '../src/modules/cockpit/domain/warningResponsePanels.js'
  7. import { currentEventsView, toCurrentEvents } from '../src/modules/cockpit/domain/eventList.js'
  8. import { CARD_ACTION, cardActionFor } from '../src/modules/cockpit/domain/panelBlocks.js'
  9. const loaded = { state: 'success', loaded: true, data: null }
  10. const listRows = (view) => (view.blocks || []).filter((block) => block.kind === 'list').flatMap((block) => block.rows || [])
  11. const action = (row, kind, code) => {
  12. const actual = cardActionFor(row)
  13. assert.equal(actual.kind, kind)
  14. assert.equal(actual.code, code)
  15. assert.equal(actual.reason, '')
  16. }
  17. const unavailable = (row, reason) => {
  18. const actual = cardActionFor(row)
  19. assert.equal(actual.kind, CARD_ACTION.NONE)
  20. assert.match(actual.reason, reason)
  21. }
  22. const operation = operationPanel(toOperatingInformation({ selectedIndustry: { code: 'WATER_SUPPLY' }, industries: [{ industry: { code: 'WATER_SUPPLY' }, state: 'READY', metrics: [{ metricCode: 'FLOW', metricName: '流量', category: 'FLOW', facilityId: '731', facilityKind: 'WATER_PLANT', pointCodes: ['WP-DISPLAY'] }, { metricCode: 'FLOW', metricName: '流量', category: 'FLOW', facilityId: null, facilityKind: 'WATER_PLANT', pointCodes: ['NOT-A-PK'] }, { metricCode: 'FLOW', metricName: '流量', category: 'FLOW', facilityId: '732', facilityKind: null, pointCodes: ['NOT-A-CATEGORY'] }] }] }), loaded)
  23. const operationRows = listRows(operation)
  24. action(operationRows[0], CARD_ACTION.FACILITY, '731')
  25. assert.equal(operationRows[0].identityCategory, 'WATER_PLANT')
  26. unavailable(operationRows[1], /主键/)
  27. unavailable(operationRows[2], /类别/)
  28. const engineering = operationPanel(toOperatingInformation({ selectedIndustry: { code: 'DRAINAGE' }, industries: [{ industry: { code: 'DRAINAGE' }, state: 'READY', metrics: [{ metricCode: 'POINTS', metricName: '排水闸门', category: 'CAPACITY', facilityId: 'eng-1', facilityKind: 'ENGINEERING_FACILITY', pointCodes: ['GATE-1'] }] }] }), loaded)
  29. const engineeringRow = listRows(engineering)[0]
  30. action(engineeringRow, CARD_ACTION.FACILITY, 'eng-1')
  31. assert.equal(engineeringRow.identityCategory, 'ENGINEERING_FACILITY')
  32. const emergency = emergencyPanel(toEmergencySupport({ sections: { hazardSources: { state: 'EMPTY', items: [] }, protectionTargets: { state: 'READY', items: [{ objectCode: 'risk001', objectName: '学校', category: 'PROTECTION_TARGET' }] }, emergencyResources: { state: 'READY', items: [{ objectCode: 'device001', objectName: '应急设备', category: 'EMERGENCY_RESOURCE' }, { objectCode: '', objectName: '无码对象', category: 'EMERGENCY_RESOURCE' }] } } }), loaded)
  33. const emergencyRows = listRows(emergency)
  34. action(emergencyRows[0], CARD_ACTION.EMERGENCY, 'risk001')
  35. assert.equal(emergencyRows[0].identityCategory, 'PROTECTION_TARGET')
  36. action(emergencyRows[1], CARD_ACTION.EMERGENCY, 'device001')
  37. assert.equal(emergencyRows[1].identityCategory, 'EMERGENCY_RESOURCE')
  38. unavailable(emergencyRows[2], /对象编码/)
  39. // 设备台账的行来自领域转换后的 devices(`code` 由 deviceCode 归一),测试必须走同一条链,
  40. // 否则造出来的行是"原始载荷形状",与真实行的键名不同 —— 那是测试自身失真,不是产品缺陷。
  41. const overviewDomain = toMonitoringOverview({ devices: [{ deviceCode: 'D1', deviceName: '压力计' }, { deviceCode: '', deviceName: '无码设备' }] })
  42. const overview = operationOverviewPanel({}, loaded, { devices: overviewDomain.devices })
  43. const deviceRows = listRows(overview)
  44. action(deviceRows[0], CARD_ACTION.DEVICE, 'D1')
  45. unavailable(deviceRows[1], /设备编码/)
  46. const ledger = monitoringPointLedgerPanel(toMonitoringDistribution({ monitoringPoints: [{ pointCode: 'P1', pointName: '点位一' }, { pointCode: '', pointName: '无码点位' }], unassociatedEquipment: [], pagination: {} }), loaded)
  47. const pointRows = listRows(ledger)
  48. action(pointRows[0], CARD_ACTION.POINT, 'P1')
  49. unavailable(pointRows[1], /点位编码/)
  50. const history = historyAnalysisPanel({ mode: 'ALARM', events: [{ code: 'A-1', name: '报警一', level: 1 }] }, loaded)
  51. const historyRow = listRows(history)[0]
  52. action(historyRow, CARD_ACTION.EVENT, 'A-1')
  53. assert.equal(historyRow.identityFamily, 'ALARM')
  54. const orderRows = workOrderCardRows([{ id: '88', code: 'WO-88', stateCode: 0 }, { id: '', code: 'WO-NO-ID', stateCode: 0 }])
  55. action(orderRows[0], CARD_ACTION.WORK_ORDER, '88')
  56. assert.notEqual(orderRows[0].identityCode, orderRows[0].code)
  57. unavailable(orderRows[1], /工单主键/)
  58. const current = toCurrentEvents({ mode: 'WARNING', pagination: { page: 1, pageSize: 10, total: 2, totalPages: 1 }, sections: { events: { state: 'READY', data: [{ eventNo: 'W-1', eventName: '预警一' }, { eventNo: '', eventName: '无码预警' }] } } })
  59. const currentView = currentEventsView(current, current.sections.events)
  60. assert.equal(currentView.rows[0].identityCode, 'W-1')
  61. assert.equal(currentView.rows[0].identityFamily, 'WARNING')
  62. assert.equal(currentView.rows[1].identityCode, '')
  63. assert.match(currentView.rows[1].identityReason, /事件编号/)
  64. const eventPane = fs.readFileSync(new URL('../src/modules/cockpit/components/EventListPane.vue', import.meta.url), 'utf8')
  65. const warningPane = fs.readFileSync(new URL('../src/modules/cockpit/components/WarningResponsePane.vue', import.meta.url), 'utf8')
  66. assert.ok(eventPane.includes(':tabindex="canOpen(row) ? 0 : null"'))
  67. assert.ok(eventPane.includes('@click="canOpen(row) ? openEvent(row) : null"'))
  68. assert.ok(eventPane.includes(`:data-card-action="canOpen(row) ? 'event' : 'none'"`))
  69. assert.ok(warningPane.includes("if (action.kind === 'event')"))
  70. assert.ok(warningPane.includes("if (action.kind === 'work-order')"))
  71. assert.ok(warningPane.includes('const prefill = row.identityPayload || row'))
  72. console.log('t65-clickability-coverage: 32/32')