Files
goauto/web/tests/e2e/purchase-device-preference.spec.ts
T

133 lines
7.1 KiB
TypeScript

import { expect, test } from '@playwright/test'
const required = ['purchase.live.v1', 'purchase.address-update.v1', 'purchase.order-create.v1', 'purchase.spec-probe.v1']
const routes = [{ path: '/workbench', component: 'Layout', menuName: 'Workbench', title: '工作台', visible: '0', children: [
{ path: '/syb-products', component: '/goauto/syb-products/index', menuName: 'GoAutoSybProducts', title: 'SYB 商品', visible: '0' }
] }]
async function mock(page: any) {
const state = { userId: 1, available: true, previewFailed: false, previews: [] as any[], created: [] as any[] }
await page.context().addCookies([{ name: 'Admin-Token', value: 'mock-token', domain: 'localhost', path: '/' }])
await page.route('**/api/**', async (route: any) => {
const url = new URL(route.request().url())
const ok = (data: any) => route.fulfill({ json: { code: 200, data } })
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return ok({ userId: state.userId, roles: ['admin'], name: '同名测试用户', avatar: '', introduction: '', permissions: [] })
if (url.pathname.endsWith('/api/v1/menurole')) return ok(routes)
if (url.pathname.endsWith('/api/admin/v1/syb-products')) return ok({ items: [
{ id: 1, orderCode: 'TEST-1', shopeeItemId: '1001', shopeeProductId: 2, productTitle: '测试商品', targetColor: '黑色', targetSize: 'XL', quantity: 1, parseStatus: 'success' }
], total: 1, page: 1, pageSize: 20 })
if (url.pathname.endsWith('/api/admin/v1/devices')) return ok({ items: [
{ id: 10, name: '测试设备A', model: 'A', selectable: state.available, capabilities: required },
{ id: 20, name: '测试设备B', model: 'B', selectable: true, capabilities: required }
], total: 2 })
if (url.pathname.endsWith('/purchase-tasks/batch-preview')) {
const body = route.request().postDataJSON()
state.previews.push(body)
if (state.previewFailed) return route.fulfill({ status: 500, json: { code: 500, message: '模拟预检失败' } })
return ok({ items: [{ sybProductId: 1, eligible: true, processStage: 'purchase_ready', reason: '规格就绪', quantity: 1 }], eligibleCount: 1, skippedCount: 0 })
}
if (url.pathname.endsWith('/purchase-tasks/batch')) {
state.created.push(route.request().postDataJSON())
return ok({ items: [], createdCount: 1, failedCount: 0 })
}
return ok([])
})
return state
}
async function open(page: any, reload = false) {
if (reload) await page.reload()
else await page.goto('/#/syb-products')
await expect(page.locator('tbody').getByText('可创建采购', { exact: true })).toBeVisible()
await page.locator('.el-table__body-wrapper tbody tr').first().locator('.el-checkbox').click()
await page.getByRole('button', { name: /^创建采购\s*1$/ }).click()
const dialog = page.getByRole('dialog', { name: '批量创建采购任务' })
await expect(dialog).toBeVisible()
await expect(dialog.locator('.el-loading-mask')).toBeHidden()
return dialog
}
async function choose(page: any, dialog: any, name: string) {
await dialog.locator('.el-select').click()
await page.getByRole('option', { name, exact: true }).click()
await expect(dialog.locator('.el-loading-mask')).toBeHidden()
}
test('设备选择跨弹窗和刷新恢复,预检与创建使用同一设备', async ({ page }) => {
const state = await mock(page)
let dialog = await open(page)
await choose(page, dialog, '测试设备A · A')
await dialog.getByRole('button', { name: '返回列表' }).click()
await page.getByRole('button', { name: /^创建采购\s*1$/ }).click()
await expect(dialog.getByText('测试设备A · A', { exact: true })).toBeVisible()
await expect.poll(() => state.previews.at(-1)?.deviceId).toBe(10)
dialog = await open(page, true)
await expect(dialog.getByText('测试设备A · A', { exact: true })).toBeVisible()
await dialog.getByRole('button', { name: '创建 1 个采购任务' }).click()
await expect.poll(() => state.created.length).toBe(1)
expect(state.created[0].deviceId).toBe(10)
})
test('不可用设备不被静默替换,主动清空后保持不指定', async ({ page }) => {
const state = await mock(page)
let dialog = await open(page)
await choose(page, dialog, '测试设备A · A')
state.available = false
dialog = await open(page, true)
await expect(dialog.getByRole('alert').filter({ hasText: '上次选择的设备当前不可用' })).toBeVisible()
await expect(dialog.getByRole('button', { name: /创建 .* 个采购任务/ })).toBeDisabled()
await dialog.locator('.el-select').hover()
await dialog.locator('.el-select__clear').click()
await expect.poll(() => state.previews.at(-1)?.deviceId).toBeUndefined()
dialog = await open(page, true)
await expect(dialog.getByText('上次选择的设备(当前不可用)', { exact: true })).toHaveCount(0)
await expect(dialog.getByText('不指定,由空闲设备领取', { exact: true })).toBeVisible()
})
test('同名用户偏好按ID隔离,预检失败禁用创建', async ({ page }) => {
const state = await mock(page)
let dialog = await open(page)
await choose(page, dialog, '测试设备A · A')
state.userId = 2
dialog = await open(page, true)
await expect(dialog.getByText('不指定,由空闲设备领取', { exact: true })).toBeVisible()
await choose(page, dialog, '测试设备B · B')
state.userId = 1
dialog = await open(page, true)
await expect(dialog.getByText('测试设备A · A', { exact: true })).toBeVisible()
state.previewFailed = true
await choose(page, dialog, '测试设备B · B')
await expect(dialog.getByText('采购预检失败,请重试。', { exact: true })).toBeVisible()
await expect(dialog.getByRole('button', { name: /创建 .* 个采购任务/ })).toBeDisabled()
expect(state.created).toHaveLength(0)
})
test('关闭重开后旧预检响应不覆盖新设备结果', async ({ page }) => {
await mock(page)
const dialog = await open(page)
let held = false
let finished = false
let release: () => void = () => {}
const gate = new Promise<void>(resolve => { release = resolve })
await page.route('**/purchase-tasks/batch-preview', async route => {
if (route.request().postDataJSON().deviceId !== 10 || held) return route.fallback()
held = true
await gate
await route.fulfill({ json: { code: 200, data: { items: [], eligibleCount: 0, skippedCount: 1 } } })
finished = true
})
await dialog.locator('.el-select').click()
await page.getByRole('option', { name: '测试设备A · A', exact: true }).click()
await expect.poll(() => held).toBe(true)
await expect(dialog.getByRole('button', { name: /创建 .* 个采购任务/ })).toBeDisabled()
await dialog.getByRole('button', { name: '返回列表' }).click()
await page.getByRole('button', { name: /^创建采购\s*1$/ }).click()
await expect(dialog.locator('.el-loading-mask')).toBeHidden()
await choose(page, dialog, '测试设备B · B')
release()
await expect.poll(() => finished).toBe(true)
await expect(dialog.getByText('测试设备B · B', { exact: true })).toBeVisible()
await expect(dialog.getByRole('button', { name: '创建 1 个采购任务' })).toBeEnabled()
})