- Commentary and study aids wait for 15 words of your own Observe notes. - Insights page: this week's own work, themes across studies, words you keep studying, what slipped in recalls, open follow-ups. - Recall can record what slipped; session notes (teach it back, who came, group notes, follow-ups); "Pray about this" from Apply. - Compare any two passages side by side. - Handout layouts: standard, questions only, large print, note-taking. - Search understands "in <book>", "last week/month/year" and a year. - Home shows the last backup age and nudges after two weeks. - Phone: the stage bar scrolls instead of clipping Script and Export. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
65 lines
4.0 KiB
JavaScript
65 lines
4.0 KiB
JavaScript
import { test, expect } from 'vitest';
|
||
import { buildHandoutHtml, outlineForSession, questionsFor, sessionsFor } from './handout.js';
|
||
|
||
const chunk = (id, s, e, x = {}) => ({ id, startVerse: s, endVerse: e, observation: '', interpretation: '', application: '', ...x });
|
||
const project = {
|
||
title: 'Romans 8 <study>', series: 'Romans', translation: 'BSB',
|
||
outline: [{ id: 'o1', text: 'No condemnation', ref: '', chunkId: 'a', children: [{ id: 'o2', text: 'The Spirit gives life', ref: 'Rom 8:2', chunkId: null, children: [] }] }],
|
||
chapters: [{ book: 'Romans', bookAbbrev: 'ROM', chapter: '8', verses: [{ number: 1, text: 'There is now no condemnation.' }, { number: 2, text: 'For the law of the Spirit of life.' }, { number: 12, text: 'So then, brothers.' }], chunks: [
|
||
chunk('a', 1, 2, { episodeNumber: '1', episodeTitle: 'Free at last', discussionQuestions: '1. What is condemnation?\n- Why does it end?', application: 'Rest in grace' }),
|
||
chunk('b', 12, 12, { application: '- Walk by the Spirit\n- Put sin to death' }),
|
||
] }],
|
||
};
|
||
|
||
test('sessions are numbered in order with their passages', () => {
|
||
expect(sessionsFor(project).map((s) => [s.number, s.reference])).toEqual([[1, 'Romans 8:1–2'], [2, 'Romans 8:12']]);
|
||
});
|
||
|
||
test('questions written for a session are used; otherwise the Application notes become prompts', () => {
|
||
expect(questionsFor(project.chapters[0].chunks[0])).toEqual({ kind: 'questions', items: ['What is condemnation?', 'Why does it end?'] });
|
||
expect(questionsFor(project.chapters[0].chunks[1])).toEqual({ kind: 'think', items: ['Walk by the Spirit', 'Put sin to death'] });
|
||
expect(questionsFor(chunk('z', 1, 1))).toEqual({ kind: 'none', items: [] });
|
||
});
|
||
|
||
test('a session uses the study outline points linked to it', () => {
|
||
expect(outlineForSession(project, project.chapters[0].chunks[0])).toHaveLength(1);
|
||
expect(outlineForSession(project, project.chapters[0].chunks[1])).toEqual([]);
|
||
expect(outlineForSession(project, { id: 'a', outline: [{ id: 'x', text: 'Own', children: [] }] })[0].id).toBe('x');
|
||
});
|
||
|
||
test('the handout has a page per session with passage, outline and questions, and escapes text', () => {
|
||
const html = buildHandoutHtml(project);
|
||
expect(html.match(/class="page"/g)).toHaveLength(2);
|
||
expect(html).toContain('Session 1: Free at last');
|
||
expect(html).toContain('<sup>1</sup> There is now no condemnation.');
|
||
expect(html).toContain('The Spirit gives life');
|
||
expect(html).toContain('Discussion questions');
|
||
expect(html).toContain('Think about it');
|
||
expect(html).toContain('Romans 8 <study>'); // no raw markup from the title
|
||
expect(html).not.toContain('<study>');
|
||
expect(html).toContain('class="rule"');
|
||
});
|
||
|
||
test('one session only, and no writing lines when switched off', () => {
|
||
const html = buildHandoutHtml(project, ['b'], { answerLines: false });
|
||
expect(html.match(/class="page"/g)).toHaveLength(1);
|
||
expect(html).toContain('Session 2');
|
||
expect(html).not.toContain('class="rule"');
|
||
});
|
||
|
||
import { buildHandoutHtml as buildLayoutHtml } from './handout.js';
|
||
|
||
test('layouts change what the handout prints', () => {
|
||
const project = { id: 'p', title: 'T', translation: 'BSB', outline: [], chapters: [{ book: 'John', bookAbbrev: 'Jhn', chapter: '3', verses: [{ number: 16, text: 'For God so loved.' }], chunks: [{ id: 'c', startVerse: 16, endVerse: 16, discussionQuestions: 'Why did he give?', application: 'Trust him.', outline: [{ id: 'n', text: 'Point one', children: [] }] }] }] };
|
||
const standard = buildLayoutHtml(project);
|
||
const questions = buildLayoutHtml(project, null, { layout: 'questions' });
|
||
const notes = buildLayoutHtml(project, null, { layout: 'notes' });
|
||
const large = buildLayoutHtml(project, null, { layout: 'large' });
|
||
expect(standard).toContain('Point one');
|
||
expect(questions).not.toContain('Point one');
|
||
expect(questions).toContain('Why did he give?');
|
||
expect(notes).not.toContain('Why did he give?');
|
||
expect(notes.match(/class="rule"/g).length).toBeGreaterThanOrEqual(16);
|
||
expect(large).toContain('class="page large"');
|
||
});
|