import { describe, it, expect, vi, beforeEach, beforeAll } from 'vitest'; // FIX: Mock the local re-export, not the library directly. // This is more stable and ensures the service under test gets the mock. vi.mock('../lib/toast'); describe('Notification Service', () => { beforeAll(() => { // Strategy #6: Verify JSDOM Window and stub missing browser APIs. // libraries like react-hot-toast often rely on window.matchMedia or similar. if (typeof window === 'undefined') { throw new Error('Test environment is not JSDOM. Window is undefined.'); } // Polyfill matchMedia if it doesn't exist (common JSDOM issue) Object.defineProperty(window, 'matchMedia', { writable: true, value: vi.fn().mockImplementation(query => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), // deprecated removeListener: vi.fn(), // deprecated addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }); }); beforeEach(() => { // We need to reset modules to re-import the service with the mock vi.resetModules(); vi.clearAllMocks(); }); describe('notifySuccess', () => { it('should call the injected toaster.success with correct options', async () => { // Dynamically import the modules AFTER mocks are set up const { default: toast } = await import('../lib/toast'); const { notifySuccess } = await import('./notificationService'); const message = 'Operation was successful!'; notifySuccess(message); expect(toast.success).toHaveBeenCalledTimes(1); expect(toast.success).toHaveBeenCalledWith( message, expect.objectContaining({ style: expect.any(Object), iconTheme: { primary: '#10B981', secondary: '#fff', }, }) ); }); }); describe('notifyError', () => { it('should call the injected toaster.error with correct options', async () => { const { default: toast } = await import('../lib/toast'); const { notifyError } = await import('./notificationService'); const message = 'Something went wrong!'; notifyError(message); expect(toast.error).toHaveBeenCalledTimes(1); expect(toast.error).toHaveBeenCalledWith( message, expect.objectContaining({ style: expect.any(Object), iconTheme: { primary: '#EF4444', secondary: '#fff', }, }) ); }); }); });