File size: 3,539 Bytes
eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce a372176 eee11ce |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import Topics from '../../components/Topics';
describe('Topics Component', () => {
const mockOnTopicChange = jest.fn();
const mockFetch = jest.fn();
global.fetch = mockFetch;
beforeEach(() => {
jest.clearAllMocks();
mockFetch.mockClear();
});
it('shows loading state initially', () => {
render(<Topics onTopicChange={mockOnTopicChange} />);
expect(screen.getByLabelText('Topic')).toBeDisabled();
expect(screen.getByText('Loading topics...')).toBeInTheDocument();
});
it('displays topics after successful fetch', async () => {
const mockTopics = { sources: ['Topic 1', 'Topic 2', 'Topic 3'] };
mockFetch.mockImplementationOnce(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(mockTopics),
})
);
render(<Topics onTopicChange={mockOnTopicChange} />);
// Wait for loading to finish
await waitFor(() => {
expect(screen.queryByText('Loading topics...')).not.toBeInTheDocument();
});
// Open the dropdown
fireEvent.mouseDown(screen.getByLabelText('Topic'));
// Check if all topics are rendered
mockTopics.sources.forEach(topic => {
expect(screen.getByText(topic)).toBeInTheDocument();
});
});
it('handles API error correctly', async () => {
mockFetch.mockImplementationOnce(() =>
Promise.resolve({
ok: false,
status: 500,
})
);
render(<Topics onTopicChange={mockOnTopicChange} />);
await waitFor(() => {
expect(screen.queryByText('Loading topics...')).not.toBeInTheDocument();
});
const select = screen.getByLabelText('Topic');
expect(select).toHaveAttribute('aria-invalid', 'true');
});
it('calls onTopicChange when topic is selected', async () => {
const mockTopics = { sources: ['Topic 1', 'Topic 2'] };
mockFetch.mockImplementationOnce(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(mockTopics),
})
);
render(<Topics onTopicChange={mockOnTopicChange} />);
// Wait for loading to finish
await waitFor(() => {
expect(screen.queryByText('Loading topics...')).not.toBeInTheDocument();
});
// Open the dropdown
fireEvent.mouseDown(screen.getByLabelText('Topic'));
// Select a topic
fireEvent.click(screen.getByText('Topic 1'));
expect(mockOnTopicChange).toHaveBeenCalledWith('Topic 1');
});
it('handles malformed API response correctly', async () => {
const malformedResponse = { wrongKey: [] };
mockFetch.mockImplementationOnce(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(malformedResponse),
})
);
render(<Topics onTopicChange={mockOnTopicChange} />);
await waitFor(() => {
expect(screen.queryByText('Loading topics...')).not.toBeInTheDocument();
});
const select = screen.getByLabelText('Topic');
expect(select).toHaveAttribute('aria-invalid', 'true');
});
it('handles network errors correctly', async () => {
mockFetch.mockImplementationOnce(() =>
Promise.reject(new Error('Network error'))
);
render(<Topics onTopicChange={mockOnTopicChange} />);
await waitFor(() => {
expect(screen.queryByText('Loading topics...')).not.toBeInTheDocument();
});
const select = screen.getByLabelText('Topic');
expect(select).toHaveAttribute('aria-invalid', 'true');
});
}); |