@geekmidas/client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +518 -0
  2. package/dist/chunk-CUT6urMc.cjs +30 -0
  3. package/dist/fetcher-DLDD_7Sa.mjs +86 -0
  4. package/dist/fetcher-DLDD_7Sa.mjs.map +1 -0
  5. package/dist/fetcher-KdwHgdAl.cjs +98 -0
  6. package/dist/fetcher-KdwHgdAl.cjs.map +1 -0
  7. package/dist/fetcher.cjs +4 -0
  8. package/dist/fetcher.d.cts +18 -0
  9. package/dist/fetcher.d.mts +18 -0
  10. package/dist/fetcher.mjs +3 -0
  11. package/dist/openapi-hooks.cjs +44 -0
  12. package/dist/openapi-hooks.cjs.map +1 -0
  13. package/dist/openapi-hooks.d.cts +99 -0
  14. package/dist/openapi-hooks.d.mts +99 -0
  15. package/dist/openapi-hooks.mjs +43 -0
  16. package/dist/openapi-hooks.mjs.map +1 -0
  17. package/dist/openapi-types.d.cjs +0 -0
  18. package/dist/openapi-types.d.cts +443 -0
  19. package/dist/openapi-types.d.mts +443 -0
  20. package/dist/openapi.cjs +526 -0
  21. package/dist/openapi.cjs.map +1 -0
  22. package/dist/openapi.mjs +501 -0
  23. package/dist/openapi.mjs.map +1 -0
  24. package/dist/react-query.cjs +147 -0
  25. package/dist/react-query.cjs.map +1 -0
  26. package/dist/react-query.d.cts +77 -0
  27. package/dist/react-query.d.mts +77 -0
  28. package/dist/react-query.mjs +141 -0
  29. package/dist/react-query.mjs.map +1 -0
  30. package/dist/types-csACmD6U.d.cts +68 -0
  31. package/dist/types-tMp85Lt_.d.mts +68 -0
  32. package/dist/types.cjs +0 -0
  33. package/dist/types.d.cts +2 -0
  34. package/dist/types.d.mts +2 -0
  35. package/dist/types.mjs +0 -0
  36. package/package.json +59 -0
  37. package/src/__tests__/fetcher.spec.ts +409 -0
  38. package/src/__tests__/method-restrictions.spec.tsx +227 -0
  39. package/src/__tests__/openapi-hooks.spec.tsx +558 -0
  40. package/src/__tests__/react-query-infinite.spec.tsx +1003 -0
  41. package/src/__tests__/react-query-invalidation.spec.tsx +238 -0
  42. package/src/__tests__/react-query.spec.tsx +582 -0
  43. package/src/__tests__/setup.ts +281 -0
  44. package/src/__tests__/types.spec.ts +134 -0
  45. package/src/__tests__/url-parsing.spec.ts +196 -0
  46. package/src/fetcher.ts +173 -0
  47. package/src/openapi-hooks.ts +193 -0
  48. package/src/openapi-types.d.ts +440 -0
  49. package/src/openapi.json +595 -0
  50. package/src/react-query.ts +341 -0
  51. package/src/types.ts +149 -0
