Some checks failed
Dev CI / Notify Failure (push) Blocked by required conditions
Dev CI / Frontend — Lint & Type-check (push) Failing after 6m16s
Dev CI / Frontend — Unit Tests (push) Has been skipped
Dev CI / Backend — Lint (push) Successful in 10m24s
Dev CI / Backend — Unit Tests (push) Has been cancelled
144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import { renderHook, act, waitFor } from '@testing-library/react';
|
|
import { useCompanies } from '@/hooks/useCompanies';
|
|
import { getAvailableCompanies } from '@/lib/api/csv-rates';
|
|
|
|
jest.mock('@/lib/api/csv-rates', () => ({
|
|
getAvailableCompanies: jest.fn(),
|
|
}));
|
|
|
|
const mockGetAvailableCompanies = jest.mocked(getAvailableCompanies);
|
|
|
|
const MOCK_COMPANIES = ['Maersk', 'MSC', 'CMA CGM', 'Hapag-Lloyd'];
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('useCompanies', () => {
|
|
describe('initial state', () => {
|
|
it('starts with loading=true', () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
const { result } = renderHook(() => useCompanies());
|
|
expect(result.current.loading).toBe(true);
|
|
});
|
|
|
|
it('starts with an empty companies array', () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
const { result } = renderHook(() => useCompanies());
|
|
expect(result.current.companies).toEqual([]);
|
|
});
|
|
|
|
it('starts with error=null', () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
const { result } = renderHook(() => useCompanies());
|
|
expect(result.current.error).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('on mount — success', () => {
|
|
it('fetches companies automatically on mount', async () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
|
|
renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => {
|
|
expect(mockGetAvailableCompanies).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
it('populates companies after a successful fetch', async () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.companies).toEqual(MOCK_COMPANIES);
|
|
expect(result.current.error).toBeNull();
|
|
});
|
|
|
|
it('handles an empty companies list', async () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: [], total: 0 });
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.companies).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('on mount — error', () => {
|
|
it('sets error when the API call fails', async () => {
|
|
mockGetAvailableCompanies.mockRejectedValue(new Error('Service unavailable'));
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.error).toBe('Service unavailable');
|
|
expect(result.current.companies).toEqual([]);
|
|
});
|
|
|
|
it('uses a default error message when the error has no message', async () => {
|
|
mockGetAvailableCompanies.mockRejectedValue({});
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.error).toBe('Failed to fetch companies');
|
|
});
|
|
});
|
|
|
|
describe('refetch', () => {
|
|
it('exposes a refetch function', async () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
|
|
expect(typeof result.current.refetch).toBe('function');
|
|
});
|
|
|
|
it('re-triggers the API call when refetch is invoked', async () => {
|
|
mockGetAvailableCompanies.mockResolvedValue({ companies: MOCK_COMPANIES, total: 4 });
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
|
|
await act(async () => {
|
|
await result.current.refetch();
|
|
});
|
|
|
|
expect(mockGetAvailableCompanies).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('updates companies with fresh data on refetch', async () => {
|
|
mockGetAvailableCompanies
|
|
.mockResolvedValueOnce({ companies: ['Maersk'], total: 1 })
|
|
.mockResolvedValueOnce({ companies: ['Maersk', 'MSC'], total: 2 });
|
|
|
|
const { result } = renderHook(() => useCompanies());
|
|
|
|
await waitFor(() => expect(result.current.companies).toEqual(['Maersk']));
|
|
|
|
await act(async () => {
|
|
await result.current.refetch();
|
|
});
|
|
|
|
expect(result.current.companies).toEqual(['Maersk', 'MSC']);
|
|
});
|
|
});
|
|
});
|