import { expect, test, Page } from '@playwright/test' const routes = [{ path: '/collection-purchase', component: 'Layout', menuName: 'GoAutoCollectionPurchase', title: '采集采购', visible: '0', children: [{ path: '/shopee-products', component: '/goauto/shopee-products/index', menuName: 'GoAutoShopeeProducts', title: '虾皮商品', visible: '0' }] }] async function fixture(page: Page, mode: 'pending' | 'lost' | 'read-failed') { const releases: Array<() => void> = [] let posts = 0, saved = false await page.context().addCookies([{ name: 'Admin-Token', value: 'synthetic-test-only', domain: 'localhost', path: '/' }]) const product = () => ({ id: 9, shopeeItemId: 'S9', title: '匹配等待测试', pddProductId: 17, specContextVersion: 'context-254', specs: [{ name: '颜色', role: 'color', values: [{ name: '深黑', source: 'import', mapping: saved ? { pddValue: '黑色', source: 'ai_match', status: 'confirmed' } : null }] }] }) await page.route('**/api/**', async route => { const path = new URL(route.request().url()).pathname if (path.startsWith('/src/api/')) return route.continue() if (path.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['purchaser'], name: '测试采购员', avatar: '', introduction: '', permissions: [] } } }) if (path.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: routes } }) if (path.endsWith('/api/admin/v1/shopee-products')) return route.fulfill({ json: { code: 200, data: { items: [product()], total: 1, page: 1, pageSize: 20 } } }) if (path.endsWith('/specs/mapping/auto-match')) { posts++ if (mode === 'pending') await new Promise(resolve => releases.push(resolve)) saved = true if (mode !== 'pending') return route.abort('timedout') return route.fulfill({ json: { code: 200, data: { confirmedCount: 1, preservedCount: 0, unmatchedCount: 0 } } }) } if (path.endsWith('/shopee-products/9')) { if (posts && mode === 'read-failed') return route.abort('failed') return route.fulfill({ json: { code: 200, data: { product: product(), autoMatchTimeoutSeconds: 130 } } }) } if (path.endsWith('/pdd-products/17')) return route.fulfill({ json: { code: 200, data: { product: { id: 17, goodsId: '17', specs: [{ name: '颜色', role: 'color', values: [{ name: '黑色', selectable: true }] }] } } } }) return route.fulfill({ json: { code: 200, data: [] } }) }) await page.goto('/#/shopee-products') await page.getByRole('button', { name: '详情', exact: true }).click() const match = page.getByRole('button', { name: '一键匹配颜色和尺码', exact: true }) await expect(match).toBeEnabled() return { match, releases, posts: () => posts } } test('关闭重开与迟到响应不污染新匹配,显示动态140秒预算', async ({ page }) => { const f = await fixture(page, 'pending') await f.match.click() await expect(page.getByText('正在匹配并保存,最多等待 140 秒', { exact: true })).toBeVisible() await expect(page.getByRole('button', { name: '编辑档案', exact: true })).toBeDisabled() await expect(f.match).toBeDisabled() await page.screenshot({ path: 'test-results/254-waiting.png', fullPage: true }) await page.getByRole('button', { name: '关闭', exact: true }).click() await page.getByRole('button', { name: '详情', exact: true }).click() await expect(f.match).toBeEnabled() await f.match.click() await expect.poll(f.posts).toBe(2) f.releases[0]() await expect(f.match).toBeDisabled() f.releases[1]() await expect(f.match).toBeEnabled() await expect(page.getByText('新匹配并确认 1 项,保留已确认 0 项,未匹配 0 项', { exact: true }).first()).toBeVisible() }) for (const mode of ['lost', 'read-failed'] as const) { test(`${mode}:结束等待且不重试POST`, async ({ page }) => { const f = await fixture(page, mode) await f.match.click() const text = mode === 'lost' ? '已刷新当前保存结果;原请求未正常返回,请检查未匹配项后再操作' : '结果暂未确认,请刷新查看;不要重复提交匹配' await expect(page.getByText(text, { exact: true })).toBeVisible() await expect(f.match).toBeEnabled() expect(f.posts()).toBe(1) await expect(page.getByRole('button', { name: '刷新查看', exact: true })).toBeVisible() await page.screenshot({ path: `test-results/254-${mode}.png`, fullPage: true }) }) }