@@ -0,0 +1,238 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ */
4
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
5
+ import { renderHook, waitFor } from '@testing-library/react';
6
+ // biome-ignore lint/style/useImportType: <explanation>
7
+ import React from 'react';
8
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
9
+ import type { paths } from '../openapi-types';
10
+ import { TypedQueryClient, useTypedInvalidateQueries } from '../react-query';
11
+ // Mock the fetcher module
12
+ vi.mock('../fetcher', () => ({
13
+ createTypedFetcher: () => vi.fn(),
14
+ }));
15
+
16
+ describe('TypedQueryClient - Query Invalidation', () => {
17
+ let queryClient: QueryClient;
18
+ let typedClient: TypedQueryClient<paths>;
19
+
20
+ beforeEach(() => {
21
+ queryClient = new QueryClient({
22
+ defaultOptions: {
23
+ queries: { retry: false },
24
+ },
25
+ });
26
+ typedClient = new TypedQueryClient({ queryClient });
27
+ });
28
+
29
+ describe('buildQueryKey', () => {
30
+ it('should build query key with endpoint only', () => {
31
+ const key = typedClient.buildQueryKey('GET /users');
32
+ expect(key).toEqual(['GET /users']);
33
+ });
34
+
35
+ it('should build query key with params', () => {
36
+ const key = typedClient.buildQueryKey('GET /users/{id}', {
37
+ params: { id: '123' },
38
+ });
39
+ expect(key).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
40
+ });
41
+
42
+ it('should build query key with query params', () => {
43
+ const key = typedClient.buildQueryKey('GET /users', {
44
+ query: { page: 1, limit: 10 },
45
+ });
46
+ expect(key).toEqual(['GET /users', { query: { page: 1, limit: 10 } }]);
47
+ });
48
+
49
+ it('should build query key with params only for paths without query support', () => {
50
+ const key = typedClient.buildQueryKey('GET /users/{id}', {
51
+ params: { id: '123' },
52
+ });
53
+ expect(key).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
54
+ });
55
+ });
56
+
57
+ describe('invalidateQueries', () => {
58
+ it('should invalidate queries with endpoint only (partial match)', async () => {
59
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
60
+
61
+ await typedClient.invalidateQueries('GET /users');
62
+
63
+ expect(invalidateSpy).toHaveBeenCalledWith({
64
+ queryKey: ['GET /users'],
65
+ exact: false,
66
+ });
67
+ });
68
+
69
+ it('should invalidate queries with config (exact match)', async () => {
70
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
71
+
72
+ await typedClient.invalidateQueries('GET /users/{id}', {
73
+ params: { id: '123' },
74
+ });
75
+
76
+ expect(invalidateSpy).toHaveBeenCalledWith({
77
+ queryKey: ['GET /users/{id}', { params: { id: '123' } }],
78
+ exact: true,
79
+ });
80
+ });
81
+
82
+ it('should invalidate queries with query params', async () => {
83
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
84
+
85
+ await typedClient.invalidateQueries('GET /posts', {
86
+ query: { sort: 'asc' },
87
+ });
88
+
89
+ expect(invalidateSpy).toHaveBeenCalledWith({
90
+ queryKey: ['GET /posts', { query: { sort: 'asc' } }],
91
+ exact: true,
92
+ });
93
+ });
94
+ });
95
+
96
+ describe('invalidateAllQueries', () => {
97
+ it('should invalidate all queries', async () => {
98
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
99
+
100
+ await typedClient.invalidateAllQueries();
101
+
102
+ expect(invalidateSpy).toHaveBeenCalledWith();
103
+ });
104
+ });
105
+
106
+ describe('getQueryClient / setQueryClient', () => {
107
+ it('should return the query client when provided in constructor', () => {
108
+ const client = typedClient.getQueryClient();
109
+ expect(client).toBe(queryClient);
110
+ });
111
+
112
+ it('should throw error when no query client is set', () => {
113
+ const clientWithoutQC = new TypedQueryClient();
114
+
115
+ expect(() => clientWithoutQC.getQueryClient()).toThrow(
116
+ 'No QueryClient set, please provide a QueryClient via the queryClient option or ensure you are within a QueryClientProvider',
117
+ );
118
+ });
119
+
120
+ it('should allow setting query client after construction', () => {
121
+ const clientWithoutQC = new TypedQueryClient();
122
+ const newQueryClient = new QueryClient();
123
+
124
+ clientWithoutQC.setQueryClient(newQueryClient);
125
+
126
+ expect(clientWithoutQC.getQueryClient()).toBe(newQueryClient);
127
+ });
128
+ });
129
+
130
+ describe('useTypedInvalidateQueries hook', () => {
131
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
132
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
133
+ );
134
+
135
+ it('should provide invalidateQueries function', async () => {
136
+ const { result } = renderHook(
137
+ () => useTypedInvalidateQueries(typedClient),
138
+ { wrapper },
139
+ );
140
+
141
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
142
+
143
+ await result.current.invalidateQueries('GET /users/{id}', {
144
+ params: { id: '456' },
145
+ });
146
+
147
+ expect(invalidateSpy).toHaveBeenCalledWith({
148
+ queryKey: ['GET /users/{id}', { params: { id: '456' } }],
149
+ exact: true,
150
+ });
151
+ });
152
+
153
+ it('should provide invalidateAllQueries function', async () => {
154
+ const { result } = renderHook(
155
+ () => useTypedInvalidateQueries(typedClient),
156
+ { wrapper },
157
+ );
158
+
159
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
160
+
161
+ await result.current.invalidateAllQueries();
162
+
163
+ expect(invalidateSpy).toHaveBeenCalledWith();
164
+ });
165
+ });
166
+
167
+ describe('Integration test: Query invalidation with real queries', () => {
168
+ it('should invalidate matching queries after mutation', async () => {
169
+ // Set up some queries in the cache
170
+ queryClient.setQueryData(
171
+ ['GET /users'],
172
+ [
173
+ { id: '1', name: 'User 1' },
174
+ { id: '2', name: 'User 2' },
175
+ ],
176
+ );
177
+ queryClient.setQueryData(['GET /users/{id}', { params: { id: '1' } }], {
178
+ id: '1',
179
+ name: 'User 1',
180
+ });
181
+ queryClient.setQueryData(
182
+ ['GET /users', { query: { page: 1 } }],
183
+ [{ id: '1', name: 'User 1' }],
184
+ );
185
+
186
+ // Verify data is in cache
187
+ expect(queryClient.getQueryData(['GET /users'])).toBeDefined();
188
+ expect(
189
+ queryClient.getQueryData(['GET /users/{id}', { params: { id: '1' } }]),
190
+ ).toBeDefined();
191
+ expect(
192
+ queryClient.getQueryData(['GET /users', { query: { page: 1 } }]),
193
+ ).toBeDefined();
194
+
195
+ // Invalidate all user queries (partial match)
196
+ await typedClient.invalidateQueries('GET /users');
197
+
198
+ // All queries starting with 'GET /users' should be invalidated
199
+ await waitFor(() => {
200
+ const cache = queryClient.getQueryCache();
201
+ const queries = cache.findAll({ queryKey: ['GET /users'] });
202
+ queries.forEach((query) => {
203
+ expect(query.state.isInvalidated).toBe(true);
204
+ });
205
+ });
206
+ });
207
+
208
+ it('should only invalidate exact matches when config is provided', async () => {
209
+ // Set up queries
210
+ queryClient.setQueryData(
211
+ ['GET /users', { query: { page: 1 } }],
212
+ [{ id: '1', name: 'User 1' }],
213
+ );
214
+ queryClient.setQueryData(
215
+ ['GET /users', { query: { page: 2 } }],
216
+ [{ id: '2', name: 'User 2' }],
217
+ );
218
+
219
+ // Invalidate only page 1
220
+ await typedClient.invalidateQueries('GET /users', {
221
+ query: { page: 1 },
222
+ });
223
+
224
+ await waitFor(() => {
225
+ const cache = queryClient.getQueryCache();
226
+ const page1Query = cache.find({
227
+ queryKey: ['GET /users', { query: { page: 1 } }],
228
+ });
229
+ const page2Query = cache.find({
230
+ queryKey: ['GET /users', { query: { page: 2 } }],
231
+ });
232
+
233
+ expect(page1Query?.state.isInvalidated).toBe(true);
234
+ expect(page2Query?.state.isInvalidated).toBe(false);
235
+ });
236
+ });
237
+ });
238
+ });