Skip to content

Commit d474bc4

Browse files
committed
feat: Create a react query hook plugin
1 parent 41d6e62 commit d474bc4

File tree

96 files changed

+3103
-371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+3103
-371
lines changed

.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
examples/src/
22
lib/
3+
4+
packages/typoas-react-query/src/__tests__/sample-client.ts

.eslintrc.js

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ module.exports = {
66
node: true,
77
},
88
plugins: ['jest', '@typescript-eslint'],
9-
ignorePatterns: ['**/dist/'],
109
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
1110
parser: '@typescript-eslint/parser',
1211
};

.pnp.cjs

+841-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.pnp.loader.mjs

+38-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

.yarn/releases/yarn-4.1.0.cjs .yarn/releases/yarn-4.2.2.cjs

+298-297
Large diffs are not rendered by default.

.yarn/versions/f5d9f57f.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
releases:
2+
"@typoas/react-query": major
3+
"@typoas/runtime": patch

.yarnrc.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ enableGlobalCache: false
44

55
npmPublishAccess: public
66

7-
yarnPath: .yarn/releases/yarn-4.1.0.cjs
7+
yarnPath: .yarn/releases/yarn-4.2.2.cjs

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
"prettier": "^3.2.5",
2121
"typescript": "^5.3.3"
2222
},
23-
"packageManager": "yarn@4.1.0"
23+
"packageManager": "yarn@4.2.2"
2424
}

