Files
study-bible-project/src/utils/handout.test.js
T
nmemmertandClaude Sonnet 5.5 d8e522dd06 Add Insights, Observe-first, compare, handout layouts, richer search, backup nudge
- 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>
2026-10-14 12:42:11 -04:00

65 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 &lt;study&gt;'); // 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"');
});