lots more tests !
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 7m32s

This commit is contained in:
2025-12-10 21:02:01 -08:00
parent d1ff066d1b
commit b929925a6e
39 changed files with 3360 additions and 676 deletions

View File

@@ -0,0 +1,137 @@
// 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 './useAuth';
import { useData } from './useData';
import * as apiClient from '../services/apiClient';
import type { MasterGroceryItem, User } from '../types';
// Mock the hooks that useWatchedItems depends on
vi.mock('./useAuth');
vi.mock('./useData');
// The apiClient is globally mocked in our test setup, so we just need to cast it
const mockedUseAuth = vi.mocked(useAuth);
const mockedUseData = vi.mocked(useData);
const mockedApiClient = vi.mocked(apiClient);
const mockUser: User = { user_id: 'user-123', email: 'test@example.com' };
const mockInitialItems: MasterGroceryItem[] = [
{ master_grocery_item_id: 1, name: 'Milk', created_at: '' },
{ master_grocery_item_id: 2, name: 'Bread', created_at: '' },
];
describe('useWatchedItems Hook', () => {
// Create a mock setter function that we can spy on
const mockSetWatchedItems = vi.fn();
beforeEach(() => {
// Reset all mocks before each test to ensure isolation
vi.clearAllMocks();
// Provide a default implementation for the mocked hooks
mockedUseAuth.mockReturnValue({
user: mockUser,
} as any);
mockedUseData.mockReturnValue({
watchedItems: mockInitialItems,
setWatchedItems: mockSetWatchedItems,
} as any);
});
it('should initialize with the watched items from useData', () => {
const { result } = renderHook(() => useWatchedItems());
expect(result.current.watchedItems).toEqual(mockInitialItems);
expect(result.current.error).toBeNull();
});
describe('addWatchedItem', () => {
it('should call the API and update state on successful addition', async () => {
const newItem: MasterGroceryItem = { master_grocery_item_id: 3, name: 'Cheese', created_at: '' };
mockedApiClient.addWatchedItem.mockResolvedValue(new Response(JSON.stringify(newItem)));
const { result } = renderHook(() => useWatchedItems());
await act(async () => {
await result.current.addWatchedItem('Cheese', 'Dairy');
});
expect(mockedApiClient.addWatchedItem).toHaveBeenCalledWith('Cheese', 'Dairy');
// Check that the global state setter was called with an updater function
expect(mockSetWatchedItems).toHaveBeenCalledWith(expect.any(Function));
// To verify the logic inside the updater, we can call it directly
const updater = mockSetWatchedItems.mock.calls[0][0];
const newState = updater(mockInitialItems);
expect(newState).toHaveLength(3);
expect(newState).toContainEqual(newItem);
});
it('should set an error message if the API call fails', async () => {
mockedApiClient.addWatchedItem.mockRejectedValue(new Error('API Error'));
const { result } = renderHook(() => useWatchedItems());
await act(async () => {
await result.current.addWatchedItem('Failing Item', 'Error');
});
expect(result.current.error).toBe('Could not add watched item: API Error');
expect(mockSetWatchedItems).not.toHaveBeenCalled();
});
});
describe('removeWatchedItem', () => {
it('should call the API and update state on successful removal', async () => {
const itemIdToRemove = 1;
mockedApiClient.removeWatchedItem.mockResolvedValue(new Response(null, { status: 204 }));
const { result } = renderHook(() => useWatchedItems());
await act(async () => {
await result.current.removeWatchedItem(itemIdToRemove);
});
expect(mockedApiClient.removeWatchedItem).toHaveBeenCalledWith(itemIdToRemove);
expect(mockSetWatchedItems).toHaveBeenCalledWith(expect.any(Function));
// Verify the logic inside the updater function
const updater = mockSetWatchedItems.mock.calls[0][0];
const newState = updater(mockInitialItems);
expect(newState).toHaveLength(1);
expect(newState.some((item: MasterGroceryItem) => item.master_grocery_item_id === itemIdToRemove)).toBe(false);
});
it('should set an error message if the API call fails', async () => {
mockedApiClient.removeWatchedItem.mockRejectedValue(new Error('Deletion Failed'));
const { result } = renderHook(() => useWatchedItems());
await act(async () => {
await result.current.removeWatchedItem(999);
});
expect(result.current.error).toBe('Could not remove watched item: Deletion Failed');
expect(mockSetWatchedItems).not.toHaveBeenCalled();
});
});
it('should not perform actions if the user is not authenticated', async () => {
mockedUseAuth.mockReturnValue({ user: null } as any);
const { result } = renderHook(() => useWatchedItems());
await act(async () => {
await result.current.addWatchedItem('Test', 'Category');
await result.current.removeWatchedItem(1);
});
expect(mockedApiClient.addWatchedItem).not.toHaveBeenCalled();
expect(mockedApiClient.removeWatchedItem).not.toHaveBeenCalled();
});
});