Files
study-bible-project/src/utils/passageRef.test.js
T
nmemmertandClaude Sonnet 5.5 d13f55faf7 Add Outline stage, parallel reading, offline saves, backup, sync-conflict handling and more
Study
- New Outline stage (hierarchical I./A./1. points, linked to chunks, in all exports);
  the chunk stage is now "Chunks"
- Home cards: passages shown as ranges, tags capped with "+N more"

Reader
- Side-by-side translations and a Compare tab per verse
- Typeface, line spacing, verse-number settings; text and column scale with the screen
- Highlights/bookmarks sheet with named colours (synced); BSB footnote spacing fix
- Cmd-K palette (passages, studies, notes, marks), keyboard shortcuts and "?" help

Flow and safety
- Toasts with Undo replace most confirm()/alert()
- Back/Forward move between pages
- Server refuses saves over a newer copy (409); keep-mine / use-other banner;
  opening a study no longer re-stamps it
- Latest chapter request wins when flipping quickly

Offline and data
- Save books, plan days or a whole BSB/NET for offline
- Service worker fixes: helloao /api/ URLs were skipped and responses cloned too late
- Settings: download/restore a full backup

Accessibility
- Sheets trap focus and close on Escape, skip link, focus ring, reduced motion,
  theme contrast raised to 4.5:1 (with a test)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 14:08:08 -04:00

38 lines
1.7 KiB
JavaScript

import { expect, test } from 'vitest';
import { formatPassage, matchBooks, parsePassageRef } from './passageRef.js';
const first = (text) => parsePassageRef(text)[0];
test('understands a book, chapter and verse in the usual ways', () => {
expect(first('John 3:16')).toMatchObject({ book: 'JHN', chapter: 3, verse: 16 });
expect(first('jn 3 16')).toMatchObject({ book: 'JHN', chapter: 3, verse: 16 });
expect(first('Ps 23')).toMatchObject({ book: 'PSA', chapter: 23, verse: null });
expect(first('1 cor 13:4')).toMatchObject({ book: '1CO', chapter: 13, verse: 4 });
expect(first('1corinthians 13')).toMatchObject({ book: '1CO', chapter: 13 });
expect(first('song of solomon 2')).toMatchObject({ book: 'SNG', chapter: 2 });
expect(first('Rom. 8.28')).toMatchObject({ book: 'ROM', chapter: 8, verse: 28 });
});
test('a bare book name opens its first chapter', () => {
expect(first('romans')).toMatchObject({ book: 'ROM', chapter: 1, hasChapter: false });
});
test('a name that fits several books lists them; a short form picks one', () => {
expect(matchBooks('jo').length).toBeGreaterThan(1);
expect(matchBooks('jn').map((b) => b.abbrev)).toEqual(['JHN']);
});
test('rejects chapters a book does not have, and things that are not passages', () => {
expect(parsePassageRef('jude 2')).toEqual([]); // Jude has one chapter
expect(parsePassageRef('genesis 51')).toEqual([]);
expect(parsePassageRef('')).toEqual([]);
expect(parsePassageRef('3:16')).toEqual([]);
expect(parsePassageRef('zzz 4')).toEqual([]);
});
test('formats a place the way people write it', () => {
expect(formatPassage(first('john 3:16'))).toBe('John 3:16');
expect(formatPassage(first('psalm 23'))).toBe('Psalms 23');
expect(formatPassage(first('romans'))).toBe('Romans');
});