133 lines
7.1 KiB
TypeScript
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()
|
|
})
|