import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { vi, test, expect, beforeEach } from 'vitest'; vi.mock('../syncService.js', () => ({ listStudyVersions: vi.fn(), getStudyVersion: vi.fn() })); import VersionHistory from './VersionHistory.jsx'; import { getStudyVersion, listStudyVersions } from '../syncService.js'; const project = { id: 'p1', title: 'Romans', chapters: [{ book: 'Romans', chapter: '8', chunks: [{ id: 'a', startVerse: 1, endVerse: 4, observation: 'new words' }] }] }; const older = { id: 'p1', title: 'Romans', chapters: [{ book: 'Romans', chapter: '8', chunks: [{ id: 'a', startVerse: 1, endVerse: 4, observation: 'old words' }, { id: 'b', startVerse: 5, endVerse: 9, observation: 'lost' }] }] }; const at = new Date(2026, 9, 5, 14, 30).getTime(); beforeEach(() => { vi.clearAllMocks(); listStudyVersions.mockResolvedValue({ ok: true, data: { versions: [{ id: 7, savedAt: at, chunks: 2, words: 12 }] } }); getStudyVersion.mockResolvedValue({ ok: true, data: older }); vi.spyOn(window, 'confirm').mockReturnValue(true); }); test('lists the kept versions and says what is different from now', async () => { const user = userEvent.setup(); render(); expect(await screen.findByText(/2 chunks · 12 words/)).toBeInTheDocument(); await user.click(screen.getByRole('button', { name: /what’s different/i })); expect(await screen.findByText('Romans 8:1–4: Observe differs.')).toBeInTheDocument(); expect(screen.getByText(/Brings back 1 chunk deleted since: Romans 8:5–9/)).toBeInTheDocument(); expect(getStudyVersion).toHaveBeenCalledWith('p1', 7); }); test('putting one back asks first, then restores and refreshes the list', async () => { const onRestore = vi.fn(async () => true); const user = userEvent.setup(); render(); await user.click(await screen.findByRole('button', { name: /put this back/i })); expect(window.confirm).toHaveBeenCalled(); expect(onRestore).toHaveBeenCalledWith(7); expect(listStudyVersions).toHaveBeenCalledTimes(2); // reloaded after }); test('declining the question restores nothing; a failed restore says so', async () => { const onRestore = vi.fn(async () => false); const user = userEvent.setup(); window.confirm.mockReturnValueOnce(false); render(); await user.click(await screen.findByRole('button', { name: /put this back/i })); expect(onRestore).not.toHaveBeenCalled(); await user.click(screen.getByRole('button', { name: /put this back/i })); expect(await screen.findByRole('alert')).toHaveTextContent(/Could not restore/); }); test('with nothing kept, or no connection, it says so', async () => { listStudyVersions.mockResolvedValueOnce({ ok: true, data: { versions: [] } }); const { unmount } = render(); expect(await screen.findByText(/Nothing kept yet/)).toBeInTheDocument(); unmount(); listStudyVersions.mockResolvedValueOnce({ ok: false, status: 404 }); render(); expect(await screen.findByText(/need your account and a connection/)).toBeInTheDocument(); });