| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- import { describe, expect, it } from 'vitest';
- import { render, screen } from '@testing-library/react';
- import type { FunnelQueryResponse } from '../../../api/types';
- import { FunnelResult } from '../components/FunnelResult';
- function renderResult(props: Parameters<typeof FunnelResult>[0]) {
- return render(<FunnelResult {...props} />);
- }
- const readyData: FunnelQueryResponse = {
- period: 'last_7d',
- snapshot_dt: '20260623',
- data_status: 'ready',
- results: [
- {
- step_index: 1,
- name: '启动',
- event_key: 'start',
- uv: 10000,
- conversion_rate: null,
- dropoff_rate: null,
- },
- {
- step_index: 2,
- name: '曝光',
- event_key: 'show',
- uv: 8200,
- conversion_rate: 0.82,
- dropoff_rate: 0.18,
- },
- ],
- };
- const baseProps = {
- period: 'last_7d' as const,
- isLoading: false,
- isError: false,
- };
- describe('FunnelResult states', () => {
- it('ready: renders funnel chart and result table', async () => {
- renderResult({ ...baseProps, data: readyData });
- // FunnelChart is lazy-loaded — await its appearance.
- expect(await screen.findByTestId('funnel-chart')).toBeInTheDocument();
- expect(screen.getByText('UV')).toBeInTheDocument();
- expect(screen.getByText('转化率')).toBeInTheDocument();
- expect(screen.getByText('流失率')).toBeInTheDocument();
- expect(screen.getByText(/启动/)).toBeInTheDocument();
- expect(screen.getByText(/曝光/)).toBeInTheDocument();
- });
- it('ready (7d): shows the rolling "数据截至 … (近 7 天)" caption', () => {
- renderResult({ ...baseProps, data: readyData });
- expect(
- screen.getByText(/数据截至 2026-06-23(近 7 天)/),
- ).toBeInTheDocument();
- expect(screen.queryByText(/数据快照日/)).not.toBeInTheDocument();
- });
- it('ready (30d): caption says (近 30 天)', () => {
- renderResult({
- ...baseProps,
- period: 'last_30d',
- data: { ...readyData, period: 'last_30d' },
- });
- expect(
- screen.getByText(/数据截至 2026-06-23(近 30 天)/),
- ).toBeInTheDocument();
- });
- it('ready (day): shows the "数据快照日" caption', () => {
- renderResult({
- ...baseProps,
- period: 'day',
- data: { ...readyData, period: 'day' },
- });
- expect(screen.getByText(/数据快照日:2026-06-23/)).toBeInTheDocument();
- expect(screen.queryByText(/数据截至/)).not.toBeInTheDocument();
- });
- it('ready: step 1 null conversion renders as "—", not 0%', () => {
- renderResult({ ...baseProps, data: readyData });
- const dashes = screen.getAllByText('—');
- // step 1 conversion + dropoff = two em-dashes
- expect(dashes.length).toBeGreaterThanOrEqual(2);
- expect(screen.queryByText('0%')).not.toBeInTheDocument();
- expect(screen.queryByText('0.00%')).not.toBeInTheDocument();
- // the real value still shows
- expect(screen.getByText('82.00%')).toBeInTheDocument();
- });
- it('missing: explicit 数据缺失 empty state, no zeros / no chart', () => {
- renderResult({
- ...baseProps,
- data: { ...readyData, results: [], data_status: 'missing' },
- });
- expect(screen.getByText(/数据缺失/)).toBeInTheDocument();
- expect(screen.queryByTestId('funnel-chart')).not.toBeInTheDocument();
- expect(screen.queryByText('0')).not.toBeInTheDocument();
- });
- it('request error: shows error state with message', () => {
- renderResult({
- ...baseProps,
- isError: true,
- errorMessage: '网络请求失败',
- });
- expect(screen.getByText('查询失败')).toBeInTheDocument();
- expect(screen.getByText('网络请求失败')).toBeInTheDocument();
- });
- it('loading / no data yet: shows loading card', () => {
- renderResult({ ...baseProps, isLoading: true });
- expect(screen.getByTestId('funnel-loading')).toBeInTheDocument();
- });
- });
|