Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 46s
202 lines
6.1 KiB
TypeScript
202 lines
6.1 KiB
TypeScript
// src/hooks/useWatchedItems.test.tsx
|
|
import { renderHook, act } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { useWatchedItems } from './useWatchedItems';
|
|
import { useAuth } from '../hooks/useAuth';
|
|
import { useUserData } from '../hooks/useUserData';
|
|
import { useAddWatchedItemMutation, useRemoveWatchedItemMutation } from './mutations';
|
|
import type { User } from '../types';
|
|
import {
|
|
createMockMasterGroceryItem,
|
|
createMockUser,
|
|
createMockUserProfile,
|
|
} from '../tests/utils/mockFactories';
|
|
|
|
// Mock the hooks that useWatchedItems depends on
|
|
vi.mock('../hooks/useAuth');
|
|
vi.mock('../hooks/useUserData');
|
|
vi.mock('./mutations', () => ({
|
|
useAddWatchedItemMutation: vi.fn(),
|
|
useRemoveWatchedItemMutation: vi.fn(),
|
|
}));
|
|
|
|
const mockedUseAuth = vi.mocked(useAuth);
|
|
const mockedUseUserData = vi.mocked(useUserData);
|
|
const mockedUseAddWatchedItemMutation = vi.mocked(useAddWatchedItemMutation);
|
|
const mockedUseRemoveWatchedItemMutation = vi.mocked(useRemoveWatchedItemMutation);
|
|
|
|
const mockUser: User = createMockUser({ user_id: 'user-123', email: 'test@example.com' });
|
|
const mockInitialItems = [
|
|
createMockMasterGroceryItem({ master_grocery_item_id: 1, name: 'Milk' }),
|
|
createMockMasterGroceryItem({ master_grocery_item_id: 2, name: 'Bread' }),
|
|
];
|
|
|
|
describe('useWatchedItems Hook', () => {
|
|
const mockMutateAsync = vi.fn();
|
|
const mockAddMutation = {
|
|
mutateAsync: mockMutateAsync,
|
|
mutate: vi.fn(),
|
|
isPending: false,
|
|
error: null,
|
|
isError: false,
|
|
isSuccess: false,
|
|
isIdle: true,
|
|
};
|
|
const mockRemoveMutation = {
|
|
mutateAsync: mockMutateAsync,
|
|
mutate: vi.fn(),
|
|
isPending: false,
|
|
error: null,
|
|
isError: false,
|
|
isSuccess: false,
|
|
isIdle: true,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
|
|
// Mock TanStack Query mutation hooks
|
|
mockedUseAddWatchedItemMutation.mockReturnValue(mockAddMutation as any);
|
|
mockedUseRemoveWatchedItemMutation.mockReturnValue(mockRemoveMutation as any);
|
|
|
|
// Provide default implementation for auth
|
|
mockedUseAuth.mockReturnValue({
|
|
userProfile: createMockUserProfile({ user: mockUser }),
|
|
authStatus: 'AUTHENTICATED',
|
|
isLoading: false,
|
|
login: vi.fn(),
|
|
logout: vi.fn(),
|
|
updateProfile: vi.fn(),
|
|
});
|
|
|
|
// Provide default implementation for user data (no more setters!)
|
|
mockedUseUserData.mockReturnValue({
|
|
watchedItems: mockInitialItems,
|
|
shoppingLists: [],
|
|
isLoading: false,
|
|
error: null,
|
|
});
|
|
});
|
|
|
|
it('should initialize with the watched items from useData', () => {
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
expect(result.current.watchedItems).toEqual(mockInitialItems);
|
|
expect(result.current.error).toBeNull();
|
|
});
|
|
|
|
it('should use TanStack Query mutation hooks', () => {
|
|
renderHook(() => useWatchedItems());
|
|
|
|
// Verify that the mutation hooks were called
|
|
expect(mockedUseAddWatchedItemMutation).toHaveBeenCalled();
|
|
expect(mockedUseRemoveWatchedItemMutation).toHaveBeenCalled();
|
|
});
|
|
|
|
describe('addWatchedItem', () => {
|
|
it('should call the mutation with correct parameters', async () => {
|
|
mockMutateAsync.mockResolvedValue({});
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
await act(async () => {
|
|
await result.current.addWatchedItem('Cheese', 'Dairy');
|
|
});
|
|
|
|
// Verify mutation was called with correct parameters
|
|
expect(mockMutateAsync).toHaveBeenCalledWith({
|
|
itemName: 'Cheese',
|
|
category: 'Dairy',
|
|
});
|
|
});
|
|
|
|
it('should expose error from mutation', () => {
|
|
const errorMutation = {
|
|
...mockAddMutation,
|
|
error: new Error('API Error'),
|
|
};
|
|
mockedUseAddWatchedItemMutation.mockReturnValue(errorMutation as any);
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
expect(result.current.error).toBe('API Error');
|
|
});
|
|
|
|
it('should handle mutation errors gracefully', async () => {
|
|
mockMutateAsync.mockRejectedValue(new Error('Failed to add'));
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
await act(async () => {
|
|
await result.current.addWatchedItem('Failing Item', 'Error');
|
|
});
|
|
|
|
// Should not throw - error is caught and logged
|
|
expect(mockMutateAsync).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('removeWatchedItem', () => {
|
|
it('should call the mutation with correct parameters', async () => {
|
|
mockMutateAsync.mockResolvedValue({});
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
await act(async () => {
|
|
await result.current.removeWatchedItem(1);
|
|
});
|
|
|
|
// Verify mutation was called with correct parameters
|
|
expect(mockMutateAsync).toHaveBeenCalledWith({
|
|
masterItemId: 1,
|
|
});
|
|
});
|
|
|
|
it('should expose error from remove mutation', () => {
|
|
const errorMutation = {
|
|
...mockRemoveMutation,
|
|
error: new Error('Deletion Failed'),
|
|
};
|
|
mockedUseRemoveWatchedItemMutation.mockReturnValue(errorMutation as any);
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
expect(result.current.error).toBe('Deletion Failed');
|
|
});
|
|
|
|
it('should handle mutation errors gracefully', async () => {
|
|
mockMutateAsync.mockRejectedValue(new Error('Failed to remove'));
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
await act(async () => {
|
|
await result.current.removeWatchedItem(999);
|
|
});
|
|
|
|
// Should not throw - error is caught and logged
|
|
expect(mockMutateAsync).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('should not perform actions if the user is not authenticated', async () => {
|
|
mockedUseAuth.mockReturnValue({
|
|
userProfile: null,
|
|
authStatus: 'SIGNED_OUT',
|
|
isLoading: false,
|
|
login: vi.fn(),
|
|
logout: vi.fn(),
|
|
updateProfile: vi.fn(),
|
|
});
|
|
|
|
const { result } = renderHook(() => useWatchedItems());
|
|
|
|
await act(async () => {
|
|
await result.current.addWatchedItem('Test', 'Category');
|
|
await result.current.removeWatchedItem(1);
|
|
});
|
|
|
|
// Mutations should not be called when user is not authenticated
|
|
expect(mockMutateAsync).not.toHaveBeenCalled();
|
|
});
|
|
});
|