- npm run test:e2e builds the app, runs it on port 3101 with an empty throwaway database and drives Chrome (the installed one; no browser download) through notes and the paste check, the daily five minutes and weekly recall, translation compare (Bible text faked), and two-screen presenting. - Vitest skips e2e/; ESLint knows the e2e folder and playwright.config.js. - .gitignore: the local demo video, Playwright output and sign-in file. - README and TODO describe the browser tests and what CI still needs. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
52 lines
4.4 KiB
JavaScript
52 lines
4.4 KiB
JavaScript
// Shared test helpers: a ready-made study so tests don't depend on downloading Bible text.
|
|
const DAY = 86400000;
|
|
const verses = [
|
|
{ number: 16, text: 'For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life.' },
|
|
{ number: 17, text: 'For God sent not his Son into the world to condemn the world; but that the world through him might be saved.' },
|
|
{ number: 18, text: 'He that believeth on him is not condemned: but he that believeth not is condemned already.' },
|
|
{ number: 19, text: 'And this is the condemnation, that light is come into the world, and men loved darkness rather than light, because their deeds were evil.' },
|
|
];
|
|
export const NOTE_TEXT = {
|
|
observation: 'Jesus is speaking to Nicodemus at night. The verse starts with "for", so it explains the previous verses about the serpent lifted up. God is the one who acts: he loved, he gave.',
|
|
interpretation: 'In its setting this is not a slogan but the reason the cross happens. The world is the object of love, not just the good in it. Giving the Son points back to Moses lifting the serpent.',
|
|
application: 'I do not have to earn being loved before I trust him. This week I want to stop treating belief as a feeling and decide one concrete thing to trust him with.',
|
|
};
|
|
export const SPEAKER_NOTE = 'PRIVATE: open with the story about Nicodemus at night, then pause after perish.';
|
|
|
|
// Writes a two-chunk John 3 study (edited two weeks ago, so a weekly recall is due) into this browser's storage
|
|
// for the signed-in account, then reloads.
|
|
export async function seedStudy(page, { id = `e2e-${Date.now()}-${Math.floor(Math.random() * 1e6)}`, withOutline = false } = {}) {
|
|
await page.goto('/');
|
|
await page.waitForFunction(() => Object.keys(localStorage).some((k) => /^bible-study-index:.+:known$/.test(k)));
|
|
await page.evaluate(({ id, verses, notes, speakerNote, withOutline, DAY }) => {
|
|
const uid = Object.keys(localStorage).find((k) => /^bible-study-index:.+:known$/.test(k)).split(':')[1];
|
|
const now = Date.now();
|
|
const chunk = (cid, s, e, extra) => ({ id: cid, startVerse: s, endVerse: e, spilloverEndVerse: null, observation: '', interpretation: '', application: '', crossReferences: [], greekWords: [], generalNotes: '', episodeNumber: '', episodeTitle: '', finalScript: '', tags: [], editedAt: now - 14 * DAY, ...extra });
|
|
const node = (nid, text, extra = {}) => ({ id: nid, text, ref: '', chunkId: null, note: '', kind: '', minutes: null, scripture: null, attachments: [], children: [], ...extra });
|
|
const a = chunk(`${id}-a`, 16, 18, { ...notes });
|
|
const b = chunk(`${id}-b`, 19, 19, {});
|
|
// a title of its own: studies from earlier tests sync back through the account, so titles must not repeat
|
|
const title = `John 3 (${id.slice(-6)})`;
|
|
const outline = withOutline ? [node('n1', 'God so loved', { minutes: 5, note: speakerNote, ref: 'John 3:16', scripture: { text: verses[0].text, ref: 'John 3:16' } }), node('n2', 'Light and darkness', { minutes: 5 })] : [];
|
|
const project = { id, title, translation: 'BSB', lastEdited: now - 2 * DAY, selectedChunkId: a.id, outline, chapters: [{ book: 'John', bookAbbrev: 'JHN', chapter: '3', verses, chunks: [a, b] }] };
|
|
localStorage.setItem(`bible-study-project:${uid}:${id}`, JSON.stringify(project));
|
|
const index = JSON.parse(localStorage.getItem(`bible-study-index:${uid}`) || '[]').filter((e) => e.id !== id);
|
|
index.push({ id, title: project.title, lastEdited: project.lastEdited, chapterSummary: 'John 3', series: '', tags: [] });
|
|
localStorage.setItem(`bible-study-index:${uid}`, JSON.stringify(index));
|
|
}, { id, verses, notes: NOTE_TEXT, speakerNote: SPEAKER_NOTE, withOutline, DAY });
|
|
await page.reload();
|
|
return { id, title: `John 3 (${id.slice(-6)})` };
|
|
}
|
|
|
|
// The Resume button on one study's card on Home
|
|
export const resumeButton = (page, title) => page.getByRole('heading', { name: title }).locator('xpath=ancestor::div[contains(@class,"rounded-2xl")][1]').getByRole('button', { name: 'Resume' });
|
|
|
|
// Fakes a long paste into a note box (Playwright can't use the real clipboard in every setup)
|
|
export async function pasteInto(locator, text) {
|
|
await locator.evaluate((el, value) => {
|
|
const dt = new DataTransfer();
|
|
dt.setData('text', value);
|
|
el.dispatchEvent(new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true }));
|
|
}, text);
|
|
}
|