Skip to content

Commit 391d8cb

Browse files
committed
So far so good
1 parent d510d54 commit 391d8cb

File tree

4 files changed

+206
-25
lines changed

4 files changed

+206
-25
lines changed

packages/openapi-react-query/src/index.ts

+27-25
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
type UseMutationResult,
44
type UseQueryOptions,
55
type UseQueryResult,
6+
type InfiniteData,
7+
type InfiniteQueryObserverResult,
68
type UseInfiniteQueryOptions,
79
type UseInfiniteQueryResult,
810
type UseSuspenseQueryOptions,
@@ -103,34 +105,34 @@ export type UseInfiniteQueryMethod<Paths extends Record<string, Record<HttpMetho
103105
url: Path,
104106
...[init, options, queryClient]: RequiredKeysOf<Init> extends never
105107
? [
106-
InitWithUnknowns<Init>?,
107-
Omit<
108-
UseInfiniteQueryOptions<
109-
Response["data"],
110-
Response["error"],
111-
Response["data"],
112-
number,
113-
QueryKey<Paths, Method, Path>
114-
>,
115-
"queryKey" | "queryFn"
116-
>?,
117-
QueryClient?,
108+
InitWithUnknowns<Init>?,
109+
Omit<
110+
UseInfiniteQueryOptions<
111+
Response["data"],
112+
Response["error"],
113+
Response["data"],
114+
number,
115+
QueryKey<Paths, Method, Path>
116+
>,
117+
"queryKey" | "queryFn"
118+
>?,
119+
QueryClient?,
118120
]
119121
: [
120-
InitWithUnknowns<Init>,
121-
Omit<
122-
UseInfiniteQueryOptions<
123-
Response["data"],
124-
Response["error"],
125-
Response["data"],
126-
number,
127-
QueryKey<Paths, Method, Path>
128-
>,
129-
"queryKey" | "queryFn"
130-
>?,
131-
QueryClient?,
122+
InitWithUnknowns<Init>,
123+
Omit<
124+
UseInfiniteQueryOptions<
125+
Response["data"],
126+
Response["error"],
127+
Response["data"],
128+
number,
129+
QueryKey<Paths, Method, Path>
130+
>,
131+
"queryKey" | "queryFn"
132+
>?,
133+
QueryClient?,
132134
]
133-
) => UseInfiniteQueryResult<Response["data"], Response["error"]>;
135+
) => UseInfiniteQueryResult<InfiniteData<Response["data"]>, Response["error"]>;
134136

135137
export type UseSuspenseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <
136138
Method extends HttpMethod,

packages/openapi-react-query/test/fixtures/api.d.ts

+53
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,59 @@
44
*/
55

