mirror of
https://github.com/wahyd4/heygo.git
synced 2026-08-09 05:15:52 +10:00
99 lines
3.2 KiB
TypeScript
99 lines
3.2 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
ApiClientError,
|
|
deleteNotification,
|
|
deleteNotifications,
|
|
getUnreadNotificationCount,
|
|
listNotifications,
|
|
} from '../src/lib/api';
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
function mockFetch(responder: (input: RequestInfo | URL, init?: RequestInit) => {
|
|
status?: number;
|
|
body?: unknown;
|
|
statusText?: string;
|
|
}) {
|
|
const calls: { path: string; init?: RequestInit }[] = [];
|
|
const fetchMock = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
const path = typeof input === 'string' ? input : new URL(input.toString()).pathname;
|
|
calls.push({ path, init });
|
|
const { status = 200, body = {}, statusText = 'OK' } = responder(input, init);
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
statusText,
|
|
headers: { 'content-type': 'application/json' },
|
|
});
|
|
});
|
|
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
return { calls, fetchMock };
|
|
}
|
|
|
|
afterEach(() => {
|
|
globalThis.fetch = originalFetch;
|
|
});
|
|
|
|
describe('notifications api client', () => {
|
|
it('listNotifications GETs /api/notifications with credentials', async () => {
|
|
const { calls } = mockFetch(() => ({
|
|
body: { notifications: [{ id: 'n1', title: 'A', kind: 'promotion_approved', status: 'viewed' }] },
|
|
}));
|
|
|
|
const result = await listNotifications();
|
|
|
|
expect(calls[0].path).toBe('/api/notifications');
|
|
expect(calls[0].init?.method).toBeUndefined();
|
|
expect(calls[0].init?.credentials).toBe('include');
|
|
expect(result.notifications).toHaveLength(1);
|
|
});
|
|
|
|
it('getUnreadNotificationCount GETs the unread-count endpoint', async () => {
|
|
const { calls } = mockFetch(() => ({ body: { count: 3 } }));
|
|
|
|
const result = await getUnreadNotificationCount();
|
|
|
|
expect(calls[0].path).toBe('/api/notifications/unread-count');
|
|
expect(result.count).toBe(3);
|
|
});
|
|
|
|
it('deleteNotification issues DELETE to /api/notifications/:id', async () => {
|
|
const { calls } = mockFetch(() => ({ body: { ok: true } }));
|
|
|
|
const result = await deleteNotification('n1');
|
|
|
|
expect(calls[0].path).toBe('/api/notifications/n1');
|
|
expect(calls[0].init?.method).toBe('DELETE');
|
|
expect(result.ok).toBe(true);
|
|
});
|
|
|
|
it('deleteNotifications POSTs the ids array to the batch endpoint', async () => {
|
|
const { calls } = mockFetch(() => ({ body: { ok: true, deleted: 2 } }));
|
|
|
|
const result = await deleteNotifications(['n1', 'n2']);
|
|
|
|
expect(calls[0].path).toBe('/api/notifications/delete-batch');
|
|
expect(calls[0].init?.method).toBe('POST');
|
|
const body = JSON.parse(calls[0].init?.body as string);
|
|
expect(body).toEqual({ ids: ['n1', 'n2'] });
|
|
expect(result.deleted).toBe(2);
|
|
});
|
|
|
|
it('encodes notification ids with special characters', async () => {
|
|
const { calls } = mockFetch(() => ({ body: { ok: true } }));
|
|
|
|
await deleteNotification('a/b');
|
|
|
|
expect(calls[0].path).toBe('/api/notifications/a%2Fb');
|
|
});
|
|
|
|
it('surfaces server errors as ApiClientError', async () => {
|
|
mockFetch(() => ({ status: 401, body: { error: 'Authentication required' } }));
|
|
|
|
await expect(listNotifications()).rejects.toMatchObject({
|
|
name: 'ApiClientError',
|
|
status: 401,
|
|
message: 'Authentication required',
|
|
});
|
|
});
|
|
});
|