gongxiangp2/components/department-dashboard/PerformanceConversionDetail.test.tsx
2026-09-29 11:35:41 +08:00

174 lines
5.9 KiB
TypeScript

import type { ReactNode } from 'react'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import PerformanceConversionDetail from './PerformanceConversionDetail'
jest.mock('./DepartmentShell', () => ({
__esModule: true,
default: ({ children }: { children: ReactNode }) => <>{children}</>,
}))
const detailData = {
workflow: {
key: 'flow-1:1041432226288',
workflowId: 'flow-1',
approvalNumber: '202609170001',
processCode: 'art-design',
title: '商品主图美术设计申请',
brand: '亿家达' as const,
productId: '1041432226288',
spu: 'SPU-001',
platform: '天猫',
completedAt: '2026-07-12T08:00:00.000Z',
monitorStartDate: '2026-07-12',
monitorEndDate: '2027-01-12',
monitoringStatus: 'monitoring' as const,
},
product: {
id: '1041432226288',
name: '亿家达折叠书桌',
sourceBrand: '亿家达',
category: '住宅家具',
brandMatchesWorkflow: true,
},
latest: {
date: '2026-07-13',
impressions: 1200,
visitors: 200,
clickRate: 0.125,
favorites: 18,
cartUsers: 12,
paymentConversionRate: 0.035,
paymentAmount: 1299.5,
roi: 2.4,
},
daily: [
{
date: '2026-07-12',
impressions: 1000,
visitors: 160,
clickRate: 0.1,
favorites: 12,
cartUsers: 9,
paymentConversionRate: 0.03,
paymentAmount: 899,
roi: 2.1,
},
{
date: '2026-07-13',
impressions: 1200,
visitors: 200,
clickRate: 0.125,
favorites: 18,
cartUsers: 12,
paymentConversionRate: 0.035,
paymentAmount: 1299.5,
roi: 2.4,
},
],
coverage: {
sourceFirstDate: '2026-07-12',
sourceLatestDate: '2026-07-13',
coveredDays: 2,
expectedDaysToDate: 2,
monitorStartDate: '2026-07-12',
monitorEndDate: '2027-01-12',
},
}
describe('PerformanceConversionDetail', () => {
const originalFetch = global.fetch
afterEach(() => {
global.fetch = originalFetch
jest.restoreAllMocks()
})
it('loads the selected product on its own page and links back to the filtered list', async () => {
const fetchMock = jest.fn().mockResolvedValue({
ok: true,
json: async () => ({ success: true, data: detailData }),
} as Response)
global.fetch = fetchMock
const returnHref = '/workspaces/business/performance-conversion?brand=%E4%BA%BF%E5%AE%B6%E8%BE%BE&page=3'
render(
<PerformanceConversionDetail
workflowId="flow-1"
productId="1041432226288"
returnHref={returnHref}
/>,
)
expect(await screen.findByRole('heading', { level: 1, name: '亿家达折叠书桌' })).toBeInTheDocument()
expect(fetchMock).toHaveBeenCalledWith(
'/api/department-dashboard/performance-conversion/timeseries?workflowId=flow-1&productId=1041432226288',
expect.objectContaining({ cache: 'no-store' }),
)
expect(screen.getByRole('link', { name: '返回业绩转化' })).toHaveAttribute('href', returnHref)
expect(screen.getByText(/经营数据更新至/)).toBeInTheDocument()
expect(screen.getAllByText('12.50%').length).toBeGreaterThan(0)
expect(screen.getAllByText('¥1,299.50').length).toBeGreaterThan(0)
expect(screen.getAllByText('——').length).toBe(3)
expect(screen.getByRole('img', { name: /支付金额从/ })).toBeInTheDocument()
expect(screen.getByRole('table')).toHaveTextContent('2026-07-13')
})
it('shows the no-data state without hiding the product and workflow metadata', async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: async () => ({
success: true,
data: { ...detailData, latest: null, daily: [] },
}),
} as Response)
render(<PerformanceConversionDetail workflowId="flow-1" productId="1041432226288" returnHref="/workspaces/business/performance-conversion" />)
expect(await screen.findByRole('heading', { name: '亿家达折叠书桌' })).toBeInTheDocument()
expect(screen.getByText('该商品在流程完结后的监控区间内暂无经营数据')).toBeInTheDocument()
expect(screen.getByText(/审批编号 202609170001/)).toBeInTheDocument()
})
it('shows the API error and allows the user to retry', async () => {
const fetchMock = jest.fn()
.mockResolvedValueOnce({
ok: false,
json: async () => ({ success: false, error: '商品 ID 不属于该流程' }),
} as Response)
.mockResolvedValueOnce({
ok: true,
json: async () => ({ success: true, data: detailData }),
} as Response)
global.fetch = fetchMock
render(<PerformanceConversionDetail workflowId="flow-1" productId="1041432226288" returnHref="/workspaces/business/performance-conversion" />)
expect(await screen.findByRole('heading', { name: '无法打开商品数据' })).toBeInTheDocument()
expect(screen.getByText('商品 ID 不属于该流程')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: '重试' }))
await waitFor(() => expect(screen.getByRole('heading', { name: '亿家达折叠书桌' })).toBeInTheDocument())
expect(fetchMock).toHaveBeenCalledTimes(2)
})
it('shows complete intent-rate averages and change when 15 days are available', async () => {
const daily = Array.from({ length: 15 }, (_, index) => ({
...detailData.daily[0],
date: `2026-07-${String(index + 1).padStart(2, '0')}`,
favorites: index < 8 ? 10 : 20,
cartUsers: 10,
visitors: 100,
paymentConversionRate: 0.03,
}))
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: async () => ({ success: true, data: { ...detailData, daily } }),
} as Response)
render(<PerformanceConversionDetail workflowId="flow-1" productId="1041432226288" returnHref="/workspaces/business/performance-conversion" />)
expect(await screen.findByText('23.00%')).toBeInTheDocument()
expect(screen.getByText('27.67%')).toBeInTheDocument()
expect(screen.getByText('20.29%')).toBeInTheDocument()
})
})