Build and Push Docker Image / build-and-push (push) Successful in 6m47s
- Admin: sign-up Open / Invite only / Closed with single-use invite links - Present mode for scripts (auto-scroll) and outlines (step through, pace vs planned minutes) - Series: group studies on the dashboard, filter by series, calendar file for a study's sessions - Lesson handout: printable page per session (passage, outline, questions, writing lines) - Save a chunk's notes as your own study template (synced) - Voice dictation for notes and scripts (browser speech recognition) - Reading progress: map of the 66 books and a calendar of days read, synced and merged across devices - Export highlights and bookmarks as Markdown or Word, grouped by named colour - Verse of the day push to the ntfy topic (needs IQBIBLE_API_KEY) - Sharing: co-teacher editing via single-use invite links; read-only links can expire and take a passcode Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
41 lines
2.3 KiB
JavaScript
41 lines
2.3 KiB
JavaScript
// @vitest-environment node
|
|
import { test, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import { parseVotd, fetchVerseOfDay, clearVotdCache, votdMessage } from './votd.js';
|
|
|
|
beforeEach(() => { clearVotdCache(); process.env.IQBIBLE_API_KEY = 'k'; });
|
|
afterEach(() => { delete process.env.IQBIBLE_API_KEY; vi.restoreAllMocks(); });
|
|
|
|
const body = { data: { book_usfm: 'ROM', chapter_number: 8, verse_number: 28, text: '¶ And we know that all things work together for good.' } };
|
|
const ok = () => vi.fn(async () => ({ ok: true, json: async () => body }));
|
|
|
|
test('IQ Bible\'s verse becomes a reference and clean text', () => {
|
|
expect(parseVotd(body)).toEqual({ reference: 'Romans 8:28', text: 'And we know that all things work together for good.' });
|
|
expect(parseVotd({ data: { book_usfm: 'XXX', chapter_number: 1, verse_number: 1, text: 'x' } })).toBeNull();
|
|
expect(parseVotd({})).toBeNull();
|
|
});
|
|
|
|
test('the notification carries the verse and its reference', () => {
|
|
expect(votdMessage({ reference: 'Romans 8:28', text: 'All things.' })).toEqual({ title: 'Verse of the day: Romans 8:28', body: 'All things.\n\nRomans 8:28 (KJV)', tags: 'sunrise' });
|
|
});
|
|
|
|
test('one lookup a day serves everyone, and a new day looks again', async () => {
|
|
const fetcher = ok();
|
|
const day1 = new Date('2026-10-06T12:00:00Z');
|
|
expect((await fetchVerseOfDay(day1, fetcher)).reference).toBe('Romans 8:28');
|
|
await fetchVerseOfDay(new Date('2026-10-06T23:00:00Z'), fetcher);
|
|
expect(fetcher).toHaveBeenCalledTimes(1);
|
|
await fetchVerseOfDay(new Date('2026-10-07T01:00:00Z'), fetcher);
|
|
expect(fetcher).toHaveBeenCalledTimes(2);
|
|
expect(fetcher.mock.calls[0][0]).toContain('/bibles/eng_kjv/verse-of-the-day');
|
|
expect(fetcher.mock.calls[0][1].headers['X-IQBible-API-Key']).toBe('k');
|
|
});
|
|
|
|
test('without a key, or when IQ Bible fails, there is no verse (and nothing is remembered)', async () => {
|
|
delete process.env.IQBIBLE_API_KEY;
|
|
expect(await fetchVerseOfDay(new Date(), ok())).toBeNull();
|
|
process.env.IQBIBLE_API_KEY = 'k';
|
|
expect(await fetchVerseOfDay(new Date(), vi.fn(async () => ({ ok: false })))).toBeNull();
|
|
expect(await fetchVerseOfDay(new Date(), vi.fn(async () => { throw new Error('down'); }))).toBeNull();
|
|
expect((await fetchVerseOfDay(new Date(), ok())).reference).toBe('Romans 8:28'); // a later good answer still works
|
|
});
|