Skip to content

Commit

Permalink
Add test for initial page param references
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson committed Jan 5, 2025
1 parent f8f0b00 commit 249e0ec
Showing 1 changed file with 246 additions and 5 deletions.
251 changes: 246 additions & 5 deletions packages/toolkit/src/query/tests/buildHooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import {
import { userEvent } from '@testing-library/user-event'
import type { SyncScreen } from '@testing-library/react-render-stream/pure'
import { createRenderStream } from '@testing-library/react-render-stream/pure'
import { HttpResponse, http } from 'msw'
import { useEffect, useState } from 'react'
import { HttpResponse, http, delay } from 'msw'
import { useEffect, useMemo, useState } from 'react'
import type { InfiniteQueryResultFlags } from '../core/buildSelectors'

// Just setup a temporary in-memory counter for tests that `getIncrementedAmount`.
Expand Down Expand Up @@ -929,9 +929,6 @@ describe('hooks tests', () => {
// See https://github.com/reduxjs/redux-toolkit/issues/4267 - Memory leak in useQuery rapid query arg changes
test('Hook subscriptions are properly cleaned up when query is fulfilled/rejected', async () => {
// This is imported already, but it seems to be causing issues with the test on certain matrixes
function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms))
}

const pokemonApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
Expand Down Expand Up @@ -1974,6 +1971,250 @@ describe('hooks tests', () => {
hasPreviousPage: true,
})
})

test('Object page params does not keep forcing refetching', async () => {
type Project = {
id: number
createdAt: string
}

type ProjectsResponse = {
projects: Project[]
numFound: number
serverTime: string
}

interface ProjectsInitialPageParam {
offset: number
limit: number
}

const apiWithInfiniteScroll = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com/' }),
endpoints: (builder) => ({
projectsLimitOffset: builder.infiniteQuery<
ProjectsResponse,
void,
ProjectsInitialPageParam
>({
infiniteQueryOptions: {
initialPageParam: {
offset: 0,
limit: 20,
},
getNextPageParam: (
lastPage,
allPages,
lastPageParam,
allPageParams,
) => {
const nextOffset = lastPageParam.offset + lastPageParam.limit
const remainingItems = lastPage?.numFound - nextOffset

if (remainingItems <= 0) {
return undefined
}

return {
...lastPageParam,
offset: nextOffset,
}
},
getPreviousPageParam: (
firstPage,
allPages,
firstPageParam,
allPageParams,
) => {
const prevOffset = firstPageParam.offset - firstPageParam.limit
if (prevOffset < 0) return undefined

return {
...firstPageParam,
offset: firstPageParam.offset - firstPageParam.limit,
}
},
},
query: ({ offset, limit }) => {
return {
url: `https://example.com/api/projectsLimitOffset?offset=${offset}&limit=${limit}`,
method: 'GET',
}
},
}),
}),
})

const projects = Array.from({ length: 50 }, (_, i) => {
return {
id: i,
createdAt: Date.now() + i * 1000,
}
})

let numRequests = 0

server.use(
http.get(
'https://example.com/api/projectsLimitOffset',
async ({ request }) => {
const url = new URL(request.url)
const limit = parseInt(url.searchParams.get('limit') ?? '5', 10)
let offset = parseInt(url.searchParams.get('offset') ?? '0', 10)

numRequests++

if (isNaN(offset) || offset < 0) {
offset = 0
}
if (isNaN(limit) || limit <= 0) {
return HttpResponse.json(
{
message:
"Invalid 'limit' parameter. It must be a positive integer.",
} as any,
{ status: 400 },
)
}

const result = projects.slice(offset, offset + limit)

await delay(10)
return HttpResponse.json({
projects: result,
serverTime: Date.now(),
numFound: projects.length,
})
},
),
)

function LimitOffsetExample() {
const {
data,
hasPreviousPage,
hasNextPage,
error,
isFetching,
isLoading,
isError,
fetchNextPage,
fetchPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
status,
} = apiWithInfiniteScroll.useProjectsLimitOffsetInfiniteQuery(
undefined,
{
initialPageParam: {
offset: 10,
limit: 10,
},
},
)

const [counter, setCounter] = useState(0)

const combinedData = useMemo(() => {
return data?.pages?.map((item) => item?.projects)?.flat()
}, [data])

return (
<div>
<h2>Limit and Offset Infinite Scroll</h2>
<button onClick={() => setCounter((c) => c + 1)}>Increment</button>
<div>Counter: {counter}</div>
{isLoading ? (
<p>Loading...</p>
) : isError ? (
<span>Error: {error.message}</span>
) : null}

<>
<div>
<button
onClick={() => fetchPreviousPage()}
disabled={!hasPreviousPage || isFetchingPreviousPage}
>
{isFetchingPreviousPage
? 'Loading more...'
: hasPreviousPage
? 'Load Older'
: 'Nothing more to load'}
</button>
</div>
<div data-testid="projects">
{combinedData?.map((project, index, arr) => {
return (
<div key={project.id}>
<div data-testid="project">
<div>{`Project ${project.id} (created at: ${project.createdAt})`}</div>
</div>
</div>
)
})}
</div>
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? 'Loading more...'
: hasNextPage
? 'Load Newer'
: 'Nothing more to load'}
</button>
</div>
<div>
{isFetching && !isFetchingPreviousPage && !isFetchingNextPage
? 'Background Updating...'
: null}
</div>
</>
</div>
)
}

const storeRef = setupApiStore(
apiWithInfiniteScroll,
{ ...actionsReducer },
{
withoutTestLifecycles: true,
},
)

const { takeRender, render, totalRenderCount } = createRenderStream({
snapshotDOM: true,
})

render(<LimitOffsetExample />, {
wrapper: storeRef.wrapper,
})

{
const { withinDOM } = await takeRender()
withinDOM().getByText('Counter: 0')
withinDOM().getByText('Loading...')
}

{
const { withinDOM } = await takeRender()
withinDOM().getByText('Counter: 0')
withinDOM().getByText('Loading...')
}

{
const { withinDOM } = await takeRender()
withinDOM().getByText('Counter: 0')

expect(withinDOM().getAllByTestId('project').length).toBe(10)
expect(withinDOM().queryByTestId('Loading...')).toBeNull()
}

expect(totalRenderCount()).toBe(3)
expect(numRequests).toBe(1)
})
})

describe('useMutation', () => {
Expand Down

0 comments on commit 249e0ec

Please sign in to comment.