78 lines
2.8 KiB
React
78 lines
2.8 KiB
React
import React from 'react'
|
|
import { act, render, screen, waitFor } from '@testing-library/react'
|
|
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
|
|
import useLazyProfileFeaturedArtworks from './useLazyProfileFeaturedArtworks'
|
|
|
|
function Harness({ username = 'alice', initial = null, enabled = false }) {
|
|
const state = useLazyProfileFeaturedArtworks({
|
|
username,
|
|
initialFeaturedArtworks: initial,
|
|
enabled,
|
|
})
|
|
|
|
return (
|
|
<div>
|
|
<span data-testid="count">{state.items.length}</span>
|
|
<span data-testid="loading">{String(state.loading)}</span>
|
|
<span data-testid="error">{String(state.error)}</span>
|
|
<button type="button" onClick={state.retry}>retry</button>
|
|
{state.items.map((item) => <span key={item.id}>{item.title}</span>)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
describe('useLazyProfileFeaturedArtworks', () => {
|
|
beforeEach(() => {
|
|
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
ok: true,
|
|
json: async () => ({ data: [{ id: 1, title: 'Featured one' }] }),
|
|
})))
|
|
})
|
|
|
|
afterEach(() => vi.unstubAllGlobals())
|
|
|
|
it('does not request while the posts tab is active', () => {
|
|
render(<Harness />)
|
|
expect(fetch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('loads once on first artworks activation and reuses the result', async () => {
|
|
const view = render(<Harness enabled />)
|
|
|
|
await waitFor(() => expect(screen.getByText('Featured one')).toBeTruthy())
|
|
expect(fetch).toHaveBeenCalledTimes(1)
|
|
|
|
view.rerender(<Harness enabled={false} />)
|
|
view.rerender(<Harness enabled />)
|
|
expect(fetch).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('does not request when SSR already supplied featured artworks', () => {
|
|
render(<Harness enabled initial={[{ id: 9, title: 'SSR feature' }]} />)
|
|
expect(screen.getByText('SSR feature')).toBeTruthy()
|
|
expect(fetch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('allows a safe retry after failure', async () => {
|
|
fetch.mockRejectedValueOnce(new Error('network'))
|
|
render(<Harness enabled />)
|
|
|
|
await waitFor(() => expect(screen.getByTestId('error').textContent).toBe('true'))
|
|
await act(async () => screen.getByRole('button', { name: 'retry' }).click())
|
|
await waitFor(() => expect(screen.getByText('Featured one')).toBeTruthy())
|
|
expect(fetch).toHaveBeenCalledTimes(2)
|
|
})
|
|
|
|
it('ignores a stale response after profile navigation', async () => {
|
|
let resolveAlice
|
|
fetch.mockImplementationOnce(() => new Promise((resolve) => { resolveAlice = resolve }))
|
|
const view = render(<Harness username="alice" enabled />)
|
|
|
|
view.rerender(<Harness username="bob" enabled={false} />)
|
|
await act(async () => resolveAlice({ ok: true, json: async () => ({ data: [{ id: 1, title: 'Alice feature' }] }) }))
|
|
|
|
expect(screen.queryByText('Alice feature')).toBeNull()
|
|
expect(screen.getByTestId('count').textContent).toBe('0')
|
|
})
|
|
})
|