6879c756f2
- E-Mail-Planer: Anspruch vor dem Senden (genau eine Mail je Faelligkeit, hoechstens 3 Versuche), Systemlesen nur fuer die Kandidatenabfrage - MailService.sendReminderEmail (Berliner Zeit, nur Text), GET /reminders/email-status, Haken im Formular mit Erklaerung - Zugriffsklassifikation und Erlaubnisliste fuer forSystem nachgezogen, Aenderungsliste und Anwenderanleitung Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
96 lines
3.8 KiB
TypeScript
96 lines
3.8 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
ReminderRequestError,
|
|
createReminder,
|
|
deleteReminder,
|
|
getReminderEmailStatus,
|
|
listReminders,
|
|
snoozeReminder,
|
|
updateReminder,
|
|
} from './reminders-api';
|
|
|
|
const fetchMock = vi.fn();
|
|
|
|
beforeEach(() => {
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
});
|
|
|
|
afterEach(() => {
|
|
fetchMock.mockReset();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
const ok = (body: unknown) => ({ ok: true, status: 200, json: async () => body });
|
|
|
|
describe('reminders-api', () => {
|
|
it('listReminders ruft GET /reminders mit Cookie-Anmeldung', async () => {
|
|
fetchMock.mockResolvedValue(ok([]));
|
|
await expect(listReminders()).resolves.toEqual([]);
|
|
const [url, init] = fetchMock.mock.calls[0];
|
|
expect(url).toMatch(/\/reminders$/);
|
|
expect(init.credentials).toBe('include');
|
|
});
|
|
|
|
it('createReminder schickt POST mit JSON-Koerper', async () => {
|
|
fetchMock.mockResolvedValue(ok({ id: 'r1' }));
|
|
await createReminder({ title: 'a', dueAt: '2099-01-01T10:00:00.000Z' });
|
|
const [url, init] = fetchMock.mock.calls[0];
|
|
expect(url).toMatch(/\/reminders$/);
|
|
expect(init.method).toBe('POST');
|
|
expect(init.credentials).toBe('include');
|
|
expect(JSON.parse(init.body)).toEqual({ title: 'a', dueAt: '2099-01-01T10:00:00.000Z' });
|
|
});
|
|
|
|
it('updateReminder schickt PATCH an /reminders/:id', async () => {
|
|
fetchMock.mockResolvedValue(ok({ id: 'r 1' }));
|
|
await updateReminder('r 1', { title: 'neu' });
|
|
const [url, init] = fetchMock.mock.calls[0];
|
|
expect(url).toMatch(/\/reminders\/r%201$/);
|
|
expect(init.method).toBe('PATCH');
|
|
expect(init.credentials).toBe('include');
|
|
expect(JSON.parse(init.body)).toEqual({ title: 'neu' });
|
|
});
|
|
|
|
it('snoozeReminder schickt POST /reminders/:id/snooze mit dueAt', async () => {
|
|
fetchMock.mockResolvedValue(ok({ id: 'r1' }));
|
|
await snoozeReminder('r1', '2099-01-01T10:00:00.000Z');
|
|
const [url, init] = fetchMock.mock.calls[0];
|
|
expect(url).toMatch(/\/reminders\/r1\/snooze$/);
|
|
expect(init.method).toBe('POST');
|
|
expect(JSON.parse(init.body)).toEqual({ dueAt: '2099-01-01T10:00:00.000Z' });
|
|
});
|
|
|
|
it('deleteReminder schickt DELETE an /reminders/:id', async () => {
|
|
fetchMock.mockResolvedValue(ok({ deleted: true }));
|
|
await expect(deleteReminder('r1')).resolves.toEqual({ deleted: true });
|
|
const [url, init] = fetchMock.mock.calls[0];
|
|
expect(url).toMatch(/\/reminders\/r1$/);
|
|
expect(init.method).toBe('DELETE');
|
|
expect(init.credentials).toBe('include');
|
|
});
|
|
|
|
it('getReminderEmailStatus ruft GET /reminders/email-status', async () => {
|
|
fetchMock.mockResolvedValue(ok({ smtpConfigured: true, hasEmail: false }));
|
|
await expect(getReminderEmailStatus()).resolves.toEqual({ smtpConfigured: true, hasEmail: false });
|
|
const [url, init] = fetchMock.mock.calls[0];
|
|
expect(url).toMatch(/\/reminders\/email-status$/);
|
|
expect(init.credentials).toBe('include');
|
|
});
|
|
|
|
it('bei 404 und 409 tragen die Fehler den Status', async () => {
|
|
fetchMock.mockResolvedValue({ ok: false, status: 404, json: async () => ({}) });
|
|
await expect(deleteReminder('x')).rejects.toMatchObject({ status: 404 });
|
|
fetchMock.mockResolvedValue({ ok: false, status: 409, json: async () => ({}) });
|
|
await expect(snoozeReminder('x', 'y')).rejects.toMatchObject({ status: 409 });
|
|
});
|
|
|
|
it('ein Status ausserhalb 2xx wirft ReminderRequestError mit diesem Status', async () => {
|
|
fetchMock.mockResolvedValue({ ok: false, status: 401, json: async () => ({}) });
|
|
await expect(listReminders()).rejects.toMatchObject({ status: 401 });
|
|
fetchMock.mockResolvedValue({ ok: false, status: 409, json: async () => ({}) });
|
|
const err = await createReminder({ title: 'a', dueAt: 'x' }).catch((e) => e);
|
|
expect(err).toBeInstanceOf(ReminderRequestError);
|
|
expect(err.status).toBe(409);
|
|
});
|
|
});
|