From 6b545ef2dba5618cd04f24fb8c9ec3732a395998 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 20:07:27 +0800
Subject: [PATCH] 验证模拟器通道编辑与控制台工步方案展示
---
tests/test-simulator-observation-browser.mjs | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/tests/test-simulator-observation-browser.mjs b/tests/test-simulator-observation-browser.mjs
index de91a4f..a864c52 100644
--- a/tests/test-simulator-observation-browser.mjs
+++ b/tests/test-simulator-observation-browser.mjs
@@ -15,7 +15,11 @@
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' }] }],
+ channels: [1, 2].map(channelId => ({ channelId, online: true, workStatus: 'WORKING', configuration: {
+ currentA: 0, voltageV: 3.7, capacityAh: 1.2, energyWh: 4.44, cycleNo: 1, stepNo: 1,
+ plannedCycleCount: 1, totalTimeSeconds: 0, relativeTimeSeconds: 0,
+ steps: [{ name: '恒流充电', stepType: 'cc', durationSeconds: 60, voltageV: 3.7 }],
+ } })) }],
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',
@@ -25,6 +29,7 @@
}
const calls = []
let failSoftware = false
+ let failConfiguration = false
await page.route('http://simulator.test/**', async route => {
const request = route.request()
const path = new URL(request.url()).pathname
@@ -34,13 +39,71 @@
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('/devices/1/channels/1/configuration')) {
+ if (failConfiguration) return route.fulfill({ status: 503, json: { message: '配置保存失败' } })
+ state.devices[0].channels[0].configuration = body
+ }
+ else if (path.endsWith('/devices/1/channels/1')) Object.assign(state.devices[0].channels[0], body)
else if (path.endsWith('/collectors/1/channels/S-01/status')) state.collectors[0].channels[0].workStatus = body.workStatus
+ else if (path.endsWith('/collectors/1/channels/S-01')) state.collectors[0].channels[0].metrics = body.metrics
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 page.locator('#devices').getByRole('button', { name: '参数与方案' }).first().click()
+ const editor = page.getByRole('dialog')
+ await editor.getByLabel('电压 (V)', { exact: true }).fill('4.125')
+ await editor.getByLabel('电流 (A)').fill('-2.5')
+ await editor.getByRole('button', { name: '添加工步' }).click()
+ await editor.getByLabel('工步名称', { exact: true }).last().fill('放电测试')
+ await editor.getByLabel('工步类型').last().selectOption('dc')
+ await editor.getByLabel('时长 (s)', { exact: true }).last().fill('90')
+ await editor.getByLabel('当前工步').fill('2')
+ await editor.getByLabel('计划循环数').fill('3')
+ await page.clock.install()
+ await page.clock.fastForward(5000)
+ await expect(editor.getByLabel('电压 (V)', { exact: true })).toHaveValue('4.125')
+ await editor.screenshot({ path: output + '/channel-editor.png' })
+ await editor.getByRole('button', { name: '保存通道配置' }).click()
+ await expect(editor).not.toBeVisible()
+ assert.equal(state.devices[0].channels[0].configuration.voltageV, 4.125)
+ assert.equal(state.devices[0].channels[0].configuration.steps[1].name, '放电测试')
+ assert.equal(state.devices[0].channels[1].configuration.voltageV, 3.7)
+ await page.reload()
+ await page.locator('#devices').getByRole('button', { name: '参数与方案' }).first().click()
+ await expect(editor.getByLabel('当前工步')).toHaveValue('2')
+ await expect(editor.getByLabel('工步名称', { exact: true }).last()).toHaveValue('放电测试')
+ await editor.getByRole('button', { name: '上移工步', exact: true }).last().click()
+ await expect(editor.getByLabel('工步名称', { exact: true }).first()).toHaveValue('放电测试')
+ await editor.getByRole('button', { name: '下移工步', exact: true }).first().click()
+ await editor.getByRole('button', { name: '添加工步' }).click()
+ await editor.getByRole('button', { name: '删除工步', exact: true }).last().click()
+ await expect(editor.getByLabel('工步名称', { exact: true })).toHaveCount(2)
+ failConfiguration = true
+ await editor.getByLabel('电压 (V)', { exact: true }).fill('4.2')
+ await editor.getByRole('button', { name: '保存通道配置' }).click()
+ await expect(editor.getByRole('alert')).toContainText('配置保存失败')
+ await expect(editor.getByLabel('电压 (V)', { exact: true })).toHaveValue('4.2')
+ failConfiguration = false
+ await page.setViewportSize({ width: 390, height: 844 })
+ assert.equal(await editor.evaluate(element => element.scrollWidth > element.clientWidth), false)
+ await editor.screenshot({ path: output + '/channel-editor-390.png' })
+ await editor.getByRole('button', { name: '取消' }).click()
+ await page.setViewportSize({ width: 1440, height: 1000 })
+ await page.locator('#collectors').getByRole('button', { name: '编辑测量值' }).click()
+ await editor.getByLabel('数值', { exact: true }).first().fill('32.75')
+ await editor.getByRole('button', { name: '添加测量项' }).click()
+ await editor.getByLabel('测量项', { exact: true }).last().selectOption('negative_potential')
+ await editor.getByLabel('数值', { exact: true }).last().fill('-0.15')
+ await editor.screenshot({ path: output + '/collector-editor.png' })
+ await editor.getByRole('button', { name: '保存通道配置' }).click()
+ await expect(editor).not.toBeVisible()
+ assert.equal(state.collectors[0].channels[0].metrics[0].value, 32.75)
+ assert.equal(state.collectors[0].channels[0].metrics[1].value, -0.15)
+ await page.reload()
+ await expect(page.locator('#collectors')).toContainText('温度 32.75 ℃')
+ await expect(page.locator('#collectors')).toContainText('负电位 -0.15 V')
await expect(page.getByLabel('新威软件可访问')).toBeChecked()
await page.getByLabel('新威软件可访问').uncheck()
await expect(page.getByLabel('新威软件可访问')).not.toBeChecked()
@@ -70,7 +133,42 @@
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 布局通过。')
+ const consolePage = await browser.newPage({ viewport: { width: 1440, height: 1000 } })
+ consolePage.on('pageerror', error => errors.push(error.message))
+ await consolePage.addInitScript(() => localStorage.setItem('battery_detection_auth_token', 'browser-test'))
+ const config = state.devices[0].channels[0].configuration
+ const detail = { testId: 1, testName: '通道方案验收', testStatus: 'RUNNING', receptionStatus: 'RECEIVING',
+ creatorName: '若依', principalName: '若依', testTypeName: '性能测试', testPurpose: '方案观测',
+ thresholds: [], batteries: [], planSteps: [], logicStepMappings: [] }
+ const live = { testId: 1, testStatus: 'RUNNING', receptionStatus: 'RECEIVING', serverTime: Date.now(), sources: [], exceptions: [],
+ testPlan: { currentCycleNo: config.cycleNo, currentStepNo: config.stepNo, plannedCycleCount: config.plannedCycleCount,
+ rows: config.steps.map((step, index) => ({ rowType: 'STEP', stepNo: index + 1, cyclePosition: index + 1,
+ stepName: step.name, durationSeconds: step.durationSeconds, voltageV: step.voltageV,
+ executionStatus: index === 1 ? '进行中' : '已完成' })) } }
+ await consolePage.addInitScript(state => {
+ const fetch = window.fetch.bind(window)
+ window.fetch = (input, init) => String(input).endsWith('/test/1/live')
+ ? Promise.resolve(new Response(new ReadableStream({ start(controller) {
+ controller.enqueue(new TextEncoder().encode(`event: snapshot\ndata: ${JSON.stringify(state)}\n\n`))
+ } }), { headers: { 'Content-Type': 'text/event-stream' } })) : fetch(input, init)
+ }, live)
+ await consolePage.route('http://simulator-console.test/**', async route => {
+ const path = new URL(route.request().url()).pathname
+ if (path.startsWith('/assets/')) return route.fulfill({ body: await readFile(`dist${path}`), contentType: path.endsWith('.css') ? 'text/css' : 'application/javascript' })
+ if (path.endsWith('/test/1/live')) return route.fulfill({ contentType: 'text/event-stream', body: `event: snapshot\ndata: ${JSON.stringify(live)}\n\n` })
+ if (path.includes('/system/test/1')) return route.fulfill({ json: { code: 200, data: path.endsWith('/live-state') ? live : detail } })
+ if (path.endsWith('/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') })
+ })
+ await consolePage.goto('http://simulator-console.test/test-list/1/console')
+ const plan = consolePage.locator('.step-panel')
+ await expect(plan).toContainText('放电测试')
+ await expect(plan).toContainText('恒流充电')
+ await expect(plan).toContainText('进行中')
+ await expect(plan).not.toContainText('暂无后端')
+ await plan.screenshot({ path: output + '/console-plan.png' })
+ assert.deepEqual(errors, [])
+ console.log('模拟器页面:逐通道参数、工步增删排序、采集器数值、刷新保留、编辑防覆盖、保存失败及 1440/768/390 布局通过。')
} finally {
await browser.close()
}
--
Gitblit v1.7.1