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>
61 lines
3.0 KiB
React
61 lines
3.0 KiB
React
import { render, screen, act } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { vi, test, expect, afterEach } from 'vitest';
|
|
import PresentMode from './PresentMode.jsx';
|
|
|
|
afterEach(() => vi.useRealTimers());
|
|
const n = (id, text, minutes, extra = {}) => ({ id, text, ref: '', chunkId: null, minutes, note: '', kind: '', scripture: null, attachments: [], children: [], ...extra });
|
|
const tree = [n('a', 'Welcome', 2, { note: 'Say hello' }), n('b', 'The gospel', 10, { ref: 'Rom 1:16' })];
|
|
|
|
test('the outline is stepped through a point at a time, with the keyboard or the buttons', async () => {
|
|
const user = userEvent.setup();
|
|
render(<PresentMode mode="outline" title="Romans" tree={tree} onClose={() => {}} />);
|
|
expect(screen.getByText('Welcome')).toBeInTheDocument();
|
|
expect(screen.getByText('Say hello')).toBeInTheDocument();
|
|
expect(screen.getByText(/Point 1 of 2/)).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: /back/i })).toBeDisabled();
|
|
await user.keyboard('{ArrowRight}');
|
|
expect(screen.getByText('The gospel')).toBeInTheDocument();
|
|
expect(screen.getByText('Rom 1:16')).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: /next/i })).toBeDisabled();
|
|
await user.click(screen.getByRole('button', { name: /back/i }));
|
|
expect(screen.getByText('Welcome')).toBeInTheDocument();
|
|
});
|
|
|
|
test('the timer runs, pauses and resets, and tells you how you are doing against the plan', async () => {
|
|
vi.useFakeTimers();
|
|
render(<PresentMode mode="outline" title="Romans" tree={tree} onClose={() => {}} />);
|
|
const group = screen.getByRole('group', { name: 'Timer' });
|
|
const click = (name) => act(() => { screen.getByRole('button', { name }).click(); });
|
|
click('Start');
|
|
act(() => { vi.advanceTimersByTime(65_000); });
|
|
expect(group).toHaveTextContent('1:05');
|
|
expect(screen.getByRole('status')).toHaveTextContent(/On pace/); // a minute in, on a 2-minute point
|
|
click('Pause');
|
|
act(() => { vi.advanceTimersByTime(10_000); });
|
|
expect(group).toHaveTextContent('1:05'); // paused
|
|
click('Reset');
|
|
expect(group).toHaveTextContent('0:00');
|
|
});
|
|
|
|
test('the text size can be changed and the choice is remembered', async () => {
|
|
const user = userEvent.setup();
|
|
localStorage.clear();
|
|
render(<PresentMode mode="script" title="Romans 8" script="In the beginning" onClose={() => {}} />);
|
|
const text = screen.getByText('In the beginning');
|
|
expect(text.style.fontSize).toBe('34px');
|
|
await user.click(screen.getByRole('button', { name: 'Larger text' }));
|
|
expect(text.style.fontSize).toBe('40px');
|
|
expect(localStorage.getItem('present-size')).toBe('40');
|
|
});
|
|
|
|
test('Escape and Close both leave, and an empty script says what to do', async () => {
|
|
const onClose = vi.fn();
|
|
const user = userEvent.setup();
|
|
render(<PresentMode mode="script" title="T" script=" " onClose={onClose} />);
|
|
expect(screen.getByText(/no script to present yet/i)).toBeInTheDocument();
|
|
await user.keyboard('{Escape}');
|
|
await user.click(screen.getByRole('button', { name: 'Close' }));
|
|
expect(onClose).toHaveBeenCalledTimes(2);
|
|
});
|