diff --git a/country-explorer/src/components/App.test.tsx b/country-explorer/src/components/App.test.tsx new file mode 100644 index 0000000..ee57e11 --- /dev/null +++ b/country-explorer/src/components/App.test.tsx @@ -0,0 +1,84 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { getCountriesByRegion } from '../api/countries'; +import { mockCountries } from '../test/fixtures'; +import App from './App'; + +vi.mock('../api/countries', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, getCountriesByRegion: vi.fn() }; +}); + +const mockedGetCountriesByRegion = vi.mocked(getCountriesByRegion); + +function renderApp() { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + return render( + + + , + ); +} + +beforeEach(() => { + window.sessionStorage.clear(); + window.localStorage.clear(); + mockedGetCountriesByRegion.mockResolvedValue(mockCountries); +}); + +describe('App navigation', () => { + it('shows the first country by default with the previous button disabled', async () => { + renderApp(); + + await screen.findByRole('heading', { name: 'Norway' }); + + expect(screen.getByText('Country 1 of 2')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Previous country' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Next country' })).toBeEnabled(); + }); + + it('moves to the next country when the next button is clicked', async () => { + renderApp(); + await screen.findByRole('heading', { name: 'Norway' }); + + fireEvent.click(screen.getByRole('button', { name: 'Next country' })); + + expect(screen.getByRole('heading', { name: 'Sweden' })).toBeInTheDocument(); + expect(screen.getByText('Country 2 of 2')).toBeInTheDocument(); + }); + + it('moves back to the previous country when the previous button is clicked', async () => { + renderApp(); + await screen.findByRole('heading', { name: 'Norway' }); + + fireEvent.click(screen.getByRole('button', { name: 'Next country' })); + fireEvent.click(screen.getByRole('button', { name: 'Previous country' })); + + expect(screen.getByRole('heading', { name: 'Norway' })).toBeInTheDocument(); + expect(screen.getByText('Country 1 of 2')).toBeInTheDocument(); + }); + + it('shows the selected country when chosen directly from the selector', async () => { + renderApp(); + await screen.findByRole('heading', { name: 'Norway' }); + + fireEvent.change(screen.getByLabelText('Country'), { target: { value: 'SWE' } }); + + expect(screen.getByRole('heading', { name: 'Sweden' })).toBeInTheDocument(); + expect(screen.getByText('Stockholm')).toBeInTheDocument(); + expect(screen.getByText('Country 2 of 2')).toBeInTheDocument(); + }); + + it('disables next at the last country and previous at the first country', async () => { + renderApp(); + await screen.findByRole('heading', { name: 'Norway' }); + + expect(screen.getByRole('button', { name: 'Previous country' })).toBeDisabled(); + + fireEvent.click(screen.getByRole('button', { name: 'Next country' })); + + expect(screen.getByRole('heading', { name: 'Sweden' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Next country' })).toBeDisabled(); + }); +});