Version history, notes on highlights and bookmarks, "you've studied this", prayer journal
Build and Push Docker Image / build-and-push (push) Successful in 5m13s
Build and Push Docker Image / build-and-push (push) Successful in 5m13s
- Earlier versions of a study: the server keeps compressed copies (about one per ten minutes of editing, the latest 30); Export shows what differs and puts one back (the replaced copy is kept) - Notes on highlights and bookmarks: synced, merged without loss, in exports and backups - Reader verse panel lists your studies and chunks that cover the verse, and opens them - Prayer journal: requests, who for, linked verses, days prayed, answers; synced, in backups and the account export; daily prayer reminder through ntfy - TODO.md lists the ideas not built yet Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
54cb1c217d
commit
207bfcb919
45 files changed
+1669
-75
No files matched your search
@@ -0,0 +1,57 @@
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { vi, test, expect, beforeEach } from 'vitest';
|
||||
|
||||
vi.mock('../syncService.js', () => ({ getRemotePrayers: vi.fn(), saveRemotePrayers: vi.fn() }));
|
||||
import { usePrayers } from './usePrayers.js';
|
||||
import { getRemotePrayers, saveRemotePrayers } from '../syncService.js';
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
vi.clearAllMocks();
|
||||
getRemotePrayers.mockResolvedValue({ ok: true, data: { prayers: [] } });
|
||||
saveRemotePrayers.mockImplementation(async (list) => ({ ok: true, data: { prayers: list } }));
|
||||
});
|
||||
|
||||
test('prayers are added, changed, answered and kept on this device', () => {
|
||||
const { result } = renderHook(() => usePrayers());
|
||||
let id;
|
||||
act(() => { id = result.current.addPrayer({ text: 'Peace at home', forWhom: 'Family' }).id; });
|
||||
expect(result.current.prayers[0]).toMatchObject({ text: 'Peace at home', forWhom: 'Family' });
|
||||
act(() => result.current.editPrayer(id, { text: 'Peace and joy at home' }));
|
||||
act(() => result.current.togglePrayed(id));
|
||||
expect(result.current.prayers[0].prayedOn).toHaveLength(1);
|
||||
act(() => result.current.answerPrayer(id, 'Yes'));
|
||||
expect(result.current.prayers[0]).toMatchObject({ text: 'Peace and joy at home', answerNote: 'Yes' });
|
||||
expect(result.current.prayers[0].answeredAt).toBeGreaterThan(0);
|
||||
act(() => result.current.reopenPrayer(id));
|
||||
expect(result.current.prayers[0].answeredAt).toBeNull();
|
||||
expect(JSON.parse(localStorage.getItem('prayers'))[0].text).toBe('Peace and joy at home');
|
||||
});
|
||||
|
||||
test('a deleted prayer can be taken back', () => {
|
||||
const { result } = renderHook(() => usePrayers());
|
||||
let id; let undo;
|
||||
act(() => { id = result.current.addPrayer({ text: 'Keep me' }).id; });
|
||||
act(() => { undo = result.current.deletePrayer(id); });
|
||||
expect(result.current.prayers[0].deleted).toBe(true);
|
||||
act(() => undo());
|
||||
expect(result.current.prayers[0]).toMatchObject({ id, text: 'Keep me' });
|
||||
expect(result.current.prayers[0].deleted).toBeUndefined();
|
||||
});
|
||||
|
||||
test('signing in merges with the account and sends back what it lacked', async () => {
|
||||
localStorage.setItem('prayers', JSON.stringify([{ id: 'local', text: 'Only here', forWhom: '', verses: [], prayedOn: [], createdAt: 1, updatedAt: 5, answeredAt: null, answerNote: '' }]));
|
||||
getRemotePrayers.mockResolvedValue({ ok: true, data: { prayers: [{ id: 'remote', text: 'Only there', forWhom: '', verses: [], prayedOn: [], createdAt: 1, updatedAt: 6, answeredAt: null, answerNote: '' }] } });
|
||||
const { result } = renderHook(() => usePrayers());
|
||||
await act(async () => { await result.current.pullPrayers(); });
|
||||
expect(result.current.prayers.map((p) => p.id).sort()).toEqual(['local', 'remote']);
|
||||
expect(saveRemotePrayers).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('signing out clears the journal from this device', async () => {
|
||||
const { result } = renderHook(() => usePrayers());
|
||||
act(() => { result.current.addPrayer({ text: 'Private' }); });
|
||||
act(() => result.current.stopPrayers());
|
||||
expect(result.current.prayers).toEqual([]);
|
||||
expect(localStorage.getItem('prayers')).toBeNull();
|
||||
});
|
||||
Reference in new issue
Block a user