Files
waooplus/tests/unit/optimistic/asset-actions-generate.test.ts

108 lines
3.1 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import { QueryClient } from '@tanstack/react-query'
import { queryKeys } from '@/lib/query/keys'
import type { TaskTargetOverlayMap } from '@/lib/query/task-target-overlay'
const {
apiFetchMock,
useQueryClientMock,
} = vi.hoisted(() => ({
apiFetchMock: vi.fn(),
useQueryClientMock: vi.fn(),
}))
vi.mock('@tanstack/react-query', async () => {
const actual = await vi.importActual<typeof import('@tanstack/react-query')>('@tanstack/react-query')
return {
...actual,
useQueryClient: () => useQueryClientMock(),
}
})
vi.mock('@/lib/api-fetch', () => ({
apiFetch: apiFetchMock,
}))
import { useAssetActions } from '@/lib/query/hooks/useAssets'
function getOverlay(
queryClient: QueryClient,
projectId: string,
key: string,
) {
const map = queryClient.getQueryData<TaskTargetOverlayMap>(
queryKeys.tasks.targetStateOverlay(projectId),
) || {}
return map[key] || null
}
function createOkResponse() {
return {
ok: true,
json: async () => ({ success: true }),
} as Response
}
describe('useAssetActions.generate optimistic overlay', () => {
beforeEach(() => {
useQueryClientMock.mockReset()
apiFetchMock.mockReset()
apiFetchMock.mockResolvedValue(createOkResponse())
})
it('keeps global prop in generating state immediately after submit', async () => {
const queryClient = new QueryClient()
useQueryClientMock.mockReturnValue(queryClient)
const actions = useAssetActions({ scope: 'global', kind: 'prop' })
await actions.generate({ id: 'prop-1' })
expect(apiFetchMock).toHaveBeenCalledWith('/api/assets/prop-1/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
scope: 'global',
kind: 'prop',
projectId: undefined,
id: 'prop-1',
}),
})
const overlay = getOverlay(queryClient, 'global-asset-hub', 'GlobalLocation:prop-1')
expect(overlay?.phase).toBe('queued')
expect(overlay?.intent).toBe('generate')
})
it('targets project prop generation overlay at the shared location-image task target', async () => {
const queryClient = new QueryClient()
useQueryClientMock.mockReturnValue(queryClient)
const actions = useAssetActions({
scope: 'project',
projectId: 'project-1',
kind: 'prop',
})
await actions.generate({ id: 'prop-2' })
const overlay = getOverlay(queryClient, 'project-1', 'LocationImage:prop-2')
expect(overlay?.phase).toBe('queued')
expect(overlay?.intent).toBe('generate')
})
it('clears the overlay when prop generation submission fails', async () => {
const queryClient = new QueryClient()
useQueryClientMock.mockReturnValue(queryClient)
apiFetchMock.mockResolvedValueOnce({
ok: false,
json: async () => ({}),
} as Response)
const actions = useAssetActions({ scope: 'global', kind: 'prop' })
await expect(actions.generate({ id: 'prop-3' })).rejects.toThrow('Failed to generate asset render')
const overlay = getOverlay(queryClient, 'global-asset-hub', 'GlobalLocation:prop-3')
expect(overlay).toBeNull()
})
})