yeg
2026-09-05 3439cace9d2674bc5a7874503df4fe9c1d1495b1
补充模拟器观测边界浏览器验证

验证软件可访问性、设备在线及通道状态操作、刷新和错误提示,检查桌面与窄屏布局。复用实际静态页面并拦截接口响应,无需启动业务服务。
1个文件已添加
76 ■■■■■ 已修改文件
tests/test-simulator-observation-browser.mjs 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tests/test-simulator-observation-browser.mjs
New file
@@ -0,0 +1,76 @@
import assert from 'node:assert/strict'
import { readFile, mkdir } from 'node:fs/promises'
import { chromium, expect } from '@playwright/test'
// 使用实际模拟器页面与拦截响应验证交互,不启动业务服务。
const html = await readFile('../BatteryDetection/ruoyi-admin/src/main/resources/static/dev/bts-simulator.html', 'utf8')
const output = '../.scratch/simulator-and-data-import-v1/browser'
await mkdir(output, { recursive: true })
const browser = await chromium.launch({ channel: 'chrome', headless: true })
try {
  const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } })
  const errors = []
  page.on('pageerror', error => errors.push(error.message))
  const state = {
    running: true, softwareAccessible: true, listenAddress: '127.0.0.1:15020',
    devices: [{ deviceId: 1, ip: '127.0.0.2', online: true,
      profile: { devtype: 22, subDeviceId: 1, model: 'BTS Virtual Cabinet' },
      channels: [{ channelId: 1, online: true, workStatus: 'WORKING' }] }],
    collectors: [{ collectorId: 1, deviceCode: 'dev-sim-collector-1', mac: '02:43:00:00:00:01',
      name: 'dev-sim 采集器 1', ip: '127.0.1.2', online: true, channelCount: 1,
      channels: [{ channelCode: 'S-01', workStatus: 'WORKING',
        metrics: [{ metricCode: 'temperature', value: 25.1, unit: '℃' }] }], latestMeasurements: [] }],
    recentRequests: [{ receivedAt: Date.now(), command: 'inquire', request: '<bts><cmd>inquire</cmd></bts>',
      response: '<inquire voltage="3.700" />' }],
  }
  const calls = []
  let failSoftware = false
  await page.route('http://simulator.test/**', async route => {
    const request = route.request()
    const path = new URL(request.url()).pathname
    if (path === '/dev/bts-simulator.html') return route.fulfill({ contentType: 'text/html', body: html })
    const body = request.postDataJSON()
    calls.push({ path, method: request.method(), body })
    if (path.endsWith('/software')) {
      if (failSoftware) return route.fulfill({ status: 503, json: { message: '保存失败' } })
      state.softwareAccessible = body.accessible
    } else if (path.endsWith('/devices/1/channels/1')) state.devices[0].channels[0] = { channelId: 1, ...body }
    else if (path.endsWith('/collectors/1/channels/S-01/status')) state.collectors[0].channels[0].workStatus = body.workStatus
    else if (path.endsWith('/devices/1')) Object.assign(state.devices[0], body)
    else if (path.endsWith('/collectors/1')) Object.assign(state.collectors[0], body)
    return route.fulfill({ json: state })
  })
  await page.goto('http://simulator.test/dev/bts-simulator.html')
  await expect(page.getByLabel('新威软件可访问')).toBeChecked()
  await page.getByLabel('新威软件可访问').uncheck()
  await expect(page.getByLabel('新威软件可访问')).not.toBeChecked()
  assert.equal(state.devices[0].online, true)
  await page.getByLabel('检测柜 1 通道 1 工作状态').selectOption('PROTECTED')
  await expect(page.getByLabel('检测柜 1 通道 1 工作状态')).toHaveValue('PROTECTED')
  await page.getByLabel('S-01 工作状态').selectOption('UNOBSERVABLE')
  await expect(page.getByLabel('S-01 工作状态')).toHaveValue('UNOBSERVABLE')
  await page.locator('#devices').getByLabel('整机在线').uncheck()
  await page.locator('#devices').getByRole('button', { name: '保存配置' }).click()
  await expect(page.locator('#devices').getByLabel('整机离线')).not.toBeChecked()
  await page.reload()
  await expect(page.getByLabel('检测柜 1 通道 1 工作状态')).toHaveValue('PROTECTED')
  await expect(page.getByLabel('新威软件可访问')).not.toBeChecked()
  await expect(page.locator('#requests')).toContainText('voltage="3.700"')
  await expect(page.getByText('600x', { exact: true })).toHaveCount(0)
  await expect(page.getByRole('button', { name: '下载历史' })).toHaveCount(0)
  await page.screenshot({ path: output + '/desktop.png', fullPage: true })
  for (const width of [390, 768]) {
    await page.setViewportSize({ width, height: 844 })
    assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth), false)
    await page.screenshot({ path: output + '/width-' + width + '.png', fullPage: true })
  }
  failSoftware = true
  await page.getByLabel('新威软件可访问').check()
  await expect(page.locator('#error')).toContainText('保存失败')
  assert.deepEqual(errors, [])
  assert.ok(calls.some(call => call.path.endsWith('/software') && call.method === 'PUT'))
  assert.ok(calls.every(call => !/playback|sampling|history/.test(call.path)))
  console.log('模拟器页面:软件、设备、通道、刷新、失败提示及 1440/768/390 布局通过。')
} finally {
  await browser.close()
}