packages/typoas-react-query/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'jsdom',
4+
testMatch: ['**/__tests__/**/*.spec.[jt]s?(x)'],
5+
testPathIgnorePatterns: ['/node_modules/', '/lib/'],
6+
};
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "@typoas/react-query",
3+
"version": "3.0.0",
4+
"license": "MIT",
5+
"repository": {
6+
"type": "git",
7+
"url": "https://github.com/embraser01/typoas",
8+
"directory": "packages/typoas-react-query"
9+
},
10+
"main": "./src/index.ts",
11+
"scripts": {
12+
"prepack": "tsc",
13+
"start": "ts-node ./src/bin.ts",
14+
"test:types": "tsc --noEmit",
15+
"test": "jest"
16+
},
17+
"devDependencies": {
18+
"@jest/globals": "^29.7.0",
19+
"@tanstack/react-query": "^5.35.5",
20+
"@testing-library/react": "^15.0.7",
21+
"@types/node": "^20.11.24",
22+
"@types/react": "^18.3.2",
23+
"@types/react-dom": "^18.3.0",
24+
"@typoas/runtime": "workspace:^",
25+
"jest": "^29.7.0",
26+
"jest-environment-jsdom": "^29.7.0",
27+
"react": "^18.3.1",
28+
"react-dom": "^18.3.1",
29+
"ts-jest": "^29.1.2",
30+
"typescript": "^5.3.3"
31+
},
32+
"peerDependencies": {
33+
"@tanstack/react-query": "^5.35.5",
34+
"@typoas/runtime": "workspace:^"
35+
},
36+
"files": [
37+
"/lib/**/*.js",
38+
"/lib/**/*.d.ts",
39+
"!/lib/**/__tests__/*"
40+
],
41+
"publishConfig": {
42+
"main": "./lib/index.js",
43+
"types": "./lib/index.d.ts"
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3+
import { PropsWithChildren } from 'react';
4+
import { renderHook, waitFor } from '@testing-library/react';
5+
import { createContext, findPetsByStatus, Pet } from './sample-client';
6+
import { ApiContextProvider } from '../api-context';
7+
import { MockFetcher } from './mock-fetcher';
8+
import { createInfiniteQueryHook } from '../infinite-query-factory';
9+
10+
describe('createInfiniteQueryHook', () => {
11+
const queryClient = new QueryClient();
12+
const fetcher = new MockFetcher();
13+
const ctx = createContext({ fetcher });
14+
15+
const wrapper = ({ children }: PropsWithChildren) => (
16+
<ApiContextProvider context={ctx}>
17+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
18+
</ApiContextProvider>
19+
);
20+
21+
it('should work for simple cases', async () => {
22+
const useFindPetsByStatus = createInfiniteQueryHook(findPetsByStatus, {
23+
initialPageParam: { page: 1 },
24+
getNextPageParam: (lastPage, allPages) => {
25+
if (allPages.length === 1) {
26+
return { page: 2 };
27+
}
28+
return undefined;
29+
},
30+
});
31+
fetcher
32+
.mockResponseOnce<Pet[]>([
33+
{ id: 3, name: 'Rocky', status: 'available', photoUrls: [] },
34+
{ id: 4, name: 'Beethoven', status: 'available', photoUrls: [] },
35+
])
36+
.mockResponseOnce<Pet[]>([
37+
{ id: 1, name: 'Bob', status: 'available', photoUrls: [] },
38+
{ id: 2, name: 'Rufus', status: 'available', photoUrls: [] },
39+
]);
40+
41+
const { result } = renderHook(
42+
() => useFindPetsByStatus({ queryKey: [{ status: 'available' }] }),
43+
{ wrapper },
44+
);
45+
46+
await waitFor(() => {
47+
expect(result.current.data?.pages.length).toEqual(1);
48+
expect(result.current.data?.pages[0].map((d) => d.id)).toEqual([1, 2]);
49+
});
50+
51+
result.current.fetchNextPage();
52+
53+
await waitFor(() => {
54+
expect(result.current.data?.pages.length).toEqual(2);
55+
expect(result.current.data?.pages[1].map((d) => d.id)).toEqual([3, 4]);
56+
});
57+
});
58+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Fetcher, RequestContext, ResponseContext } from '@typoas/runtime';
2+
3+
export class MockFetcher implements Fetcher {
4+
private data: unknown = undefined;
5+
6+
private resQueue: unknown[] = [];
7+
8+
mockResponse<T>(data: T): void {
9+
this.data = data;
10+
}
11+
12+
mockResponseOnce<T>(data: T): MockFetcher {
13+
this.resQueue.push(data);
14+
return this;
15+
}
16+
17+
async send(
18+
request: RequestContext,
19+
options?: string,
20+
): Promise<ResponseContext> {
21+
let data = this.resQueue.pop();
22+
if (!data) {
23+
data = this.data;
24+
}
25+
26+
return new ResponseContext(
27+
200,
28+
{ 'content-type': 'application/json' },
29+
{
30+
binary: async () => new Blob([]),
31+
text: async () => '',
32+
json: async () => data,
33+
},
34+
);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3+
import { PropsWithChildren } from 'react';
4+
import { renderHook, waitFor } from '@testing-library/react';
5+
import { createQueryHook } from '../query-factory';
6+
import { createContext, findPetsByStatus, Pet } from './sample-client';
7+
import { ApiContextProvider } from '../api-context';
8+
import { MockFetcher } from './mock-fetcher';
9+
10+
describe('createQueryHook', () => {
11+
const queryClient = new QueryClient();
12+
const fetcher = new MockFetcher();
13+
const ctx = createContext({ fetcher });
14+
15+
const wrapper = ({ children }: PropsWithChildren) => (
16+
<ApiContextProvider context={ctx}>
17+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
18+
</ApiContextProvider>
19+
);
20+
21+
it('should work for simple cases', async () => {
22+
const useFindPetsByStatus = createQueryHook(findPetsByStatus, {
23+
successStatus: 200,
24+
});
25+
fetcher.mockResponse<Pet[]>([
26+
{ id: 1, name: 'Rufus', status: 'available', photoUrls: [] },
27+
{ id: 2, name: 'Rocky', status: 'available', photoUrls: [] },
28+
]);
29+
30+
const { result } = renderHook(
31+
() => useFindPetsByStatus({ queryKey: [{ status: 'available' }] }),
32+
{ wrapper },
33+
);
34+
35+
await waitFor(() =>
36+
expect(result.current.data?.map((d) => d.id)).toEqual([1, 2]),
37+
);
38+
});
39+
});

0 commit comments

Comments
 (0)