Skip to content

Commit

Permalink
test(react-query): refactor test file structure 1 file by 1 api
Browse files Browse the repository at this point in the history
  • Loading branch information
manudeli committed Nov 8, 2024
1 parent 8ae5aed commit d4242a5
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 218 deletions.
Original file line number Diff line number Diff line change
@@ -1,39 +1,5 @@
import { describe, expectTypeOf, it } from 'vitest'
import { usePrefetchInfiniteQuery, usePrefetchQuery } from '..'

describe('usePrefetchQuery', () => {
it('should return nothing', () => {
const result = usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
})

expectTypeOf(result).toEqualTypeOf<void>()
})

it('should not allow refetchInterval, enabled or throwOnError options', () => {
usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// @ts-expect-error TS2345
refetchInterval: 1000,
})

usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// @ts-expect-error TS2345
enabled: true,
})

usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// @ts-expect-error TS2345
throwOnError: true,
})
})
})
import { usePrefetchInfiniteQuery } from '..'

describe('useInfinitePrefetchQuery', () => {
it('should return nothing', () => {
Expand Down
188 changes: 188 additions & 0 deletions packages/react-query/src/__tests__/usePrefetchInfiniteQuery.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { describe, expect, it, vi } from 'vitest'
import React from 'react'
import { fireEvent, waitFor } from '@testing-library/react'

import {
QueryCache,
usePrefetchInfiniteQuery,
useSuspenseInfiniteQuery,
} from '..'
import { createQueryClient, queryKey, renderWithClient, sleep } from './utils'

import type { InfiniteData, UseSuspenseInfiniteQueryOptions } from '..'
import type { Mock } from 'vitest'

const generateInfiniteQueryOptions = (
data: Array<{ data: string; currentPage: number; totalPages: number }>,
) => {
let currentPage = 0

return {
queryFn: vi
.fn<(...args: Array<any>) => Promise<(typeof data)[number]>>()
.mockImplementation(async () => {
const currentPageData = data[currentPage]
if (!currentPageData) {
throw new Error('No data defined for page ' + currentPage)
}

await sleep(10)
currentPage++

return currentPageData
}),
initialPageParam: 1,
getNextPageParam: (lastPage: (typeof data)[number]) =>
lastPage.currentPage === lastPage.totalPages
? undefined
: lastPage.currentPage + 1,
}
}

describe('usePrefetchInfiniteQuery', () => {
const queryCache = new QueryCache()
const queryClient = createQueryClient({ queryCache })

const Fallback = vi.fn().mockImplementation(() => <div>Loading...</div>)

function Suspended<T = unknown>(props: {
queryOpts: UseSuspenseInfiniteQueryOptions<
T,
Error,
InfiniteData<T>,
any,
Array<string>,
any
>
renderPage: (page: T) => React.JSX.Element
}) {
const state = useSuspenseInfiniteQuery(props.queryOpts)

return (
<div>
{state.data.pages.map((page, index) => (
<div key={index}>{props.renderPage(page)}</div>
))}
<button onClick={() => state.fetchNextPage()}>Next Page</button>
</div>
)
}

it('should prefetch an infinite query if query state does not exist', async () => {
const data = [
{ data: 'Do you fetch on render?', currentPage: 1, totalPages: 3 },
{ data: 'Or do you render as you fetch?', currentPage: 2, totalPages: 3 },
{
data: 'Either way, Tanstack Query helps you!',
currentPage: 3,
totalPages: 3,
},
]

const queryOpts = {
queryKey: queryKey(),
...generateInfiniteQueryOptions(data),
}

function App() {
usePrefetchInfiniteQuery({ ...queryOpts, pages: data.length })

return (
<React.Suspense fallback={<Fallback />}>
<Suspended
queryOpts={queryOpts}
renderPage={(page) => <div>data: {page.data}</div>}
/>
</React.Suspense>
)
}

const rendered = renderWithClient(queryClient, <App />)

await waitFor(() => rendered.getByText('data: Do you fetch on render?'))
fireEvent.click(rendered.getByText('Next Page'))
await waitFor(() =>
rendered.getByText('data: Or do you render as you fetch?'),
)
fireEvent.click(rendered.getByText('Next Page'))
await waitFor(() =>
rendered.getByText('data: Either way, Tanstack Query helps you!'),
)
expect(Fallback).toHaveBeenCalledTimes(1)
expect(queryOpts.queryFn).toHaveBeenCalledTimes(3)
})

it('should not display fallback if the query cache is already populated', async () => {
const queryOpts = {
queryKey: queryKey(),
...generateInfiniteQueryOptions([
{ data: 'Prefetch rocks!', currentPage: 1, totalPages: 3 },
{ data: 'No waterfalls, boy!', currentPage: 2, totalPages: 3 },
{ data: 'Tanstack Query #ftw', currentPage: 3, totalPages: 3 },
]),
}

await queryClient.prefetchInfiniteQuery({ ...queryOpts, pages: 3 })
;(queryOpts.queryFn as Mock).mockClear()

function App() {
usePrefetchInfiniteQuery(queryOpts)

return (
<React.Suspense fallback={<Fallback />}>
<Suspended
queryOpts={queryOpts}
renderPage={(page) => <div>data: {page.data}</div>}
/>
</React.Suspense>
)
}

const rendered = renderWithClient(queryClient, <App />)

await waitFor(() => rendered.getByText('data: Prefetch rocks!'))
fireEvent.click(rendered.getByText('Next Page'))
await waitFor(() => rendered.getByText('data: No waterfalls, boy!'))
fireEvent.click(rendered.getByText('Next Page'))
await waitFor(() => rendered.getByText('data: Tanstack Query #ftw'))
expect(queryOpts.queryFn).not.toHaveBeenCalled()
expect(Fallback).not.toHaveBeenCalled()
})

it('should not create an endless loop when using inside a suspense boundary', async () => {
const queryOpts = {
queryKey: queryKey(),
...generateInfiniteQueryOptions([
{ data: 'Infinite Page 1', currentPage: 1, totalPages: 3 },
{ data: 'Infinite Page 2', currentPage: 1, totalPages: 3 },
{ data: 'Infinite Page 3', currentPage: 1, totalPages: 3 },
]),
}

function Prefetch({ children }: { children: React.ReactNode }) {
usePrefetchInfiniteQuery(queryOpts)
return <>{children}</>
}

function App() {
return (
<React.Suspense>
<Prefetch>
<Suspended
queryOpts={queryOpts}
renderPage={(page) => <div>data: {page.data}</div>}
/>
</Prefetch>
</React.Suspense>
)
}

const rendered = renderWithClient(queryClient, <App />)
await waitFor(() => rendered.getByText('data: Infinite Page 1'))
fireEvent.click(rendered.getByText('Next Page'))
await waitFor(() => rendered.getByText('data: Infinite Page 2'))
fireEvent.click(rendered.getByText('Next Page'))
await waitFor(() => rendered.getByText('data: Infinite Page 3'))
expect(queryOpts.queryFn).toHaveBeenCalledTimes(3)
})
})
36 changes: 36 additions & 0 deletions packages/react-query/src/__tests__/usePrefetchQuery.test-d.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, expectTypeOf, it } from 'vitest'
import { usePrefetchQuery } from '..'

describe('usePrefetchQuery', () => {
it('should return nothing', () => {
const result = usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
})

expectTypeOf(result).toEqualTypeOf<void>()
})

it('should not allow refetchInterval, enabled or throwOnError options', () => {
usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// @ts-expect-error TS2345
refetchInterval: 1000,
})

usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// @ts-expect-error TS2345
enabled: true,
})

usePrefetchQuery({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// @ts-expect-error TS2345
throwOnError: true,
})
})
})
Loading

0 comments on commit d4242a5

Please sign in to comment.