146 lines
9.8 KiB
TypeScript
146 lines
9.8 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
||
|
||
async function setup(page: any, state = 'not_started', failManualOnce = false) {
|
||
await page.setViewportSize({ width: 1920, height: 1080 })
|
||
await page.context().addCookies([{ name: 'Admin-Token', value: 'test-only', domain: 'localhost', path: '/' }])
|
||
const requests: { path: string, body: any }[] = []
|
||
const items = [
|
||
{ id: 11, taskType: 'syb_order', executionMode: 'live', status: 'order_created', pddOrderNo: 'EXAMPLE-11', orderSubmittedAt: '2026-09-19T12:00:00Z', pddOrderAmountCent: null as number | null, paymentReviewStatus: 'unpaid', orderWriteback: { status: state, canSubmit: ['not_started', 'failed', 'unknown'].includes(state), reason: state === 'conflict' ? 'SYB 已有不同单号,未覆盖' : '' } },
|
||
{ id: 12, taskType: 'syb_order', executionMode: 'live', status: 'failed', retryable: true, orderWriteback: { status: 'not_applicable', canSubmit: false, reason: '' } },
|
||
{ id: 13, taskType: 'stock', executionMode: 'live', status: 'order_created', orderWriteback: { status: 'not_applicable', canSubmit: false, reason: '' } }
|
||
]
|
||
await page.route('**/api/**', async route => {
|
||
const path = new URL(route.request().url()).pathname
|
||
if (path.endsWith('/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '测试采购员', avatar: '', introduction: '', permissions: [] } } })
|
||
if (path.endsWith('/menurole')) return route.fulfill({ json: { code: 200, data: [{ path: '/collection-purchase', component: 'Layout', menuName: 'GoAutoCollectionPurchase', title: '采集采购', visible: '0', children: [{ path: '/purchase-tasks/index', component: '/goauto/purchase-tasks/index', menuName: 'GoAutoPurchaseTasks', title: '采购管理', visible: '0' }] }] } })
|
||
if (route.request().method() === 'POST') {
|
||
const body = route.request().postDataJSON()
|
||
requests.push({ path, body })
|
||
if (path.endsWith('/resolve-unknown')) {
|
||
if (failManualOnce) { failManualOnce = false; return route.fulfill({ status: 500, json: { code: 500, message: 'synthetic failure' } }) }
|
||
items[0].pddOrderAmountCent = body.pddOrderAmountCent
|
||
return route.fulfill({ json: { code: 200, data: items[0] } })
|
||
}
|
||
if (path.endsWith('/syb-order-writeback')) {
|
||
items[0].orderWriteback = { status: 'pending', canSubmit: false, reason: '' }
|
||
return route.fulfill({ json: { code: 200, data: { items: body.purchaseTaskIds.map((taskId: number) => ({ taskId, result: 'pending', reason: '已受理' })) } } })
|
||
}
|
||
if (path.endsWith('/batch-retry')) return route.fulfill({ json: { code: 200, data: { items: [], createdCount: 1, failedCount: 0 } } })
|
||
throw new Error('unexpected write: ' + path)
|
||
}
|
||
if (path.endsWith('/purchase-tasks/11')) return route.fulfill({ json: { code: 200, data: { task: items[0], attempts: [] } } })
|
||
if (path.endsWith('/purchase-tasks')) return route.fulfill({ json: { code: 200, data: { items, total: items.length } } })
|
||
return route.fulfill({ json: { code: 200, data: [] } })
|
||
})
|
||
await page.goto('/#/purchase-tasks/index')
|
||
await expect(page.getByText('CG-11', { exact: true })).toBeVisible()
|
||
return requests
|
||
}
|
||
|
||
test('混选任务分别回填与重试,不把已下单任务交给采购重试', async ({ page }) => {
|
||
const requests = await setup(page)
|
||
await page.locator('.el-table__header-wrapper .el-checkbox').click()
|
||
await expect(page.getByRole('button', { name: '重试(1)', exact: true })).toBeEnabled()
|
||
await expect(page.getByRole('button', { name: '批量回填 SYB(1)', exact: true })).toBeEnabled()
|
||
await page.getByRole('button', { name: '重试(1)', exact: true }).click()
|
||
const retry = page.getByRole('dialog', { name: '确认重试失败任务' })
|
||
await expect(retry.getByText('CG-12', { exact: true })).toBeVisible()
|
||
await expect(retry.getByText('CG-11', { exact: true })).toHaveCount(0)
|
||
await retry.getByRole('button', { name: '确认重试', exact: true }).click()
|
||
await expect.poll(() => requests.length).toBe(1)
|
||
expect(requests[0].body.taskIds).toEqual([12])
|
||
await page.getByRole('dialog', { name: '批量重试结果' }).getByRole('button', { name: '留在当前页' }).click()
|
||
await page.locator('.el-table__header-wrapper .el-checkbox').first().click()
|
||
await page.getByRole('button', { name: '批量回填 SYB(1)', exact: true }).click()
|
||
const result = page.getByRole('dialog', { name: 'SYB 单号回填提交结果' })
|
||
await expect(result.getByText('待回填', { exact: true })).toBeVisible()
|
||
expect(requests[1].body.purchaseTaskIds).toEqual([11])
|
||
expect(requests[1].body.requestId).toMatch(/^[0-9a-f-]{36}$/)
|
||
await result.getByRole('button', { name: '关闭', exact: true }).click()
|
||
await expect(result).toBeHidden()
|
||
await expect(page.getByRole('button', { name: '批量回填 SYB(0)', exact: true })).toBeDisabled()
|
||
})
|
||
|
||
test('未支付订单可从详情补偿回填,旧物流流程保持独立', async ({ page }) => {
|
||
const requests = await setup(page, 'failed')
|
||
await page.getByRole('button', { name: '详情', exact: true }).first().click()
|
||
const drawer = page.getByRole('dialog', { name: '采购任务详情' })
|
||
await expect(drawer.getByText('SYB 物流回填', { exact: true })).toBeVisible()
|
||
await drawer.getByRole('button', { name: '重试回填 SYB 单号', exact: true }).click()
|
||
await expect(page.getByRole('dialog', { name: 'SYB 单号回填提交结果' })).toBeVisible()
|
||
expect(requests).toHaveLength(1)
|
||
expect(requests[0].path).toContain('/syb-order-writeback')
|
||
expect(requests[0].body.purchaseTaskIds).toEqual([11])
|
||
})
|
||
|
||
test('冲突显示原因且没有覆盖按钮', async ({ page }) => {
|
||
await setup(page, 'conflict')
|
||
await page.getByRole('button', { name: '详情', exact: true }).first().click()
|
||
const drawer = page.getByRole('dialog', { name: '采购任务详情' })
|
||
await expect(drawer.getByText('单号冲突', { exact: true })).toBeVisible()
|
||
await expect(drawer.getByText('SYB 已有不同单号,未覆盖', { exact: true })).toBeVisible()
|
||
await expect(drawer.getByRole('button', { name: /回填 SYB 单号/ })).toHaveCount(0)
|
||
})
|
||
|
||
test('状态下拉框筛选已回填SYB,清空后恢复普通列表', async ({ page }) => {
|
||
const requests = await setup(page, 'succeeded')
|
||
const statuses: string[] = []
|
||
await page.route('**/api/admin/v1/purchase-tasks?**', async route => {
|
||
const query = new URL(route.request().url()).searchParams
|
||
statuses.push(query.get('status') || '')
|
||
expect(query.get('page')).toBe('1')
|
||
return route.fulfill({ json: { code: 200, data: { items: [{ id: 11, taskType: 'syb_order', executionMode: 'live', status: 'order_created', orderWriteback: { status: 'succeeded', canSubmit: false } }], total: 1 } } })
|
||
})
|
||
const field = page.locator('.search-form .el-form-item').filter({ has: page.locator('label').filter({ hasText: /^状态$/ }) })
|
||
await field.locator('.el-select').click()
|
||
await page.getByRole('option', { name: '已回填 SYB', exact: true }).click()
|
||
await page.getByRole('button', { name: '查询', exact: true }).click()
|
||
await expect.poll(() => statuses.at(-1)).toBe('syb_writeback_succeeded')
|
||
await expect(page.getByText('订单已创建', { exact: true }).first()).toBeVisible()
|
||
await field.locator('.el-select').hover()
|
||
await field.locator('.el-select__clear').click()
|
||
await page.getByRole('button', { name: '查询', exact: true }).click()
|
||
await expect.poll(() => statuses.at(-1)).toBe('')
|
||
expect(requests).toHaveLength(0)
|
||
})
|
||
|
||
for (const amount of ['0', '13.01']) {
|
||
test(`已创建订单补金额 ${amount},不重新采购或修改支付状态`, async ({ page }) => {
|
||
const requests = await setup(page)
|
||
await page.getByRole('button', { name: '详情', exact: true }).first().click()
|
||
const drawer = page.getByRole('dialog', { name: '采购任务详情' })
|
||
await drawer.getByRole('button', { name: '补全订单信息', exact: true }).click()
|
||
const dialog = page.getByRole('dialog', { name: '补全订单信息', exact: true })
|
||
await expect(dialog.getByRole('button', { name: '保存', exact: true })).toBeDisabled()
|
||
await expect(dialog.getByRole('textbox').first()).toHaveAttribute('readonly', '')
|
||
await dialog.getByPlaceholder('例如 13.00').fill('-1')
|
||
await expect(dialog.getByText('请输入不小于0、最多两位小数的金额')).toBeVisible()
|
||
await expect(dialog.getByRole('button', { name: '保存', exact: true })).toBeDisabled()
|
||
await dialog.getByPlaceholder('例如 13.00').fill(amount)
|
||
await dialog.getByRole('button', { name: '保存', exact: true }).click()
|
||
await expect(dialog).toBeHidden()
|
||
expect(requests).toHaveLength(1)
|
||
expect(requests[0].body.pddOrderAmountCent).toBe(Math.round(Number(amount) * 100))
|
||
expect(requests[0].body.pddOrderNo).toBe('EXAMPLE-11')
|
||
expect(requests[0].body.orderSubmittedAt).toBe('2026-09-19T12:00:00Z')
|
||
expect(requests[0].path).toContain('/resolve-unknown')
|
||
await expect(drawer.getByText('信息完整', { exact: true })).toBeVisible()
|
||
await expect(drawer.getByRole('button', { name: '补全订单信息', exact: true })).toHaveCount(0)
|
||
})
|
||
}
|
||
|
||
test('补录失败保留输入,原样重试复用requestId', async ({ page }) => {
|
||
const requests = await setup(page, 'not_started', true)
|
||
await page.getByRole('button', { name: '详情', exact: true }).first().click()
|
||
await page.getByRole('button', { name: '补全订单信息', exact: true }).click()
|
||
const dialog = page.getByRole('dialog', { name: '补全订单信息', exact: true })
|
||
await dialog.getByPlaceholder('例如 13.00').fill('15.50')
|
||
await dialog.getByRole('button', { name: '保存', exact: true }).click()
|
||
await expect(dialog.getByText(/保存未确认/)).toBeVisible()
|
||
await expect(dialog.getByPlaceholder('例如 13.00')).toHaveValue('15.50')
|
||
await dialog.getByRole('button', { name: '保存', exact: true }).click()
|
||
await expect(dialog).toBeHidden()
|
||
expect(requests).toHaveLength(2)
|
||
expect(requests[1].body).toEqual(requests[0].body)
|
||
})
|