import React from 'react' import { act, cleanup, render, waitFor } from '@testing-library/react' import ArtworkNavigator from './ArtworkNavigator' describe('ArtworkNavigator preview prefetch', () => { afterEach(() => { cleanup() vi.restoreAllMocks() delete window.requestIdleCallback delete window.cancelIdleCallback }) it('seeds neighbor prefetch from navigation and keeps full navigation separate', async () => { let idleCallback let ready window.requestIdleCallback = vi.fn((callback) => { idleCallback = callback; return 1 }) window.cancelIdleCallback = vi.fn() global.fetch = vi.fn((url) => { if (String(url).includes('/api/artworks/navigation/777')) { return Promise.resolve({ ok: true, json: async () => ({ prev_id: 776, next_id: 778, prev_url: '/art/776/previous', next_url: '/art/778/next', prev_slug: 'previous', next_slug: 'next', prev_preview: { id: 776, title: 'Previous', slug: 'previous', thumbs: { md: { url: '/md-776' }, lg: { url: '/lg-776' } } }, next_preview: { id: 778, title: 'Next', slug: 'next', thumbs: { md: { url: '/md-778' }, lg: { url: '/lg-778' } } }, }), }) } return Promise.resolve({ ok: true, json: async () => ({ id: 778, title: 'Next', slug: 'next' }) }) }) render( { if (next.hasNext) ready = next }} />) await waitFor(() => expect(ready?.hasNext).toBe(true)) await act(async () => idleCallback()) expect(global.fetch.mock.calls.filter(([url]) => String(url).includes('?prefetch=1'))).toHaveLength(0) await act(async () => ready.navigateNext()) expect(global.fetch).toHaveBeenCalledWith('/api/artworks/778/page', { headers: { Accept: 'application/json' } }) }) it('uses embedded initial navigation without a standalone or prefetch request', async () => { let idleCallback window.requestIdleCallback = vi.fn((callback) => { idleCallback = callback; return 1 }) window.cancelIdleCallback = vi.fn() global.fetch = vi.fn() const navigation = { prev_id: 880, next_id: 882, prev_url: '/art/880/previous', next_url: '/art/882/next', prev_slug: 'previous', next_slug: 'next', prev_preview: { id: 880, title: 'Previous', slug: 'previous', thumbs: { md: { url: '/md-880' }, lg: { url: '/lg-880' } } }, next_preview: { id: 882, title: 'Next', slug: 'next', thumbs: { md: { url: '/md-882' }, lg: { url: '/lg-882' } } }, } render() await waitFor(() => expect(window.requestIdleCallback).toHaveBeenCalledTimes(1)) await act(async () => idleCallback()) expect(global.fetch).not.toHaveBeenCalled() }) it('falls back to standalone navigation for malformed embedded data', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: true, json: async () => ({ prev_id: 889, next_id: 891, prev_url: '/art/889/p', next_url: '/art/891/n', prev_slug: 'p', next_slug: 'n' }), }) render() await waitFor(() => expect(global.fetch).toHaveBeenCalledWith('/api/artworks/navigation/890', { headers: { Accept: 'application/json' } })) }) })