// src/pages/admin/FlyerReviewPage.test.tsx import { render, screen, waitFor, within } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { FlyerReviewPage } from './FlyerReviewPage'; import { MemoryRouter } from 'react-router-dom'; import * as apiClient from '../../services/apiClient'; import { logger } from '../../services/logger.client'; // The apiClient and logger are mocked globally. // We can get a typed reference to the apiClient for individual test overrides. const mockedApiClient = vi.mocked(apiClient); // Mock LoadingSpinner to simplify DOM and avoid potential issues vi.mock('../../components/LoadingSpinner', () => ({ LoadingSpinner: () =>
Loading...
, })); describe('FlyerReviewPage', () => { beforeEach(() => { vi.clearAllMocks(); }); it('renders loading spinner initially', () => { // Mock a promise that doesn't resolve immediately to check loading state mockedApiClient.getFlyersForReview.mockReturnValue(new Promise(() => {})); render( ); expect(screen.getByRole('status', { name: /loading flyers for review/i })).toBeInTheDocument(); }); it('renders empty state when no flyers are returned', async () => { mockedApiClient.getFlyersForReview.mockResolvedValue({ ok: true, json: async () => [], } as Response); render( ); await waitFor(() => { expect(screen.queryByRole('status')).not.toBeInTheDocument(); }); expect(screen.getByText(/the review queue is empty/i)).toBeInTheDocument(); }); it('renders a list of flyers when API returns data', async () => { const mockFlyers = [ { flyer_id: 1, file_name: 'flyer1.jpg', created_at: '2023-01-01T00:00:00Z', store: { name: 'Store A' }, icon_url: 'icon1.jpg', }, { flyer_id: 2, file_name: 'flyer2.jpg', created_at: '2023-01-02T00:00:00Z', store: { name: 'Store B' }, icon_url: 'icon2.jpg', }, { flyer_id: 3, file_name: 'flyer3.jpg', created_at: '2023-01-03T00:00:00Z', store: null, icon_url: null, }, ]; mockedApiClient.getFlyersForReview.mockResolvedValue({ ok: true, json: async () => mockFlyers, } as Response); render( ); await waitFor(() => { expect(screen.queryByRole('status')).not.toBeInTheDocument(); }); expect(screen.getByText('Store A')).toBeInTheDocument(); expect(screen.getByText('flyer1.jpg')).toBeInTheDocument(); expect(screen.getByText('Store B')).toBeInTheDocument(); expect(screen.getByText('flyer2.jpg')).toBeInTheDocument(); // Test fallback for null store and icon_url expect(screen.getByText('Unknown Store')).toBeInTheDocument(); expect(screen.getByText('flyer3.jpg')).toBeInTheDocument(); const unknownStoreItem = screen.getByText('Unknown Store').closest('li'); const unknownStoreImage = within(unknownStoreItem!).getByRole('img'); expect(unknownStoreImage).not.toHaveAttribute('src'); expect(unknownStoreImage).not.toHaveAttribute('alt'); }); it('renders error message when API response is not ok', async () => { mockedApiClient.getFlyersForReview.mockResolvedValue({ ok: false, json: async () => ({ message: 'Server error' }), } as Response); render( ); await waitFor(() => { expect(screen.queryByRole('status')).not.toBeInTheDocument(); }); expect(screen.getByText('Server error')).toBeInTheDocument(); expect(logger.error).toHaveBeenCalledWith( expect.objectContaining({ err: expect.any(Error) }), 'Failed to fetch flyers for review' ); }); it('renders error message when API throws an error', async () => { const networkError = new Error('Network error'); mockedApiClient.getFlyersForReview.mockRejectedValue(networkError); render( ); await waitFor(() => { expect(screen.queryByRole('status')).not.toBeInTheDocument(); }); expect(screen.getByText('Network error')).toBeInTheDocument(); expect(logger.error).toHaveBeenCalledWith( { err: networkError }, 'Failed to fetch flyers for review' ); }); it('renders a generic error for non-Error rejections', async () => { const nonErrorRejection = { message: 'This is not an Error object' }; mockedApiClient.getFlyersForReview.mockRejectedValue(nonErrorRejection); render( , ); await waitFor(() => { expect(screen.getByText('An unknown error occurred while fetching data.')).toBeInTheDocument(); }); expect(logger.error).toHaveBeenCalledWith( { err: nonErrorRejection }, 'Failed to fetch flyers for review', ); }); });