Files
flyer-crawler.projectium.com/src/pages/admin/CorrectionsPage.test.tsx
Torben Sorensen 503e7084da
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 14m41s
Adopt TanStack Query fixes
2026-01-10 17:42:45 -08:00

241 lines
7.3 KiB
TypeScript

// src/pages/admin/CorrectionsPage.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { MemoryRouter } from 'react-router-dom';
import { CorrectionsPage } from './CorrectionsPage';
import { useSuggestedCorrectionsQuery } from '../../hooks/queries/useSuggestedCorrectionsQuery';
import { useMasterItemsQuery } from '../../hooks/queries/useMasterItemsQuery';
import { useCategoriesQuery } from '../../hooks/queries/useCategoriesQuery';
import type { SuggestedCorrection, MasterGroceryItem, Category } from '../../types';
import {
createMockSuggestedCorrection,
createMockMasterGroceryItem,
createMockCategory,
} from '../../tests/utils/mockFactories';
import { QueryWrapper } from '../../tests/utils/renderWithProviders';
// Mock the TanStack Query hooks
vi.mock('../../hooks/queries/useSuggestedCorrectionsQuery');
vi.mock('../../hooks/queries/useMasterItemsQuery');
vi.mock('../../hooks/queries/useCategoriesQuery');
const mockedUseSuggestedCorrectionsQuery = vi.mocked(useSuggestedCorrectionsQuery);
const mockedUseMasterItemsQuery = vi.mocked(useMasterItemsQuery);
const mockedUseCategoriesQuery = vi.mocked(useCategoriesQuery);
// Mock the child CorrectionRow component to isolate the test to the page itself
vi.mock('./components/CorrectionRow', async () => {
const { MockCorrectionRow } = await import('../../tests/utils/componentMocks');
return { CorrectionRow: MockCorrectionRow };
});
// Helper to render the component within router and query contexts
const renderWithRouter = () => {
return render(
<QueryWrapper>
<MemoryRouter>
<CorrectionsPage />
</MemoryRouter>
</QueryWrapper>,
);
};
describe('CorrectionsPage', () => {
const mockCorrections: SuggestedCorrection[] = [
createMockSuggestedCorrection({
suggested_correction_id: 1,
flyer_item_id: 101,
user_id: 'user-1',
correction_type: 'item_name',
suggested_value: 'Organic Bananas',
flyer_item_name: 'Bananas',
user_email: 'test@example.com',
}),
createMockSuggestedCorrection({
suggested_correction_id: 2,
flyer_item_id: 102,
user_id: 'user-2',
correction_type: 'price_in_cents',
suggested_value: '199',
flyer_item_name: 'Apples',
user_email: 'test2@example.com',
}),
];
const mockMasterItems: MasterGroceryItem[] = [
createMockMasterGroceryItem({
master_grocery_item_id: 1,
name: 'Organic Bananas',
category_id: 1,
category_name: 'Produce',
}),
];
const mockCategories: Category[] = [createMockCategory({ category_id: 1, name: 'Produce' })];
const mockRefetch = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
// Default mock implementations for the hooks
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: [],
isLoading: false,
error: null,
refetch: mockRefetch,
} as any);
mockedUseMasterItemsQuery.mockReturnValue({
data: [],
isLoading: false,
error: null,
} as any);
mockedUseCategoriesQuery.mockReturnValue({
data: [],
isLoading: false,
error: null,
} as any);
});
it('should render a loading spinner while fetching data', async () => {
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: undefined,
isLoading: true,
error: null,
refetch: mockRefetch,
} as any);
renderWithRouter();
expect(screen.getByRole('status', { name: /loading/i })).toBeInTheDocument();
});
it('should display corrections when data is fetched successfully', async () => {
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: mockCorrections,
isLoading: false,
error: null,
refetch: mockRefetch,
} as any);
mockedUseMasterItemsQuery.mockReturnValue({
data: mockMasterItems,
isLoading: false,
error: null,
} as any);
mockedUseCategoriesQuery.mockReturnValue({
data: mockCategories,
isLoading: false,
error: null,
} as any);
renderWithRouter();
// Check for the mocked CorrectionRow components
expect(screen.getByTestId('correction-row-1')).toBeInTheDocument();
expect(screen.getByTestId('correction-row-2')).toBeInTheDocument();
// Check for the text content within the mocked rows
expect(screen.getByText('Bananas')).toBeInTheDocument();
expect(screen.getByText('Apples')).toBeInTheDocument();
});
it('should display a message when there are no pending corrections', async () => {
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: [],
isLoading: false,
error: null,
refetch: mockRefetch,
} as any);
mockedUseMasterItemsQuery.mockReturnValue({
data: mockMasterItems,
isLoading: false,
error: null,
} as any);
mockedUseCategoriesQuery.mockReturnValue({
data: mockCategories,
isLoading: false,
error: null,
} as any);
renderWithRouter();
expect(screen.getByText(/no pending corrections. great job!/i)).toBeInTheDocument();
});
it('should display an error message if fetching corrections fails', async () => {
const errorMessage = 'Network Error: Failed to fetch';
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: undefined,
isLoading: false,
error: new Error(errorMessage),
refetch: mockRefetch,
} as any);
mockedUseMasterItemsQuery.mockReturnValue({
data: mockMasterItems,
isLoading: false,
error: null,
} as any);
mockedUseCategoriesQuery.mockReturnValue({
data: mockCategories,
isLoading: false,
error: null,
} as any);
renderWithRouter();
expect(screen.getByText(errorMessage)).toBeInTheDocument();
});
it('should call refetch when the refresh button is clicked', async () => {
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: mockCorrections,
isLoading: false,
error: null,
refetch: mockRefetch,
} as any);
mockedUseMasterItemsQuery.mockReturnValue({
data: mockMasterItems,
isLoading: false,
error: null,
} as any);
mockedUseCategoriesQuery.mockReturnValue({
data: mockCategories,
isLoading: false,
error: null,
} as any);
renderWithRouter();
expect(screen.getByText('Bananas')).toBeInTheDocument();
// Click refresh
const refreshButton = screen.getByTitle('Refresh Corrections');
fireEvent.click(refreshButton);
expect(mockRefetch).toHaveBeenCalledTimes(1);
});
it('should call onProcessed callback when a correction is processed', async () => {
mockedUseSuggestedCorrectionsQuery.mockReturnValue({
data: mockCorrections,
isLoading: false,
error: null,
refetch: mockRefetch,
} as any);
mockedUseMasterItemsQuery.mockReturnValue({
data: mockMasterItems,
isLoading: false,
error: null,
} as any);
mockedUseCategoriesQuery.mockReturnValue({
data: mockCategories,
isLoading: false,
error: null,
} as any);
renderWithRouter();
expect(screen.getByTestId('correction-row-1')).toBeInTheDocument();
// Click the process button in the mock row for ID 1
fireEvent.click(screen.getByTestId('process-btn-1'));
// The onProcessed callback should trigger a refetch
expect(mockRefetch).toHaveBeenCalledTimes(1);
});
});