| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /**
- * T46 回归走查:不上图设备的设备级详情仍可见(票 46 交付后人工走查抓到的真缺陷)。
- *
- * ---- 缺陷背景(本脚本就是当时的复现环)----
- * 用户人工走查「重叠设备聚合与展开」(票 45)时用的是默认样例(动不了坐标场景):
- * 1. 设备统一 `UNVERIFIED_COORDINATE/renderable=false` → `no-location` → **地图上没有设备图标**
- * —— 这是票 42 照抄的现网正式边界,**不是缺陷**(要看到图标需注入 `device-layer-overlap` 场景);
- * 2. 点监测点点位摘要里的**设备卡片** → 摘要面板**直接消失** —— 这是**真缺陷**:
- * `domain/modeLayerPlan.js` 的 `selectionVisible()` 对设备级选择要求
- * `row.placement === 'drawn'`,而 `no-location` 设备不满足 ⇒ 外壳
- * `<aside v-if="… selectionVisibleInMode">` 卸载 ⇒ 面板消失。
- * 设备级详情(档案/指标/预警等分区)与该设备能否上图**无关**:一台无地图位置的设备
- * 仍要看它的详情分区。修复:设备级选择只要在 `associatedDevices` 里找到该设备行,
- * 就按**模式可见性**判(预警处置只显示报警/预警),不再要求 `placement === 'drawn'`。
- *
- * ---- 本脚本断言 ----
- * 1. 默认样例(success)选中 MP-001:设备清单里有 EQ-001,且 placement=no-location;
- * 2. 真实鼠标点击 EQ-001 设备卡片(与用户相同的操作路径);
- * 3. 断言摘要浮层**仍在**(aside 存在、尺寸正常),且已进入设备级
- * (`detailLevel=equipment`、`deviceCode=EQ-001`、`data-selection-paused='no'`);
- * 4. 无页面级报错。
- */
- import { cdpLaunch } from './cdp-driver.mjs'
- const BASE = process.env.COCKPIT_BASE || 'http://localhost:8000'
- const ENTRY_URL = process.env.COCKPIT_URL || `${BASE}/#/cockpit`
- const CHROME = process.env.CHROME_PATH || 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
- // 默认样例(success)= 现网正式边界:设备坐标统一 renderable=false。
- const SCENARIO = 'success'
- const results = []
- function check(id, pass, evidence) {
- results.push({ id, pass })
- console.log(`${pass ? 'PASS' : 'FAIL'} ${id} :: ${evidence === undefined ? '' : String(evidence)}`)
- }
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
- const browser = await cdpLaunch({ executablePath: CHROME, width: 1680, height: 950 })
- console.log(`Chrome: ${await browser.version()}`)
- const page = await browser.newPage()
- const errors = []
- page.on('pageerror', (e) => errors.push(String(e && e.message ? e.message : e)))
- page.on('console', (m) => {
- if (m.type() === 'error') errors.push(`console.error: ${m.text()}`)
- })
- await page.evaluateOnNewDocument((name) => {
- window.__COCKPIT_MOCK_SCENARIO__ = name
- }, SCENARIO)
- await page.goto(ENTRY_URL, { timeout: 60000 })
- await page.waitForSelector('.cockpit-shell', { timeout: 20000 })
- if (await page.$('[data-cockpit-intro]')) {
- await page.click('[data-cockpit-intro]')
- await page.waitForSelector('[data-cockpit-intro]', { hidden: true, timeout: 10000 }).catch(() => {})
- }
- await page.waitForFunction(
- () => ['ready', 'failed', 'disabled'].includes(document.querySelector('.cockpit-shell__map .map-canvas')?.dataset.mapEngine),
- { timeout: 40000 },
- ).catch(() => {})
- // 推进地图摘要到 complete。
- await page.evaluate(() => {
- const dev = window.__cockpitMap
- if (!dev || !dev.mapSummary) return
- let steps = 0
- const step = () => {
- const state = dev.mapSummary.getState()
- if (!state || ['complete', 'empty', 'failed', 'expired'].includes(state.phase) || steps >= 20) return
- dev.mapSummary.advance()
- steps += 1
- window.setTimeout(step, 220)
- }
- step()
- })
- await page.waitForFunction(() => {
- const dev = window.__cockpitMap
- const state = dev && dev.mapSummary ? dev.mapSummary.getState() : null
- return !state || ['complete', 'empty', 'failed', 'expired'].includes(state.phase)
- }, { timeout: 20000 }).catch(() => {})
- // 统一选择入口打开 MP-001 点位摘要(与地图点选/台账同一用户路径)。
- await page.evaluate(() => window.__cockpitMap && window.__cockpitMap.selectMonitoringPoint && window.__cockpitMap.selectMonitoringPoint('MP-001'))
- await page.waitForSelector('[data-device-card]', { timeout: 20000 }).catch(() => {})
- await sleep(2500)
- const snapshot = () => page.evaluate(() => {
- const aside = document.querySelector('.cockpit-shell__detail')
- const card = document.querySelector('[data-point-detail]')
- const rows = [...document.querySelectorAll('[data-device-layer-row]')].map((n) => ({
- code: n.dataset.deviceLayerCode,
- placement: n.dataset.deviceLayerRow,
- }))
- const host = document.querySelector('.cockpit-shell__map .map-canvas')
- return {
- asidePresent: !!aside,
- asideRect: aside ? (() => { const r = aside.getBoundingClientRect(); return { w: Math.round(r.width), h: Math.round(r.height), left: Math.round(r.left), top: Math.round(r.top) } })() : null,
- detailLevel: card ? card.dataset.detailLevel : '',
- pointCode: card ? card.dataset.pointCode : '',
- deviceCode: card ? card.dataset.deviceCode : '',
- selectionPaused: aside ? aside.dataset.selectionPaused : '',
- deviceRows: rows,
- mapDevices: host && host.dataset.mapDevices,
- }
- })
- const before = await snapshot()
- // 断言默认样例下设备确实不上图(现网正式边界;这是复现缺陷的前置条件,不是本轮测缺陷)。
- const noLocationRow = before.deviceRows.find((r) => r.code === 'EQ-001')
- check('R1-production-boundary-no-location',
- Boolean(noLocationRow) && noLocationRow.placement === 'no-location' && before.mapDevices === '0',
- `默认样例 EQ-001 placement=${noLocationRow && noLocationRow.placement}、地图设备数 ${before.mapDevices}(现网正式边界:不上图仅清单)`)
- check('R2-point-summary-open', before.asidePresent && before.detailLevel === 'point',
- `点位摘要打开:detailLevel=${before.detailLevel}、aside w=${before.asideRect && before.asideRect.w} h=${before.asideRect && before.asideRect.h}`)
- // 真实鼠标点击 EQ-001 设备卡片(与用户相同的操作路径)。
- const cardRect = await page.evaluate((code) => {
- const el = document.querySelector(`[data-device-card][data-device-code="${code}"]`)
- if (!el) return null
- const r = el.getBoundingClientRect()
- return { x: r.left + r.width / 2, y: r.top + r.height / 2, w: Math.round(r.width), h: Math.round(r.height) }
- }, 'EQ-001')
- check('R3-device-card-found', Boolean(cardRect), `设备卡片 EQ-001 存在(rect w=${cardRect && cardRect.w} h=${cardRect && cardRect.h})`)
- if (cardRect) {
- await page.mouse.move(cardRect.x, cardRect.y)
- await sleep(200)
- await page.mouse.click(cardRect.x, cardRect.y)
- }
- await sleep(2500)
- const after = await snapshot()
- check('R4-detail-panel-still-visible',
- after.asidePresent &&
- after.detailLevel === 'equipment' &&
- after.deviceCode === 'EQ-001' &&
- after.selectionPaused === 'no' &&
- after.asideRect && after.asideRect.w > 0 && after.asideRect.h > 0,
- `点设备卡片后面板仍在(aside=${after.asidePresent}、detailLevel=${after.detailLevel}、deviceCode=${after.deviceCode}、selectionPaused=${after.selectionPaused}、w=${after.asideRect && after.asideRect.w} h=${after.asideRect && after.asideRect.h})`)
- check('R5-no-page-errors', errors.length === 0, errors.length ? errors.slice(0, 3).join(' | ') : '无 pageerror / console.error')
- await page.close()
- await browser.close()
- const failed = results.filter((r) => !r.pass)
- console.log('')
- console.log(`T46 回归走查(不上图设备详情可见):${results.length - failed.length}/${results.length} 项通过。`)
- if (failed.length) {
- console.log('未通过:')
- for (const r of failed) console.log(` · ${r.id}`)
- process.exit(1)
- }
- console.log('T46 回归走查全部通过。')
|