Files
smoothschedule/frontend/src/api/__tests__/notifications.test.ts
poduck 8dc2248f1f feat: Add comprehensive test suite and misc improvements
- Add frontend unit tests with Vitest for components, hooks, pages, and utilities
- Add backend tests for webhooks, notifications, middleware, and edge cases
- Add ForgotPassword, NotFound, and ResetPassword pages
- Add migration for orphaned staff resources conversion
- Add coverage directory to gitignore (generated reports)
- Various bug fixes and improvements from previous work

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 02:36:46 -05:00

114 lines
3.2 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock apiClient
vi.mock('../client', () => ({
default: {
get: vi.fn(),
post: vi.fn(),
delete: vi.fn(),
},
}));
import {
getNotifications,
getUnreadCount,
markNotificationRead,
markAllNotificationsRead,
clearAllNotifications,
} from '../notifications';
import apiClient from '../client';
describe('notifications API', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('getNotifications', () => {
it('fetches all notifications without params', async () => {
const mockNotifications = [
{ id: 1, verb: 'created', read: false, timestamp: '2024-01-01T00:00:00Z' },
{ id: 2, verb: 'updated', read: true, timestamp: '2024-01-02T00:00:00Z' },
];
vi.mocked(apiClient.get).mockResolvedValue({ data: mockNotifications });
const result = await getNotifications();
expect(apiClient.get).toHaveBeenCalledWith('/notifications/');
expect(result).toEqual(mockNotifications);
});
it('applies read filter', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: [] });
await getNotifications({ read: false });
expect(apiClient.get).toHaveBeenCalledWith('/notifications/?read=false');
});
it('applies limit parameter', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: [] });
await getNotifications({ limit: 10 });
expect(apiClient.get).toHaveBeenCalledWith('/notifications/?limit=10');
});
it('applies multiple parameters', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: [] });
await getNotifications({ read: true, limit: 5 });
expect(apiClient.get).toHaveBeenCalledWith('/notifications/?read=true&limit=5');
});
});
describe('getUnreadCount', () => {
it('returns unread count', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: { count: 5 } });
const result = await getUnreadCount();
expect(apiClient.get).toHaveBeenCalledWith('/notifications/unread_count/');
expect(result).toBe(5);
});
it('returns 0 when no unread notifications', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: { count: 0 } });
const result = await getUnreadCount();
expect(result).toBe(0);
});
});
describe('markNotificationRead', () => {
it('marks single notification as read', async () => {
vi.mocked(apiClient.post).mockResolvedValue({});
await markNotificationRead(42);
expect(apiClient.post).toHaveBeenCalledWith('/notifications/42/mark_read/');
});
});
describe('markAllNotificationsRead', () => {
it('marks all notifications as read', async () => {
vi.mocked(apiClient.post).mockResolvedValue({});
await markAllNotificationsRead();
expect(apiClient.post).toHaveBeenCalledWith('/notifications/mark_all_read/');
});
});
describe('clearAllNotifications', () => {
it('clears all read notifications', async () => {
vi.mocked(apiClient.delete).mockResolvedValue({});
await clearAllNotifications();
expect(apiClient.delete).toHaveBeenCalledWith('/notifications/clear_all/');
});
});
});