| | |
| | | |
| | | // 拦截构建产物和 API 完成页面验收,不启动业务服务或连接共享数据库。 |
| | | const origin = 'http://single-sheet-import.test' |
| | | const output = '../.scratch/simulator-and-data-import-v1/single-sheet-browser' |
| | | const output = '../.scratch/console-excel-field-alignment/browser' |
| | | await mkdir(output, { recursive: true }) |
| | | const browser = await chromium.launch({ channel: 'chrome', headless: true }) |
| | | const calls = [] |
| | |
| | | |
| | | function standardFile(type, invalid = false) { |
| | | const fields = consoleImportColumns[type] |
| | | const row = { recordNo: '17', batteryNo: 'BAT-1', recordedAt: '2023-05-08 11:42:11', cycleNo: 1, stepNo: 1, stepName: '恒流放电', sequenceId: 17, capacity: 8.5122, temperature: 25, positivePotential: 1.5, negativePotential: -0.1, chargeMedianVoltage: 0, dischargeMedianVoltage: 1.1709 } |
| | | const row = { recordNo: '17', batteryNo: 'BAT-1', recordedAt: '2023-05-08 11:42:11', cycleNo: 1, stepNo: 1, stepName: '恒流放电', sequenceId: 17, relativeTimeSeconds: '1:02:32.125', stepDuration: '1:02:32.125', capacity: 8.5122, temperature: 25, positivePotential: 1.5, negativePotential: -0.1, chargeMedianVoltage: 0, dischargeMedianVoltage: 1.1709 } |
| | | const rows = [Object.values(fields), Object.keys(fields).map(field => row[field] ?? '')] |
| | | if (invalid) { |
| | | while (rows.length < 19) rows.push([]) |
| | | rows.push(Object.keys(fields).map(field => field === 'cycleNo' ? 0 : row[field] ?? '')) |
| | | } |
| | | const workbook = XLSX.utils.book_new() |
| | | XLSX.utils.book_append_sheet(workbook, XLSX.utils.aoa_to_sheet(rows), { REALTIME: '实时', STEP: '工步', CYCLE: '循环' }[type]) |
| | | const workbook = createConsoleImportWorkbook(type) |
| | | workbook.Sheets[workbook.SheetNames[0]] = XLSX.utils.aoa_to_sheet(rows) |
| | | if (type !== 'REALTIME') XLSX.utils.sheet_add_aoa(workbook.Sheets.record, [Object.keys(consoleImportColumns.REALTIME).map(field => row[field] ?? '')], { origin: 'A2' }) |
| | | return { name: '单页数据.xlsx', mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', buffer: XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' }) } |
| | | } |
| | | |
| | |
| | | if (path.endsWith('/live-state')) { liveCalls.push(path); return route.fulfill({ json: { code: 200, data: { ...detail, sources: [], exceptions: [] } } }) } |
| | | if (/\/data\/(records|steps|cycles)$/.test(path)) { |
| | | const type = { records: 'REALTIME', steps: 'STEP', cycles: 'CYCLE' }[path.split('/').at(-1)] |
| | | const data = workbookRows?.[type]?.slice(0, 1).map(row => ({ ...row, recordId: 1, stepRecordId: 1, cycleRecordId: 1, stableIdentity: `${type.toLowerCase()}:1` })) || [] |
| | | const data = workbookRows?.[type]?.slice(0, 1).map(row => ({ ...row, sourceType: type === 'REALTIME' ? 'SNAPSHOT' : undefined, deviceTime: row.recordedAt, recordId: 1, stepRecordId: 1, cycleRecordId: 1, stableIdentity: `${type.toLowerCase()}:1` })) || [] |
| | | return route.fulfill({ json: { code: 200, data } }) |
| | | } |
| | | if (path.endsWith('/system/test/1')) return route.fulfill({ json: { code: 200, data: detail } }) |
| | |
| | | return route.fulfill({ body: await readFile('dist/index.html'), contentType: 'text/html' }) |
| | | }) |
| | | for (const type of ['REALTIME', 'STEP', 'CYCLE']) { |
| | | await page.setViewportSize({ width: 1440, height: 1000 }) |
| | | await page.goto(`${origin}/test-list/1/console?tab=data-list&dataType=${type}`) |
| | | const downloadEvent = page.waitForEvent('download') |
| | | await page.getByRole('button', { name: '下载模板', exact: true }).click() |
| | | const download = await downloadEvent |
| | | const workbook = XLSX.read(await readFile(await download.path())) |
| | | assert.equal(workbook.SheetNames.length, 1) |
| | | assert.equal(workbook.SheetNames.length, type === 'REALTIME' ? 1 : 2) |
| | | assert.deepEqual(XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { header: 1 })[0], Object.values(consoleImportColumns[type])) |
| | | await page.goto(`${origin}/test-list/1/console/data/import?dataType=${type}`) |
| | | await expect(page.locator('.status-notice')).toHaveCount(0) |
| | |
| | | await expect(page.locator('.table-wrap tbody')).toContainText('BAT-1') |
| | | await page.reload() |
| | | await expect(page.locator('.table-wrap tbody')).toContainText('BAT-1') |
| | | const expectedHeaders = ['记录编号', '电池', ...XLSX.utils.sheet_to_json(XLSX.readFile(process.env.PARTY_EXCEL || (await import('node:path')).resolve('../outputs/ticket03-excel/277#(5)(1)_补充三项测试值.xls')).Sheets[{ REALTIME: 'record', STEP: 'step', CYCLE: 'cycle' }[type]], { header: 1 })[0]] |
| | | assert.deepEqual((await page.locator('.table-wrap th').allTextContents()).map(value => value.trim()).slice(1, -1), expectedHeaders) |
| | | await expect(page.locator('.record-code').first()).toHaveText(type.toLowerCase() + ':1') |
| | | await page.screenshot({ path: `${output}/list-${type.toLowerCase()}-390.png`, fullPage: true }) |
| | | await page.setViewportSize({ width: 1440, height: 1000 }) |
| | | await page.screenshot({ path: `${output}/list-${type.toLowerCase()}.png`, fullPage: true, animations: 'disabled' }) |
| | | const downloadEvent = page.waitForEvent('download') |
| | | await page.getByRole('button', { name: '下载', exact: true }).click() |
| | | const csvText = await readFile(await (await downloadEvent).path(), 'utf8') |
| | | const csvRows = XLSX.utils.sheet_to_json(XLSX.read(csvText.replace(/^\uFEFF/, ''), { type: 'string', raw: true }).Sheets.Sheet1, { header: 1, raw: true }) |
| | | assert.deepEqual(csvRows[0], expectedHeaders) |
| | | assert.equal(csvRows[1][0], type.toLowerCase() + ':1') |
| | | if (type === 'REALTIME') { |
| | | assert.equal(csvRows[1][6], process.env.PARTY_EXCEL ? '0:00:00.000' : '1:02:32.125') |
| | | assert.match(csvRows[1][11], /^2023-05-08 11:42:11/) |
| | | } |
| | | if (type === 'STEP') { |
| | | assert.equal(csvRows[1][5], process.env.PARTY_EXCEL ? '1:02:32.000' : '1:02:32.125') |
| | | await expect(page.locator('.table-wrap thead')).toContainText('充电中值电压(V)') |
| | | await expect(page.locator('.table-wrap thead')).toContainText('放电中值电压(V)') |
| | | await expect(page.locator('.table-wrap tbody')).toContainText('0.0000') |
| | |
| | | assert.match(csv, /放电中值电压\(V\)/) |
| | | assert.match(csv, /"0\.0000","1\.1709"/) |
| | | assert.doesNotMatch(csv, /峰值|谷值/) |
| | | await page.locator('.row-actions').first().getByRole('button', { name: '编辑', exact: true }).click() |
| | | const durationInput = page.locator('.single-form-grid label').filter({ hasText: '工步时间(h:min:s.ms)' }).locator('input') |
| | | await expect(durationInput).toHaveValue(process.env.PARTY_EXCEL ? '1:02:32.000' : '1:02:32.125') |
| | | await durationInput.fill('1:02:33.250') |
| | | await page.locator('.remark-field textarea').fill('核对时长编辑与记录编号') |
| | | const edited = page.waitForResponse(response => response.url().endsWith('/console-data/actions')) |
| | | await page.getByRole('button', { name: '提交修改', exact: true }).click() |
| | | await edited |
| | | assert.equal(calls.at(-1).operationType, 'EDIT') |
| | | assert.deepEqual(JSON.parse(calls.at(-1).identitySummary), ['step:1']) |
| | | assert.deepEqual(JSON.parse(calls.at(-1).overrides[0].fieldValues), { stepDuration: '3753.25' }) |
| | | } |
| | | } |
| | | assert.deepEqual(errors, []) |