Files
SkinbaseNova/resources/js/lib/useLazyProfileWorldHistory.test.jsx
T

82 lines
3.7 KiB
React

import React from 'react'
import { render, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import useLazyProfileWorldHistory from './useLazyProfileWorldHistory'
function Harness({ username = 'alice', initial = null, enabled = false }) {
const state = useLazyProfileWorldHistory({
username,
initialWorldHistory: initial,
enabled,
})
return <output data-testid="state">{JSON.stringify(state)}</output>
}
describe('useLazyProfileWorldHistory', () => {
beforeEach(() => vi.restoreAllMocks())
it('does not request on Posts until a consuming tab is active', () => {
const fetchMock = vi.spyOn(globalThis, 'fetch')
render(<Harness />)
expect(fetchMock).not.toHaveBeenCalled()
})
it('requests once on first consuming-tab activation and reuses the result', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
ok: true,
json: async () => ({ summary: { available: true }, entries: [{ id: 'world-1' }] }),
})
const view = render(<Harness />)
view.rerender(<Harness enabled />)
await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(1))
view.rerender(<Harness enabled={false} />)
view.rerender(<Harness enabled />)
expect(fetchMock).toHaveBeenCalledTimes(1)
await waitFor(() => expect(JSON.parse(view.getByTestId('state').textContent).loaded).toBe(true))
})
it('uses direct Worlds/Achievements SSR data without a lazy request', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch')
const initial = { summary: { available: true }, entries: [{ id: 'world-1' }] }
const view = render(<Harness initial={initial} enabled />)
view.rerender(<Harness initial={initial} enabled={false} />)
view.rerender(<Harness initial={initial} enabled />)
await waitFor(() => expect(JSON.parse(view.getByTestId('state').textContent).data).toEqual(initial))
expect(fetchMock).not.toHaveBeenCalled()
})
it('treats an empty response as loaded', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue({ ok: true, json: async () => ({ summary: { available: false }, entries: [] }) })
const view = render(<Harness enabled />)
await waitFor(() => expect(JSON.parse(view.getByTestId('state').textContent).loaded).toBe(true))
expect(fetchMock).toHaveBeenCalledTimes(1)
})
it('resets on profile navigation and ignores the stale response', async () => {
let resolveA
const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(() => new Promise((resolve) => { resolveA = resolve }))
const view = render(<Harness username="alice" enabled />)
await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(1))
view.rerender(<Harness username="bob" enabled />)
resolveA({ ok: true, json: async () => ({ summary: { available: true }, entries: [{ id: 'alice' }] }) })
await waitFor(() => expect(JSON.parse(view.getByTestId('state').textContent).data).toBe(null))
})
it('does not loop after an error and permits an explicit retry', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch')
.mockResolvedValueOnce({ ok: false })
.mockResolvedValueOnce({ ok: true, json: async () => ({ summary: { available: false }, entries: [] }) })
const view = render(<Harness enabled />)
await waitFor(() => expect(JSON.parse(view.getByTestId('state').textContent).error).toBe(true))
expect(fetchMock).toHaveBeenCalledTimes(1)
// The hook's returned retry is intentionally exercised through a small rerender activation.
view.rerender(<Harness enabled={false} />)
view.rerender(<Harness enabled />)
await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(2))
})
})