Files
shanxia2.0/web-admin/scripts/test-manual-dispatch-calendar.mjs
T

253 lines
10 KiB
JavaScript

import assert from 'node:assert/strict'
import { chromium } from 'playwright'
const browser = await chromium.launch({ headless: true, channel: 'chrome' })
try {
for (const mobile of [false, true]) {
const context = await browser.newContext({
permissions: ['clipboard-read', 'clipboard-write'],
viewport: mobile ? { width: 375, height: 812 } : { width: 1440, height: 1000 }
})
const page = await context.newPage()
await page.clock.setFixedTime(new Date('2026-10-26T04:00:00Z'))
page.setDefaultTimeout(20000)
page.on('console', (msg) => {
if (msg.type() === 'error') console.log('CONSOLE', msg.text())
})
page.on('requestfailed', (r) => console.log('FAILED', r.url(), r.failure()))
const errors = []
page.on('pageerror', (e) => errors.push(e.message))
let rows = []
let writes = 0
let failSave = false
let allowManage = true
let failLoad = false
await context.addInitScript(() => {
localStorage.setItem(
'sys-v3.0.2-user',
JSON.stringify({
isLogin: true,
accessToken: 'fixture',
info: {
id: 'fixture',
userId: 'fixture',
userName: '测试',
role: 'admin',
roles: ['admin']
}
})
)
localStorage.setItem('sys-version', '3.0.2')
})
await context.route('**/api/**', async (route) => {
const req = route.request(),
url = new URL(req.url()),
path = url.pathname.slice(4)
if (!url.pathname.startsWith('/api/')) return route.continue()
const user = {
id: 'fixture',
userId: 'fixture',
userName: '测试',
role: 'admin',
roles: ['admin']
}
if (path === '/web/auth/mp-webview-exchange')
return route.fulfill({
json: {
code: 200,
data: { token: 'fixture', refreshToken: 'refresh', expiresIn: 3600, userInfo: user }
}
})
if (path === '/web/auth/current-user')
return route.fulfill({ json: { code: 200, data: user } })
if (path === '/web/auth/menu-codes')
return route.fulfill({
json: {
code: 200,
data: {
all: false,
menuCodes: [
'pl:dispatch-calendar:list',
'mini:pl:dispatch-calendar:list',
...(allowManage ? ['pl:dispatch-calendar:manage'] : [])
]
}
}
})
if (path === '/transport/dispatch-calendar/vehicles')
return route.fulfill({
json: {
list: [
{ id: 'v1', licensePlate: '皖H12345' },
{ id: 'v2', licensePlate: '皖H54321' }
],
total: 2
}
})
if (path === '/transport/dispatch-calendar/products')
return route.fulfill({ json: { list: [{ id: 'p1', productName: '液碱' }], total: 1 } })
if (path.startsWith('/transport/dispatch-calendar')) {
if (req.method() === 'POST' || req.method() === 'PUT') {
writes++
if (failSave) {
failSave = false
return route.fulfill({ status: 500, json: { detail: 'fixture' } })
}
const body = req.postDataJSON(),
id = req.method() === 'PUT' ? path.split('/').pop() : String(writes)
const row = { ...body, id, licensePlate: '皖H12345', productName: '液碱' }
rows = rows.filter((r) => r.id !== id).concat(row)
return route.fulfill({ json: row })
}
if (req.method() === 'DELETE') {
rows = rows.filter((r) => r.id !== path.split('/').pop())
return route.fulfill({ json: { deleted: 1 } })
}
if (failLoad) {
failLoad = false
return route.fulfill({ status: 500, json: { detail: 'expected load failure' } })
}
const list = rows.filter((r) => r.dispatchDate.startsWith(url.searchParams.get('month')))
return route.fulfill({ json: { list, total: list.length } })
}
if (path === '/transport/plan/') return route.fulfill({ json: { list: [], total: 0 } })
return route.fulfill({
json: {
code: 200,
data: path.includes('favorites') || path.includes('upgrade-logs') ? [] : {}
}
})
})
await page.goto(
`http://localhost:3006/#/${mobile ? 'm/pl/dispatch-calendar?mpTicket=manual-test' : 'pl/calendar-module/dispatch-calendar'}`
)
await page
.getByRole('tab', { name: '派车日历', exact: true })
.waitFor()
.catch(async (e) => {
console.log('PAGE', await page.locator('body').innerText(), errors)
throw e
})
if (mobile) {
await page.getByLabel('查看月份', { exact: true }).click()
const popup = page.locator('.mp-calendar-date-picker:visible')
await popup.locator('.van-picker-column').nth(1).getByText('09', { exact: true }).click()
await popup.getByRole('button', { name: '确认', exact: true }).click()
} else {
await page.getByRole('button', { name: '上月', exact: true }).click()
}
await page.getByRole('button', { name: '今天', exact: true }).click()
await page.locator('[data-date="2026-10-26"].selected').waitFor()
if (mobile) {
const size = await page.getByRole('button', { name: '今天', exact: true }).boundingBox()
assert.ok(size.height >= 44)
assert.equal(
await page.locator('.mp-calendar-month-row').evaluate((el) => getComputedStyle(el).display),
'grid'
)
}
await page
.getByRole('button', {
name: '新增2026-10-26派车计划',
exact: true
})
.click({ timeout: 10000 })
const editor = page.locator('[data-testid="manual-editor"]:visible')
if (mobile) {
await editor.getByPlaceholder('选择车辆').click()
await page
.getByRole('button', { name: '皖H12345', exact: true })
.click({ timeout: 8000 })
.catch(async (e) => {
console.log('PICKER', await page.locator('.mp-manual-sheet:visible').allTextContents())
await page.screenshot({ path: '/tmp/manual-calendar-picker-debug.png' })
throw e
})
await editor.getByPlaceholder('选择产品').click()
await page.getByRole('button', { name: '液碱', exact: true }).click()
} else {
await editor.getByRole('combobox', { name: '车牌号', exact: true }).click()
await page.getByRole('option', { name: '皖H12345', exact: true }).click()
await editor.getByRole('combobox', { name: '产品名称', exact: true }).click()
await page.getByRole('option', { name: '液碱', exact: true }).click()
}
await editor.getByPlaceholder('请输入始发地').fill('山峡')
await editor.getByPlaceholder('请输入目的地').fill('云栋')
failSave = true
await editor.getByRole('button', { name: '保存', exact: true }).click()
await editor.getByText('保存失败,请检查填写内容或权限后重试').waitFor()
assert.equal(await editor.getByPlaceholder('请输入始发地').inputValue(), '山峡')
await editor.getByRole('button', { name: '保存', exact: true }).click()
await editor.waitFor({ state: 'hidden' })
assert.equal(rows.length, 1)
const card = page.locator('[data-testid="manual-record"]').first()
await card.waitFor()
await page.screenshot({
path: `/tmp/manual-calendar-${mobile ? 'mobile' : 'web'}.png`,
fullPage: false
})
assert.match(await card.innerText(), /山峡 → 云栋/)
await page
.locator('[data-date="2026-10-26"]')
.getByRole('button', { name: mobile ? '复制' : '复制2026-10-26派车计划', exact: true })
.click()
assert.match(
await page.evaluate(() => navigator.clipboard.readText()),
/皖H12345.*液碱.*山峡 → 云栋/
)
await card.click()
await page.getByRole('button', { name: '编辑', exact: true }).click()
await editor.getByPlaceholder('请输入目的地').fill('安庆')
await editor.getByRole('button', { name: '保存', exact: true }).click()
await editor.waitFor({ state: 'hidden' })
await page.getByText('山峡 → 安庆', { exact: true }).first().waitFor()
await page.locator('[data-testid="manual-record"]').first().click()
await page.getByRole('button', { name: '删除', exact: true }).click()
await page.getByRole('button', { name: mobile ? '确认删除' : '确定', exact: true }).click()
await page.locator('[data-testid="manual-record"]').waitFor({ state: 'hidden' })
assert.equal(rows.length, 0)
failLoad = true
await page.getByRole('tab', { name: '实际派车信息', exact: true }).click()
await page.getByRole('tab', { name: '派车日历', exact: true }).click()
await page.getByText('派车日历加载失败,请重试', { exact: false }).first().waitFor()
await page.getByRole('button', { name: '重试', exact: true }).click()
await page
.getByText('派车日历加载失败,请重试', { exact: false })
.first()
.waitFor({ state: 'hidden' })
if (mobile)
for (const width of [320, 375, 414]) {
await page.setViewportSize({ width, height: 812 })
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1))
}
await page.getByRole('tab', { name: '实际派车信息', exact: true }).click()
await page.getByText('本月暂无派车计划', { exact: true }).first().waitFor()
allowManage = false
rows = [
{
id: 'readonly',
dispatchDate: '2026-10-26',
vehicleId: 'v1',
licensePlate: '皖H12345',
productId: 'p1',
productName: '液碱',
origin: '山峡',
destination: '云栋',
remark: ''
}
]
await page.getByRole('tab', { name: '派车日历', exact: true }).click()
await page.locator('[data-testid="manual-record"]').first().waitFor()
assert.equal(await page.getByRole('button', { name: '新增派车计划', exact: true }).count(), 0)
await page.locator('[data-testid="manual-record"]').first().click()
assert.equal(await page.getByRole('button', { name: '编辑', exact: true }).count(), 0)
assert.equal(await page.getByRole('button', { name: '删除', exact: true }).count(), 0)
assert.deepEqual(errors, [])
await context.close()
console.log(mobile ? 'mobile CRUD passed' : 'web CRUD passed')
}
} finally {
await browser.close()
}