yeg
2026-09-28 6a4ca47df73d99e952d926f6103bcccea1ecea89
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import assert from 'node:assert/strict'
import { readFile, mkdir } from 'node:fs/promises'
import { resolve } from 'node:path'
import { chromium, expect } from '@playwright/test'
 
// 读取真实构建产物并拦截 API,不启动服务或写入开发数据库。
const output = '../.scratch/simulator-and-data-import-v1/related-tests-browser'
await mkdir(output, { recursive: true })
const origin = 'http://device-relations.test'
const browser = await chromium.launch({ channel: 'chrome', headless: true })
const relatedTests = [
  { testId: 1, testName: '低温循环测试', testStatus: 'WAITING', channels: ['1-1', '1-2'] },
  { testId: 2, testName: '正在接收的测试', testStatus: 'RUNNING', channels: ['1-3'] },
  { testId: 3, testName: '暂停接收的测试', testStatus: 'PAUSED', channels: ['1-4'] },
  { testId: 4, testName: '已结束的长名称测试用于验证弹窗内容换行和窄屏布局', testStatus: 'COMPLETED', channels: ['2-1', '2-2', '2-3'] },
]
const devices = (kind) => [[], [relatedTests[0]], relatedTests].map((tests, index) => ({
  [`${kind}Id`]: index + 1, [`${kind}Code`]: `${kind}-${index + 1}`, [`${kind}Name`]: `设备 ${index + 1}`,
  ipAddress: '127.0.0.2', macAddress: '02:44:00:10:00:01', manufacturer: '开发模拟器', model: 'Virtual',
  channelCount: 8, capacity: 1, onlineStatus: kind === 'cabinet' ? '0' : '1', status: '0',
  relatedTests: kind === 'cabinet' ? tests : tests.map(test => ({ ...test, channels: ['S-01', 'S-02'] })),
}))
 
try {
  const page = await browser.newPage({ viewport: { width: 1920, height: 1000 } })
  const errors = []
  let responseMode = 'normal'
  page.on('pageerror', error => errors.push(error.message))
  await page.addInitScript(() => localStorage.setItem('battery_detection_auth_token', 'browser-test'))
  await page.route(`${origin}/**`, async route => {
    const url = new URL(route.request().url())
    const path = url.pathname
    if (path.startsWith('/assets/')) {
      const body = await readFile(resolve('dist', path.slice(1)))
      return route.fulfill({ body, contentType: path.endsWith('.css') ? 'text/css' : 'application/javascript' })
    }
    if (path.includes('/system/')) {
      if (path.includes('/system/test/')) return route.fulfill({ json: { code: 404, msg: '测试控制台响应未纳入设备页面夹具' } })
      const kind = path.includes('/detectionCabinet') ? 'cabinet' : 'collector'
      if (responseMode === 'error') return route.fulfill({ status: 500, json: { code: 500, msg: '设备查询失败' } })
      if (responseMode === 'forbidden') return route.fulfill({ json: { code: 403, msg: '没有设备查询权限' } })
      if (path.endsWith('/list')) {
        assert.equal(url.searchParams.has('testStatus'), false)
        const rows = responseMode === 'empty' ? [] : devices(kind)
        return route.fulfill({ json: { code: 200, rows, total: rows.length } })
      }
      return route.fulfill({ json: { code: 200, data: devices(kind)[2] } })
    }
    if (path.includes('/getInfo')) return route.fulfill({ json: { code: 200, user: { userName: 'admin' }, roles: ['admin'] } })
    return route.fulfill({ contentType: 'text/html', body: await readFile('dist/index.html', 'utf8') })
  })
  const kinds = process.argv[2] ? [process.argv[2]] : ['cabinet', 'collector']
  for (const kind of kinds) {
    const listUrl = `${origin}/device-${kind}`
    await page.goto(listUrl)
    const table = page.locator('.result-panel table')
    await expect(table.locator('tbody tr')).toHaveCount(3)
    await expect(table.getByRole('columnheader', { name: '关联测试' })).toBeVisible()
    await expect(table.getByRole('columnheader', { name: '测试状态', exact: true })).toHaveCount(0)
    await expect(page.getByText('当前测试', { exact: true })).toHaveCount(0)
    const cellIndex = kind === 'cabinet' ? 10 : 9
    await expect(table.locator('tbody tr').nth(0).locator('td').nth(cellIndex)).toHaveText('-')
    await expect(table.getByRole('link', { name: '低温循环测试' })).toHaveAttribute('href', '/test-list/1/console')
    await page.screenshot({ path: `${output}/${kind}-list.png`, fullPage: true })
    for (const width of [1920, 768, 390]) {
      await page.setViewportSize({ width, height: 900 })
      await table.getByRole('button', { name: '4 项测试' }).click()
      const dialog = page.getByRole('dialog', { name: '关联测试' })
      await expect(dialog).toBeVisible()
      await expect(dialog).toHaveCSS('opacity', '1')
      await expect(dialog).toHaveCSS('transform', 'none')
      await expect(dialog.locator('tbody tr')).toHaveCount(4)
      for (const state of ['待测试', '检测中', '暂停', '检测完成']) await expect(dialog.getByRole('cell', { name: state, exact: true })).toBeVisible()
      await expect(dialog.locator('tbody tr').first()).toContainText(kind === 'cabinet' ? '1-1、1-2' : 'S-01、S-02')
      const box = await dialog.boundingBox()
      assert.ok(box && box.x >= 0 && box.x + box.width <= width && box.y >= 0 && box.y + box.height <= 900, JSON.stringify({ width, box }))
      assert.equal(await dialog.evaluate(element => element.scrollWidth > element.clientWidth), false)
      await page.screenshot({ path: `${output}/${kind}-${width}.png`, fullPage: true, animations: 'disabled' })
      await dialog.getByRole('button', { name: /关闭|Close/ }).click()
      await expect(dialog).not.toBeVisible()
    }
    await page.setViewportSize({ width: 1920, height: 1000 })
    await table.getByRole('link', { name: '低温循环测试' }).click()
    await expect(page).toHaveURL(`${origin}/test-list/1/console`)
    await page.goto(listUrl)
    await table.getByRole('button', { name: '4 项测试' }).click()
    await page.getByRole('dialog', { name: '关联测试' }).getByRole('link', { name: '暂停接收的测试' }).click()
    await expect(page).toHaveURL(`${origin}/test-list/3/console`)
    await page.goto(listUrl)
    await page.reload()
    await expect(table.getByRole('button', { name: '4 项测试' })).toBeVisible()
    await page.goto(`${listUrl}/3/edit`)
    await expect(page.locator('.device-summary').getByRole('button', { name: '4 项测试' })).toBeVisible()
    await expect(page.locator('.device-summary').getByText('测试状态', { exact: true })).toHaveCount(0)
    for (const mode of ['empty', 'error', 'forbidden']) {
      responseMode = mode
      await page.goto(listUrl)
      await expect(table).not.toContainText('4 项测试')
      await expect(table).toContainText('暂无符合条件')
      if (mode === 'error') await expect(page.getByText('设备查询失败', { exact: true })).toBeVisible()
      if (mode === 'forbidden') await expect(page.getByText('没有设备查询权限', { exact: true })).toBeVisible()
    }
    responseMode = 'normal'
  }
  assert.deepEqual(errors, [])
  console.log(`关联测试浏览器验证通过:${kinds.join('、')};空值、单项链接、多项展开、状态、通道、刷新、编辑、错误及 1920/768/390 布局。`)
} finally {
  await browser.close()
}