import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'; import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/svelte'; vi.mock('../lib/client', () => { const real = vi.importActual('../lib/client'); return { ...real, getDataset: vi.fn(), getDatasetPreview: vi.fn(), createDataset: vi.fn() }; }); import DatasetCard from '../components/DatasetCard.svelte'; import { getDataset, getDatasetPreview } from '../lib/client'; import type { Dataset, DatasetPreview } from '../lib/types'; const readyDs: Dataset = { id: 'ds-ready-1', name: '国泰自由现金流-20251231-20260917', request: { instruments: [ { symbol: '159399', market: 'SZ', asset_type: 'etf', name: '国泰自由现金流ETF', currency: null } ], start_date: '2025-12-31', end_date: '2026-09-17', frequency: 'daily', adjustment: 'none', fields: ['open', 'high', 'low', 'close', 'volume'] }, status: 'ready', created_at: '2026-09-17T01:00:00Z' }; const preview: DatasetPreview = { columns: ['date', 'open', 'high', 'low', 'close', 'volume'], rows: [ { date: '2026-09-16', open: 1.001, high: 1.001, low: 0.982, close: 0.992, volume: 144526400 } ], coverage: [ { instrument: '159399', market: 'SZ', asset_type: 'etf', requested_start: '2025-12-31', requested_end: '2026-09-17', actual_start: '2025-12-31', actual_end: '2026-09-16', row_count: 173, warnings: [ 'sina volume unit is 股 (shares)', 'provider_fallback: eastmoney attempt failed; served by sina', 'actual coverage 2025-12-31..2026-09-16 differs from request; gaps kept' ] } ], warnings: [] }; beforeEach(() => { vi.mocked(getDataset).mockResolvedValue(readyDs); vi.mocked(getDatasetPreview).mockReset(); }); afterEach(() => cleanup()); describe('per-instrument provenance warnings must be visible even without the range warning banner (159399 units/provider_fallback disclosure)', () => { it('renders 夲-instrument sina volume-unit and provider_fallback warnings even when the common range banner shows 覆盖平稳', async () => { vi.mocked(getDatasetPreview).mockResolvedValue(preview); render(DatasetCard, { props: { dsId: 'ds-ready-1' } }); const btn = await screen.findByRole('button', { name: /查看数据覆盖预览/ }); await fireEvent.click(btn); await waitFor(() => { expect(screen.getByText(/provider_fallback/)).toBeTruthy(); expect(screen.getByText(/volume unit is 股/)).toBeTruthy(); expect(screen.getByText(/differs from request/)).toBeTruthy(); }); }); it('no warnings: shows the plain 覆盖平稳 banner and no warning list', async () => { vi.mocked(getDatasetPreview).mockResolvedValue({ ...preview, coverage: [{ ...preview.coverage[0], warnings: [] }] }); render(DatasetCard, { props: { dsId: 'ds-ready-1' } }); const btn = await screen.findByRole('button', { name: /查看数据覆盖预览/ }); await fireEvent.click(btn); await screen.findByText(/覆盖平稳/); expect(screen.queryByText(/provider_fallback/)).toBeNull(); }); });