66
export interface paths {
7+
"/paginated-data": {
8+
parameters: {
9+
query?: never;
10+
header?: never;
11+
path?: never;
12+
cookie?: never;
13+
};
14+
get: {
15+
parameters: {
16+
query: {
17+
limit: number;
18+
cursor?: number;
19+
};
20+
header?: never;
21+
path?: never;
22+
cookie?: never;
23+
};
24+
requestBody?: never;
25+
responses: {
26+
/** @description Successful response */
27+
200: {
28+
headers: {
29+
[name: string]: unknown;
30+
};
31+
content: {
32+
"application/json": {
33+
items?: number[];
34+
nextPage?: number;
35+
};
36+
};
37+
};
38+
/** @description Error response */
39+
500: {
40+
headers: {
41+
[name: string]: unknown;
42+
};
43+
content: {
44+
"application/json": {
45+
code?: number;
46+
message?: string;
47+
};
48+
};
49+
};
50+
};
51+
};
52+
put?: never;
53+
post?: never;
54+
delete?: never;
55+
options?: never;
56+
head?: never;
57+
patch?: never;
58+
trace?: never;
59+
};
760
"/comment": {
861
parameters: {
962
query?: never;

packages/openapi-react-query/test/fixtures/api.yaml

+38
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,44 @@ info:
33
title: Test Specification
44
version: "1.0"
55
paths:
6+
/paginated-data:
7+
get:
8+
parameters:
9+
- in: query
10+
name: limit
11+
required: true
12+
schema:
13+
type: integer
14+
- in: query
15+
name: cursor
16+
required: false
17+
schema:
18+
type: integer
19+
responses:
20+
'200':
21+
description: Successful response
22+
content:
23+
application/json:
24+
schema:
25+
type: object
26+
properties:
27+
items:
28+
type: array
29+
items:
30+
type: integer
31+
nextPage:
32+
type: integer
33+
'500':
34+
description: Error response
35+
content:
36+
application/json:
37+
schema:
38+
type: object
39+
properties:
40+
code:
41+
type: integer
42+
message:
43+
type: string
644
/comment:
745
put:
846
requestBody:

packages/openapi-react-query/test/index.test.tsx

+88
Original file line numberDiff line numberDiff line change
@@ -822,4 +822,92 @@ describe("client", () => {
822822
});
823823
});
824824
});
825+
describe("useInfiniteQuery", () => {
826+
it("should fetch data correctly with pagination and include cursor", async () => {
827+
const fetchClient = createFetchClient<paths>({ baseUrl });
828+
const client = createClient(fetchClient);
829+
830+
// Track request URLs using the mock handler
831+
let firstRequestUrl: URL | undefined;
832+
let secondRequestUrl: URL | undefined;
833+
834+
// First page request handler
835+
const firstRequestHandler = useMockRequestHandler({
836+
baseUrl,
837+
method: "get",
838+
path: "/paginated-data",
839+
status: 200,
840+
body: { items: [1, 2, 3], nextPage: 1 },
841+
});
842+
843+
const { result, rerender } = renderHook(
844+
() => client.useInfiniteQuery("get", "/paginated-data",
845+
{
846+
params: {
847+
query: {
848+
limit: 3
849+
}
850+
}
851+
},
852+
{
853+
getNextPageParam: (lastPage) => lastPage.nextPage,
854+
initialPageParam: 0,
855+
}),
856+
{ wrapper },
857+
);
858+
859+
// Wait for initial query to complete
860+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
861+
862+
// Verify first request
863+
firstRequestUrl = firstRequestHandler.getRequestUrl();
864+
expect(firstRequestUrl?.searchParams.get('limit')).toBe('3');
865+
expect(firstRequestUrl?.searchParams.get('cursor')).toBe('0');
866+
867+
// Set up mock for second page before triggering next page fetch
868+
const secondRequestHandler = useMockRequestHandler({
869+
baseUrl,
870+
method: "get",
871+
path: "/paginated-data",
872+
status: 200,
873+
body: { items: [4, 5, 6], nextPage: 2 },
874+
});
875+
876+
// Fetch next page
877+
await act(async () => {
878+
await result.current.fetchNextPage();
879+
// Force a rerender to ensure state is updated
880+
rerender();
881+
});
882+
883+
// Wait for second page to be fetched and verify loading states
884+
await waitFor(() => {
885+
expect(result.current.isFetching).toBe(false);
886+
expect(result.current.hasNextPage).toBe(true);
887+
expect(result.current.data?.pages).toHaveLength(2);
888+
});
889+
890+
// Verify second request
891+
secondRequestUrl = secondRequestHandler.getRequestUrl();
892+
expect(secondRequestUrl?.searchParams.get('limit')).toBe('3');
893+
expect(secondRequestUrl?.searchParams.get('cursor')).toBe('1');
894+
895+
expect(result.current.data).toBeDefined();
896+
expect(result.current.data!.pages[0].nextPage).toBe(1);
897+
898+
899+
expect(result.current.data).toBeDefined();
900+
expect(result.current.data!.pages[1].nextPage).toBe(2);
901+
902+
// Verify the complete data structure
903+
expect(result.current.data?.pages).toEqual([
904+
{ items: [1, 2, 3], nextPage: 1 },
905+
{ items: [4, 5, 6], nextPage: 2 }
906+
]);
907+
908+
// Verify we can access all items through pages
909+
const allItems = result.current.data?.pages.flatMap(page => page.items);
910+
expect(allItems).toEqual([1, 2, 3, 4, 5, 6]);
911+
});
912+
})
825913
});

0 commit comments

Comments
 (0)