253 lines
10 KiB
JavaScript
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()
|
|
}
|