import { describe, it, expect, vi, afterEach } from 'vitest'; import { render, screen, cleanup, waitFor } from '@testing-library/svelte'; // Mock the admin API so the component's onMount load() is deterministic. const listAnalysisHistory = vi.fn(); vi.mock('$lib/api/admin', () => ({ listAnalysisHistory: (...args: unknown[]) => listAnalysisHistory(...args) })); import AnalysisHistoryTable from './AnalysisHistoryTable.svelte'; afterEach(() => { cleanup(); listAnalysisHistory.mockReset(); }); function row(over: Record = {}) { return { page_id: 'p1', page_number: 1, chapter_id: 'c1', chapter_number: 5, manga_id: 'm1', manga_title: 'Berserk', status: 'done', is_nsfw: true, // even when the backend reports nsfw, the OCR UI must not surface it model: 'ocrs', error: null, analyzed_at: '2026-01-02T00:00:00Z', duration_ms: 1234, ...over }; } function resolveOnce(rows: ReturnType[]) { listAnalysisHistory.mockResolvedValue({ items: rows, page: { total: rows.length } }); } describe('AnalysisHistoryTable (OCR)', () => { it('does not render the NSFW-only filter', async () => { resolveOnce([row()]); render(AnalysisHistoryTable, { props: { onOpenDetail: () => {} } }); await waitFor(() => expect(listAnalysisHistory).toHaveBeenCalled()); expect(screen.queryByTestId('analysis-history-nsfw')).toBeNull(); }); it('does not pass an nsfw filter to the history query', async () => { resolveOnce([row()]); render(AnalysisHistoryTable, { props: { onOpenDetail: () => {} } }); await waitFor(() => expect(listAnalysisHistory).toHaveBeenCalled()); const arg = listAnalysisHistory.mock.calls[0][0] as Record; expect('nsfw' in arg).toBe(false); }); it('never shows an NSFW tag on a row, even if the row is flagged', async () => { resolveOnce([row({ is_nsfw: true })]); render(AnalysisHistoryTable, { props: { onOpenDetail: () => {} } }); await waitFor(() => expect(screen.getByText(/Berserk/)).toBeTruthy()); expect(screen.queryByText(/NSFW/i)).toBeNull(); }); });