Files
goauto/web/tests/e2e/syb-product-layout.spec.ts
T

310 lines
27 KiB
TypeScript

import { expect, test } from '@playwright/test'
const sybProductRoute = [{ path: '/goauto-order-workbench', component: 'Layout', menuName: 'GoAutoOrderWorkbench', title: '订单工作台', visible: '0', children: [{ path: '/syb-products', component: '/goauto/syb-products/index', menuName: 'GoAutoSybProducts', title: 'SYB 商品', visible: '0' }, { path: '/shopee-products/index', component: '/goauto/shopee-products/index', menuName: 'GoAutoShopeeProducts', title: '虾皮商品', visible: '0' }] }]
test('SYB 商品工具栏与列宽按紧凑布局显示', async({ page, context }) => {
await page.setViewportSize({ width: 1920, height: 1080 })
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
const listURLs: URL[] = []
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-shops')) return route.fulfill({ json: { code: 200, data: { items: [{ id: 1, displayName: '大碼臻選', enabled: true }, { id: 2, displayName: '歷史店鋪', enabled: false }], total: 2, enabledCount: 1, page: 1, pageSize: 200 }}})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) { listURLs.push(url); return route.fulfill({ json: { code: 200, data: { items: [{ id: 1, orderCode: 'SYB001', shopeeItemId: '26154802794', shopeeProductId: 9, productTitle: '用于验证加宽后的虾皮商品标题区域', shopName: '大碼臻選', targetColor: '黑色', targetSize: 'XL', quantity: 2, unitPriceCent: 1000, parseStatus: 'success', manuallyConfirmed: false }, { id: 2, orderCode: 'SYB002', shopeeItemId: '26154802795', productTitle: '尚未关联的商品', shopName: '大碼臻選', targetColor: '白色', targetSize: 'L', quantity: 1, unitPriceCent: 900, parseStatus: 'success', manuallyConfirmed: false }], total: 2, page: 1, pageSize: 20 }}}) }
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) return route.fulfill({ json: { code: 200, data: { items: [{ sybProductId: 1, pddProductId: 17, eligible: true, collectionEligible: true, minUnitPriceCent: 200, maxUnitPriceCent: 1500, processStage: 'purchase_ready', processStageLabel: '可创建采购', processStageReason: '当前条件可以创建采购任务' }, { sybProductId: 2, eligible: false, collectionEligible: false, collectionDisabledReason: '尚未关联 PDD 商品', reason: '尚未关联蝦皮商品', processStage: 'manual_action', processStageLabel: '待人工处理', processStageReason: '尚未关联蝦皮商品' }], eligibleCount: 1, skippedCount: 1 }}})
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
await expect(page.getByRole('button', { name: '店铺管理' })).toHaveCount(0)
await expect(page.getByRole('button', { name: '导入', exact: true })).toHaveCount(0)
await expect(page.getByRole('button', { name: '同步记录', exact: true })).toHaveCount(0)
await expect(page.getByRole('button', { name: '从 SYB 导入', exact: true })).toHaveCount(0)
await expect(page.getByText('已选择 0 条', { exact: true })).toBeVisible()
await expect(page.getByRole('button', { name: '重新解析', exact: true })).toHaveCount(0)
await expect(page.getByRole('columnheader', { name: '蝦皮关联' })).toHaveCount(0)
await expect(page.getByText('本页不展示采购任务、PDD 订单号、快递单号和支付状态。', { exact: true })).toHaveCount(0)
await expect(page.getByText('未关联', { exact: true }).last()).toBeVisible()
await expect(page.locator('tbody').getByText('可创建采购', { exact: true })).toBeVisible()
await expect(page.locator('tbody').getByText('待人工处理', { exact: true })).toBeVisible()
await expect(page.getByText('26154802795 ↗', { exact: true })).toHaveCount(0)
const shopeeTitle = page.locator('.shopee-title').first()
await expect(shopeeTitle).toHaveAttribute('title', '用于验证加宽后的虾皮商品标题区域')
await expect(shopeeTitle).toHaveCSS('text-overflow', 'ellipsis')
const selectionCount = await page.getByText('已选择 0 条', { exact: true }).boundingBox()
const queryButton = await page.getByRole('button', { name: '查询', exact: true }).boundingBox()
const reset = await page.getByRole('button', { name: '重置' }).boundingBox()
const purchase = await page.getByRole('button', { name: /创建采购\s*0/ }).boundingBox()
expect(selectionCount).not.toBeNull(); expect(queryButton).not.toBeNull(); expect(reset).not.toBeNull(); expect(purchase).not.toBeNull()
expect(Math.abs((selectionCount?.y || 0) - (queryButton?.y || 0))).toBeLessThan(2)
expect(Math.abs((reset?.y || 0) - (purchase?.y || 0))).toBeLessThan(2)
expect(purchase?.x || 0).toBeGreaterThan((reset?.x || 0) + (reset?.width || 0))
await expect(page.getByRole('button', { name: /创建采购\s*0/ })).toBeDisabled()
const shopControl = page.getByPlaceholder('选择或输入店铺')
const shopInput = await shopControl.boundingBox()
const orderInput = await page.getByPlaceholder('每行一个订单号,最多 100 个').boundingBox()
expect(shopInput).not.toBeNull(); expect(orderInput).not.toBeNull()
expect(shopInput?.x || 0).toBeLessThan(orderInput?.x || 0)
await shopControl.click()
await expect(page.getByText('大碼臻選', { exact: true }).last()).toBeVisible()
await expect(page.getByText('歷史店鋪', { exact: true }).last()).toBeVisible()
await expect(page.getByText('已停用', { exact: true })).toBeVisible()
await page.locator('.el-table__body-wrapper tbody tr').first().locator('.el-checkbox').click()
await expect(page.getByText('已选择 1 条', { exact: true })).toBeVisible()
await expect(page.getByRole('button', { name: /创建采购\s*1/ })).toBeEnabled()
await expect(page.getByRole('button', { name: /创建采集\s*1/ })).toBeEnabled()
const widths = await page.locator('.el-table__header-wrapper colgroup col').evaluateAll(cols => cols.map(col => Number(col.getAttribute('width'))))
expect(widths[3]).toBe(260)
expect(widths[9]).toBeGreaterThanOrEqual(210)
expect(widths[10]).toBe(132)
await shopControl.fill('大碼')
await page.getByPlaceholder('每行一个订单号,最多 100 个').fill(' SYB001\n\nSYB002\nSYB001 ')
await page.getByPlaceholder('每行一个订单号,最多 100 个').press('Control+Enter')
await expect.poll(() => listURLs.length).toBeGreaterThan(1)
const latest = listURLs.at(-1)
expect(latest?.searchParams.get('shopName')).toBe('大碼')
expect(latest?.searchParams.get('orderCodes')).toBe('SYB001,SYB002')
await page.locator('.el-form-item').filter({ hasText: '处理阶段' }).locator('.el-select').click()
await page.getByRole('option', { name: 'PDD 待采集' }).click()
await page.getByRole('button', { name: '查询', exact: true }).click()
await expect.poll(() => listURLs.at(-1)?.searchParams.get('processStage')).toBe('pdd_pending')
})
test('批量 AI 匹配展示混合结果并在关闭后刷新采购候选', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
let matched = false
let matchBody: { sybProductIds: number[] } | null = null
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) return route.fulfill({ json: { code: 200, data: { items: [
{ id: 81, orderCode: 'MATCH-81', shopeeItemId: '1081', shopeeProductId: 181, productTitle: '高置信度候选', quantity: 1, parseStatus: 'success' },
{ id: 82, orderCode: 'MATCH-82', shopeeItemId: '1082', shopeeProductId: 182, productTitle: '低置信度候选', quantity: 1, parseStatus: 'success' },
{ id: 83, orderCode: 'READY-83', shopeeItemId: '1083', shopeeProductId: 183, productTitle: '已就绪候选', quantity: 1, parseStatus: 'success' }
], total: 3, page: 1, pageSize: 20 }}})
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-spec-match')) {
matchBody = route.request().postDataJSON()
matched = true
return route.fulfill({ json: { code: 200, data: {
items: [
{ sybProductId: 81, orderCode: 'MATCH-81', status: 'auto_confirmed', source: 'ai_match', confidence: 0.96, reason: '唯一可靠候选' },
{ sybProductId: 82, orderCode: 'MATCH-82', status: 'pending', source: 'ai_match', confidence: 0.61, reason: '未达到自动确认阈值' },
{ sybProductId: 83, orderCode: 'READY-83', status: 'skipped', reason: '当前不是规格待匹配阶段,无需处理' }
], autoConfirmedCount: 1, pendingCount: 1, failedCount: 0, skippedCount: 1
}}})
}
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) {
const stage = (id: number) => id === 83 || (id === 81 && matched) ? 'purchase_ready' : 'color_mapping'
const items = [81, 82, 83].map(id => ({ sybProductId: id, pddProductId: 200 + id, eligible: stage(id) === 'purchase_ready', collectionEligible: false, aiMatchEligible: stage(id) === 'color_mapping', aiMatchDisabledReason: stage(id) === 'color_mapping' ? '' : '已有有效确认映射,无需 AI 匹配', processStage: stage(id), processStageLabel: stage(id) === 'purchase_ready' ? '可创建采购' : '规格待匹配', processStageReason: '' }))
return route.fulfill({ json: { code: 200, data: { items, eligibleCount: items.filter(item => item.eligible).length, skippedCount: items.filter(item => !item.eligible).length }}})
}
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
const rows = page.locator('.el-table__body-wrapper tbody tr')
for (let index = 0; index < 3; index += 1) await rows.nth(index).locator('.el-checkbox').click()
await expect(page.getByRole('button', { name: /AI 匹配\s*2/ })).toBeEnabled()
await expect(page.getByRole('button', { name: /创建采购\s*1/ })).toBeEnabled()
await page.getByRole('button', { name: /AI 匹配\s*2/ }).click()
await expect(page.getByRole('dialog', { name: 'AI 匹配结果' })).toBeVisible()
await expect(page.getByText('自动确认 1 条', { exact: true })).toBeVisible()
await expect(page.getByText('待人工 1 条', { exact: true })).toBeVisible()
await expect(page.getByText('96%', { exact: true })).toBeVisible()
expect(matchBody?.sybProductIds).toEqual([81, 82, 83])
await page.getByRole('button', { name: '关闭', exact: true }).click()
await expect(page.getByRole('button', { name: /创建采购\s*2/ })).toBeEnabled()
await expect(page.getByRole('button', { name: /AI 匹配\s*1/ })).toBeEnabled()
})
test('店铺选项加载失败时仍可输入历史店铺查询', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
const listURLs: URL[] = []
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-shops')) return route.fulfill({ status: 500, json: { code: 500, message: '测试用店铺加载失败' }})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) { listURLs.push(url); return route.fulfill({ json: { code: 200, data: { items: [], total: 0, page: 1, pageSize: 20 }}}) }
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
const shopControl = page.getByPlaceholder('选择或输入店铺')
await shopControl.click()
await expect(page.getByText('店铺列表加载失败,仍可直接输入店铺名称查询', { exact: true })).toBeVisible()
await shopControl.fill('已删除店铺')
await page.getByRole('button', { name: '查询', exact: true }).click()
await expect.poll(() => listURLs.length).toBeGreaterThan(1)
expect(listURLs.at(-1)?.searchParams.get('shopName')).toBe('已删除店铺')
})
test('PDD 待采集的下一步在 SYB 列表上方打开对应 PDD 商品抽屉', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) return route.fulfill({ json: { code: 200, data: { items: [{ id: 31, orderCode: 'SYB-PDD-31', shopeeItemId: '26154802794', shopeeProductId: 9, productTitle: '待采集商品', shopName: '大碼臻選', targetColor: '黑色', targetSize: 'XL', quantity: 1, unitPriceCent: 1000, parseStatus: 'success' }], total: 1, page: 1, pageSize: 20 }}})
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) return route.fulfill({ json: { code: 200, data: { items: [{ sybProductId: 31, pddProductId: 17, eligible: false, collectionEligible: true, reason: 'PDD 商品待采集', processStage: 'pdd_pending', processStageLabel: 'PDD 待采集', processStageReason: 'PDD 商品待采集', processNextAction: 'open_pdd' }], eligibleCount: 0, skippedCount: 1 }}})
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
let popupCount = 0
page.on('popup', () => { popupCount += 1 })
await page.getByRole('button', { name: '查看 PDD 商品' }).click()
await expect(page.getByText('PDD 商品详情', { exact: true }).last()).toBeVisible()
await expect(page.getByText('SYB-PDD-31', { exact: true })).toBeVisible()
expect(popupCount).toBe(0)
})
test('未关联 PDD 显示去关联并直接打开 PDD 商品选择器', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
await context.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) return route.fulfill({ json: { code: 200, data: { items: [{ id: 41, orderCode: 'SYB-LINK-41', shopeeItemId: '26154802794', shopeeProductId: 9, productTitle: '未关联商品', shopName: '大碼臻選', targetColor: '黑色', targetSize: 'XL', quantity: 1, unitPriceCent: 1000, parseStatus: 'success' }, { id: 42, orderCode: 'SYB-MAP-42', shopeeItemId: '26154802795', shopeeProductId: 10, productTitle: '待匹配商品', shopName: '大碼臻選', targetColor: '白色', targetSize: 'L', quantity: 1, unitPriceCent: 1200, parseStatus: 'success' }], total: 2, page: 1, pageSize: 20 }}})
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) return route.fulfill({ json: { code: 200, data: { items: [{ sybProductId: 41, eligible: false, processStage: 'pdd_unlinked', processStageLabel: '未关联 PDD', processStageReason: '请先关联 PDD 商品', processNextAction: 'open_pdd_link' }, { sybProductId: 42, eligible: false, processStage: 'color_mapping', processStageLabel: '规格待匹配', processStageReason: '规格匹配无效,请重新选择', processNextAction: 'open_mapping' }], eligibleCount: 0, skippedCount: 2 }}})
if (url.pathname.endsWith('/api/admin/v1/shopee-products/9')) return route.fulfill({ json: { code: 200, data: { product: { id: 9, shopeeItemId: '26154802794', title: '未关联商品', shopName: '大碼臻選', pddProductId: null, specs: [] } } }})
if (url.pathname.endsWith('/api/admin/v1/shopee-products')) return route.fulfill({ json: { code: 200, data: { items: [], total: 0, page: 1, pageSize: 20 }}})
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
await expect(page.getByText('请先关联 PDD 商品', { exact: true })).toBeVisible()
await expect(page.getByRole('button', { name: '去关联', exact: true })).toBeVisible()
await expect(page.getByRole('button', { name: '去匹配', exact: true })).toBeVisible()
let popupCount = 0
page.on('popup', () => { popupCount += 1 })
await page.getByRole('button', { name: '去关联', exact: true }).click()
await expect(page.getByText('虾皮商品详情', { exact: true })).toBeVisible()
await expect(page.getByText('搜索并选择 PDD 商品', { exact: true })).toBeVisible()
await expect(page.getByText('SYB-LINK-41', { exact: true })).toBeVisible()
expect(popupCount).toBe(0)
})
test('SYB 商品页不读取或展示后台同步状态', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
let syncRunCalls = 0
let productCalls = 0
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.includes('/api/admin/v1/syb-products/sync-runs')) { syncRunCalls += 1; return route.fulfill({ json: { code: 200, data: { items: [] }}}) }
if (url.pathname.endsWith('/api/admin/v1/syb-products')) { productCalls += 1; return route.fulfill({ json: { code: 200, data: { items: [], total: 0, page: 1, pageSize: 20 }}}) }
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
await expect(page.getByRole('button', { name: '查询', exact: true })).toBeVisible()
await page.waitForTimeout(3500)
expect(productCalls).toBe(1)
expect(syncRunCalls).toBe(0)
await expect(page.getByText('正在同步', { exact: true })).toHaveCount(0)
await expect(page.getByText('同步失败', { exact: true })).toHaveCount(0)
})
test('混选后采购与采集分别提交候选子集且采集按 PDD 去重', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
const purchaseBodies: Array<{ sybProductIds: number[] }> = []
const collectionBodies: Array<{ pddProductIds: number[] }> = []
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) return route.fulfill({ json: { code: 200, data: { items: [
{ id: 201, orderCode: 'BUY-201', shopeeItemId: '9201', productTitle: '采购候选', quantity: 1, parseStatus: 'success' },
{ id: 202, orderCode: 'COLLECT-202', shopeeItemId: '9202', productTitle: '采集候选一', quantity: 1, parseStatus: 'success' },
{ id: 203, orderCode: 'COLLECT-203', shopeeItemId: '9203', productTitle: '采集候选二', quantity: 1, parseStatus: 'success' }
], total: 3, page: 1, pageSize: 20 }}})
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) {
const ids = route.request().postDataJSON().sybProductIds
const all = [
{ sybProductId: 201, pddProductId: 301, eligible: true, collectionEligible: false, collectionDisabledReason: '已有待执行或执行中的采集任务', processStage: 'purchase_ready', processStageLabel: '可创建采购', processStageReason: '当前条件可以创建采购任务' },
{ sybProductId: 202, pddProductId: 302, pddGoodsId: '88002', eligible: false, collectionEligible: true, processStage: 'pdd_pending', processStageLabel: 'PDD 待采集', processStageReason: 'PDD 商品待采集', processNextAction: 'open_pdd' },
{ sybProductId: 203, pddProductId: 302, pddGoodsId: '88002', eligible: false, collectionEligible: true, processStage: 'pdd_pending', processStageLabel: 'PDD 待采集', processStageReason: 'PDD 商品待采集', processNextAction: 'open_pdd' }
]
const items = all.filter(item => ids.includes(item.sybProductId))
return route.fulfill({ json: { code: 200, data: { items, eligibleCount: items.filter(item => item.eligible).length, skippedCount: items.filter(item => !item.eligible).length }}})
}
if (url.pathname.endsWith('/api/admin/v1/devices')) return route.fulfill({ json: { code: 200, data: { items: [], total: 0 }}})
if (url.pathname.endsWith('/api/admin/v1/collection-rules')) return route.fulfill({ json: { code: 200, data: { items: [{ id: 7, name: '默认采集规则' }], total: 1 }}})
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch')) { purchaseBodies.push(route.request().postDataJSON()); return route.fulfill({ json: { code: 200, data: { items: [{ sybProductId: 201, created: true, taskId: 901, taskNo: 'PUR-901' }], createdCount: 1, failedCount: 0 }}}) }
if (url.pathname.endsWith('/api/admin/v1/collection-tasks/batch')) { collectionBodies.push(route.request().postDataJSON()); return route.fulfill({ json: { code: 200, data: { items: [{ pddProductId: 302, success: false, message: '设备当前不可用' }], successCount: 0, failureCount: 1 }}}) }
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
const rows = page.locator('.el-table__body-wrapper tbody tr')
await expect(rows).toHaveCount(3)
for (let index = 0; index < 3; index += 1) await rows.nth(index).locator('.el-checkbox').click()
await expect(page.getByText('已选择 3 条', { exact: true })).toBeVisible()
await expect(page.getByRole('button', { name: /创建采购\s*1/ })).toBeEnabled()
await expect(page.getByRole('button', { name: /创建采集\s*1/ })).toBeEnabled()
await page.getByRole('button', { name: /创建采购\s*1/ }).click()
await expect(page.getByText('已选择 3 条 SYB 明细', { exact: true })).toBeVisible()
await page.getByRole('button', { name: '创建 1 个采购任务', exact: true }).click()
await expect.poll(() => purchaseBodies.length).toBe(1)
expect(purchaseBodies[0].sybProductIds).toEqual([201])
await page.getByRole('button', { name: '返回 SYB 商品', exact: true }).click()
for (let index = 0; index < 3; index += 1) await rows.nth(index).locator('.el-checkbox').click()
await page.getByRole('button', { name: /创建采集\s*1/ }).click()
await expect(page.getByText('其中 2 条适用于采集', { exact: true })).toBeVisible()
await expect(page.getByText('去重后 1 个 PDD 商品', { exact: true })).toBeVisible()
await page.getByRole('combobox', { name: '*采集规则' }).click()
await page.getByRole('option', { name: '默认采集规则', exact: true }).click()
await page.getByRole('button', { name: '创建 1 个采集任务', exact: true }).click()
await expect.poll(() => collectionBodies.length).toBe(1)
expect(collectionBodies[0].pddProductIds).toEqual([302])
await expect(page.getByText('设备当前不可用', { exact: true })).toBeVisible()
})
test('去重后超过 100 个 PDD 商品时给出提示且不调用批量接口', async({ page, context }) => {
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
const collectionCalls: unknown[] = []
const rows = Array.from({ length: 101 }, (_, index) => ({ id: 400 + index, orderCode: `OVER-${400 + index}`, shopeeItemId: `94${index}`, productTitle: `超限采集候选 ${index}`, quantity: 1, parseStatus: 'success' }))
await page.route('**/api/**', async route => {
const url = new URL(route.request().url())
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
if (url.pathname.startsWith('/src/api/')) return route.continue()
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}})
if (url.pathname.endsWith('/api/admin/v1/syb-products')) return route.fulfill({ json: { code: 200, data: { items: rows, total: rows.length, page: 1, pageSize: 200 }}})
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) {
const items = rows.map((row, index) => ({ sybProductId: row.id, pddProductId: 500 + index, pddGoodsId: `88${index}`, eligible: false, collectionEligible: true, processStage: 'pdd_pending', processStageLabel: 'PDD 待采集', processStageReason: 'PDD 商品待采集', processNextAction: 'open_pdd' }))
return route.fulfill({ json: { code: 200, data: { items, eligibleCount: 0, skippedCount: items.length }}})
}
if (url.pathname.endsWith('/api/admin/v1/collection-tasks/batch')) { collectionCalls.push(route.request().postDataJSON()); return route.fulfill({ json: { code: 200, data: { items: [], successCount: 0, failureCount: 0 }}}) }
return route.fulfill({ json: { code: 200, data: [] }})
})
await page.goto('/#/syb-products')
await expect(page.locator('.el-table__body-wrapper tbody tr')).toHaveCount(101)
await page.locator('.el-table__header-wrapper .el-checkbox').first().click()
await expect(page.getByRole('button', { name: /创建采集\s*101/ })).toBeEnabled()
await page.getByRole('button', { name: /创建采集\s*101/ }).click()
await expect(page.getByText('一次最多创建 100 个去重后的 PDD 商品采集任务', { exact: true })).toBeVisible()
await expect(page.getByRole('dialog', { name: '批量创建 PDD 采集任务' })).toHaveCount(0)
expect(collectionCalls).toHaveLength(0)
})