113 lines
4.0 KiB
TypeScript
113 lines
4.0 KiB
TypeScript
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
|
|
const listNotesMock = vi.fn();
|
|
const getNoteMock = vi.fn();
|
|
const createNoteMock = vi.fn();
|
|
const updateNoteMock = vi.fn();
|
|
const enqueueNoteCreateMock = vi.fn();
|
|
const enqueueNoteUpdateMock = vi.fn();
|
|
|
|
vi.mock('../api/notes', () => ({
|
|
listNotes: (...args: unknown[]) => listNotesMock(...args),
|
|
getNote: (...args: unknown[]) => getNoteMock(...args),
|
|
createNote: (...args: unknown[]) => createNoteMock(...args),
|
|
updateNote: (...args: unknown[]) => updateNoteMock(...args),
|
|
}));
|
|
|
|
vi.mock('../lib/offline-queue', () => ({
|
|
enqueueNoteCreate: (...args: unknown[]) => enqueueNoteCreateMock(...args),
|
|
enqueueNoteUpdate: (...args: unknown[]) => enqueueNoteUpdateMock(...args),
|
|
}));
|
|
|
|
import { useNotesStore } from './notes-store';
|
|
|
|
function resetStore() {
|
|
useNotesStore.setState({
|
|
notes: [],
|
|
selectedNote: null,
|
|
isLoading: false,
|
|
});
|
|
}
|
|
|
|
const fakeNote = {
|
|
id: 'n1',
|
|
workspaceId: 'ws-1',
|
|
title: 'Test',
|
|
body: 'Body',
|
|
workspaceName: 'Work',
|
|
status: 'draft' as const,
|
|
updatedAt: '2025-01-01T00:00:00Z',
|
|
};
|
|
|
|
describe('useNotesStore', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
resetStore();
|
|
});
|
|
|
|
it('hydrate loads notes', async () => {
|
|
listNotesMock.mockResolvedValueOnce([fakeNote]);
|
|
await useNotesStore.getState().hydrate();
|
|
expect(useNotesStore.getState().notes).toHaveLength(1);
|
|
expect(useNotesStore.getState().notes[0].id).toBe('n1');
|
|
expect(useNotesStore.getState().isLoading).toBe(false);
|
|
});
|
|
|
|
it('openNote sets selectedNote', async () => {
|
|
useNotesStore.setState({ notes: [fakeNote] });
|
|
getNoteMock.mockResolvedValueOnce(fakeNote);
|
|
await useNotesStore.getState().openNote('n1');
|
|
expect(useNotesStore.getState().selectedNote?.id).toBe('n1');
|
|
});
|
|
|
|
it('openNote clears selectedNote for unknown id', async () => {
|
|
useNotesStore.setState({ notes: [fakeNote] });
|
|
await useNotesStore.getState().openNote('missing');
|
|
expect(useNotesStore.getState().selectedNote).toBeNull();
|
|
});
|
|
|
|
it('saveDraft creates note and prepends to list', async () => {
|
|
const created = { ...fakeNote, id: 'n2', title: 'New' };
|
|
createNoteMock.mockResolvedValueOnce(created);
|
|
const ok = await useNotesStore.getState().saveDraft('ws-1', 'New', 'Body');
|
|
expect(ok).toBe(true);
|
|
expect(useNotesStore.getState().notes[0].id).toBe('n2');
|
|
expect(useNotesStore.getState().selectedNote?.id).toBe('n2');
|
|
});
|
|
|
|
it('saveDraft returns false without workspaceId', async () => {
|
|
const ok = await useNotesStore.getState().saveDraft(null, 'Title', 'Body');
|
|
expect(ok).toBe(false);
|
|
expect(createNoteMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('saveDraft enqueues create when persistence fails', async () => {
|
|
createNoteMock.mockRejectedValueOnce(new Error('offline'));
|
|
const ok = await useNotesStore.getState().saveDraft('ws-1', 'Queued', 'Body');
|
|
expect(ok).toBe(true);
|
|
expect(enqueueNoteCreateMock).toHaveBeenCalledTimes(1);
|
|
expect(useNotesStore.getState().notes[0].title).toBe('Queued');
|
|
});
|
|
|
|
it('updateNote persists and updates state', async () => {
|
|
useNotesStore.setState({ notes: [fakeNote] });
|
|
const updated = { ...fakeNote, title: 'Updated' };
|
|
updateNoteMock.mockResolvedValueOnce(updated);
|
|
await useNotesStore.getState().updateNote('n1', 'Updated', 'Body');
|
|
expect(useNotesStore.getState().notes[0].title).toBe('Updated');
|
|
});
|
|
|
|
it('updateNote does nothing for unknown id', async () => {
|
|
await useNotesStore.getState().updateNote('missing', 'Title', 'Body');
|
|
expect(updateNoteMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('updateNote enqueues update when persistence fails', async () => {
|
|
useNotesStore.setState({ notes: [fakeNote] });
|
|
updateNoteMock.mockRejectedValueOnce(new Error('offline'));
|
|
await useNotesStore.getState().updateNote('n1', 'Updated offline', 'Body');
|
|
expect(enqueueNoteUpdateMock).toHaveBeenCalledTimes(1);
|
|
expect(useNotesStore.getState().notes[0].title).toBe('Updated offline');
|
|
});
|
|
});
|