All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 15m11s
161 lines
5.9 KiB
TypeScript
161 lines
5.9 KiB
TypeScript
// src/hooks/mutations/useAddShoppingListItemMutation.test.tsx
|
|
import { renderHook, waitFor } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import type { ReactNode } from 'react';
|
|
import { useAddShoppingListItemMutation } from './useAddShoppingListItemMutation';
|
|
import * as apiClient from '../../services/apiClient';
|
|
import * as notificationService from '../../services/notificationService';
|
|
|
|
vi.mock('../../services/apiClient');
|
|
vi.mock('../../services/notificationService');
|
|
|
|
const mockedApiClient = vi.mocked(apiClient);
|
|
const mockedNotifications = vi.mocked(notificationService);
|
|
|
|
describe('useAddShoppingListItemMutation', () => {
|
|
let queryClient: QueryClient;
|
|
|
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
);
|
|
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: { retry: false },
|
|
mutations: { retry: false },
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should add a master item to shopping list successfully', async () => {
|
|
const mockResponse = { shopping_list_item_id: 1, master_item_id: 42 };
|
|
mockedApiClient.addShoppingListItem.mockResolvedValue({
|
|
ok: true,
|
|
json: () => Promise.resolve(mockResponse),
|
|
} as Response);
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
|
|
expect(mockedApiClient.addShoppingListItem).toHaveBeenCalledWith(1, { masterItemId: 42 });
|
|
expect(mockedNotifications.notifySuccess).toHaveBeenCalledWith('Item added to shopping list');
|
|
});
|
|
|
|
it('should add a custom item to shopping list successfully', async () => {
|
|
const mockResponse = { shopping_list_item_id: 2, custom_item_name: 'Special Milk' };
|
|
mockedApiClient.addShoppingListItem.mockResolvedValue({
|
|
ok: true,
|
|
json: () => Promise.resolve(mockResponse),
|
|
} as Response);
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { customItemName: 'Special Milk' } });
|
|
|
|
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
|
|
expect(mockedApiClient.addShoppingListItem).toHaveBeenCalledWith(1, {
|
|
customItemName: 'Special Milk',
|
|
});
|
|
});
|
|
|
|
it('should invalidate shopping-lists query on success', async () => {
|
|
mockedApiClient.addShoppingListItem.mockResolvedValue({
|
|
ok: true,
|
|
json: () => Promise.resolve({}),
|
|
} as Response);
|
|
|
|
const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
|
|
expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['shopping-lists'] });
|
|
});
|
|
|
|
it('should handle API error with error message', async () => {
|
|
mockedApiClient.addShoppingListItem.mockResolvedValue({
|
|
ok: false,
|
|
status: 400,
|
|
json: () => Promise.resolve({ message: 'Item already exists' }),
|
|
} as Response);
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
|
|
expect(result.current.error?.message).toBe('Item already exists');
|
|
expect(mockedNotifications.notifyError).toHaveBeenCalledWith('Item already exists');
|
|
});
|
|
|
|
it('should handle API error when json parse fails', async () => {
|
|
mockedApiClient.addShoppingListItem.mockResolvedValue({
|
|
ok: false,
|
|
status: 500,
|
|
json: () => Promise.reject(new Error('Parse error')),
|
|
} as Response);
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
|
|
expect(result.current.error?.message).toBe('Request failed with status 500');
|
|
expect(mockedNotifications.notifyError).toHaveBeenCalledWith('Request failed with status 500');
|
|
});
|
|
|
|
it('should handle API error with empty message in response', async () => {
|
|
mockedApiClient.addShoppingListItem.mockResolvedValue({
|
|
ok: false,
|
|
status: 400,
|
|
json: () => Promise.resolve({ message: '' }),
|
|
} as Response);
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
|
|
expect(result.current.error?.message).toBe('Failed to add item to shopping list');
|
|
});
|
|
|
|
it('should handle network error', async () => {
|
|
mockedApiClient.addShoppingListItem.mockRejectedValue(new Error('Network error'));
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
|
|
expect(result.current.error?.message).toBe('Network error');
|
|
});
|
|
|
|
it('should use fallback error message when error has no message', async () => {
|
|
mockedApiClient.addShoppingListItem.mockRejectedValue(new Error(''));
|
|
|
|
const { result } = renderHook(() => useAddShoppingListItemMutation(), { wrapper });
|
|
|
|
result.current.mutate({ listId: 1, item: { masterItemId: 42 } });
|
|
|
|
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
|
|
expect(mockedNotifications.notifyError).toHaveBeenCalledWith(
|
|
'Failed to add item to shopping list',
|
|
);
|
|
});
|
|
});
|