@dhis2/app-service-data 3.2.4 → 3.2.8
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.
- package/build/cjs/__tests__/integration.test.js +19 -45
- package/build/cjs/__tests__/mutations.test.js +55 -64
- package/build/cjs/links/RestAPILink/queryToRequestOptions/textPlainMatchers.js +18 -8
- package/build/cjs/links/RestAPILink/queryToRequestOptions/textPlainMatchers.test.js +38 -10
- package/build/cjs/react/hooks/useDataMutation.test.js +320 -52
- package/build/cjs/react/hooks/useDataQuery.js +16 -9
- package/build/cjs/react/hooks/useDataQuery.test.js +143 -0
- package/build/es/__tests__/integration.test.js +19 -45
- package/build/es/__tests__/mutations.test.js +53 -64
- package/build/es/links/RestAPILink/queryToRequestOptions/textPlainMatchers.js +13 -6
- package/build/es/links/RestAPILink/queryToRequestOptions/textPlainMatchers.test.js +39 -11
- package/build/es/react/hooks/useDataMutation.test.js +315 -50
- package/build/es/react/hooks/useDataQuery.js +17 -10
- package/build/es/react/hooks/useDataQuery.test.js +143 -0
- package/build/types/links/RestAPILink/queryToRequestOptions/textPlainMatchers.d.ts +2 -1
- package/package.json +2 -2
|
@@ -2,79 +2,347 @@
|
|
|
2
2
|
|
|
3
3
|
var _reactHooks = require("@testing-library/react-hooks");
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var React = _interopRequireWildcard(require("react"));
|
|
6
6
|
|
|
7
7
|
var _CustomDataProvider = require("../components/CustomDataProvider");
|
|
8
8
|
|
|
9
|
+
var _useDataEngine = require("./useDataEngine");
|
|
10
|
+
|
|
9
11
|
var _useDataMutation = require("./useDataMutation");
|
|
10
12
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
13
|
+
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
|
14
|
+
|
|
15
|
+
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
16
|
+
|
|
17
|
+
describe('useDataMutation', () => {
|
|
18
|
+
it('should render without failing', async () => {
|
|
19
|
+
const mutation = {
|
|
20
|
+
type: 'create',
|
|
21
|
+
resource: 'answer',
|
|
22
|
+
data: {
|
|
23
|
+
answer: '?'
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const data = {
|
|
27
|
+
answer: 42
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const wrapper = ({
|
|
31
|
+
children
|
|
32
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
33
|
+
data: data
|
|
34
|
+
}, children);
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
result,
|
|
38
|
+
waitFor
|
|
39
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation), {
|
|
40
|
+
wrapper
|
|
41
|
+
});
|
|
42
|
+
const [mutate, beforeMutation] = result.current;
|
|
43
|
+
expect(beforeMutation).toMatchObject({
|
|
44
|
+
loading: false,
|
|
45
|
+
called: false
|
|
46
|
+
});
|
|
47
|
+
(0, _reactHooks.act)(() => {
|
|
48
|
+
mutate();
|
|
49
|
+
});
|
|
50
|
+
await waitFor(() => {
|
|
51
|
+
const [, duringMutation] = result.current;
|
|
52
|
+
expect(duringMutation).toMatchObject({
|
|
53
|
+
loading: true,
|
|
54
|
+
called: true
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
await waitFor(() => {
|
|
58
|
+
const [, afterMutation] = result.current;
|
|
59
|
+
expect(afterMutation).toMatchObject({
|
|
60
|
+
loading: false,
|
|
61
|
+
called: true,
|
|
62
|
+
data: 42
|
|
63
|
+
});
|
|
64
|
+
});
|
|
34
65
|
});
|
|
35
|
-
it('
|
|
36
|
-
|
|
37
|
-
|
|
66
|
+
it('should run immediately with lazy: false', async () => {
|
|
67
|
+
const mutation = {
|
|
68
|
+
type: 'create',
|
|
69
|
+
resource: 'answer',
|
|
70
|
+
data: {
|
|
71
|
+
answer: '?'
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const data = {
|
|
75
|
+
answer: 42
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const wrapper = ({
|
|
79
|
+
children
|
|
80
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
81
|
+
data: data
|
|
82
|
+
}, children);
|
|
83
|
+
|
|
84
|
+
const {
|
|
85
|
+
result,
|
|
86
|
+
waitFor
|
|
87
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation, {
|
|
88
|
+
lazy: false
|
|
89
|
+
}), {
|
|
90
|
+
wrapper
|
|
91
|
+
});
|
|
92
|
+
const [, duringMutation] = result.current;
|
|
93
|
+
expect(duringMutation).toMatchObject({
|
|
94
|
+
loading: true,
|
|
95
|
+
called: true
|
|
96
|
+
});
|
|
97
|
+
await waitFor(() => {
|
|
98
|
+
const [, afterMutation] = result.current;
|
|
99
|
+
expect(afterMutation).toMatchObject({
|
|
100
|
+
loading: false,
|
|
101
|
+
called: true,
|
|
102
|
+
data: 42
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
it('should call onComplete on success', async () => {
|
|
107
|
+
const onComplete = jest.fn();
|
|
108
|
+
const mutation = {
|
|
109
|
+
type: 'create',
|
|
110
|
+
resource: 'answer',
|
|
111
|
+
data: {
|
|
112
|
+
answer: '?'
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const data = {
|
|
116
|
+
answer: 42
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const wrapper = ({
|
|
120
|
+
children
|
|
121
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
122
|
+
data: data
|
|
123
|
+
}, children);
|
|
124
|
+
|
|
125
|
+
const {
|
|
126
|
+
result,
|
|
127
|
+
waitFor
|
|
128
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation, {
|
|
129
|
+
onComplete
|
|
130
|
+
}), {
|
|
131
|
+
wrapper
|
|
132
|
+
});
|
|
133
|
+
expect(onComplete).toHaveBeenCalledTimes(0);
|
|
134
|
+
const [mutate] = result.current;
|
|
38
135
|
(0, _reactHooks.act)(() => {
|
|
39
|
-
|
|
40
|
-
|
|
136
|
+
mutate();
|
|
137
|
+
});
|
|
138
|
+
await waitFor(() => {
|
|
139
|
+
const [, state] = result.current;
|
|
140
|
+
expect(state).toMatchObject({
|
|
141
|
+
loading: false,
|
|
142
|
+
called: true,
|
|
143
|
+
data: 42
|
|
41
144
|
});
|
|
145
|
+
expect(onComplete).toHaveBeenCalledTimes(1);
|
|
146
|
+
expect(onComplete).toHaveBeenLastCalledWith(42);
|
|
42
147
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
148
|
+
});
|
|
149
|
+
it('should call onError on error', async () => {
|
|
150
|
+
const error = new Error('Something went wrong');
|
|
151
|
+
const onError = jest.fn();
|
|
152
|
+
const mutation = {
|
|
153
|
+
type: 'create',
|
|
154
|
+
resource: 'answer',
|
|
155
|
+
data: {
|
|
156
|
+
answer: 42
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const data = {
|
|
160
|
+
answer: () => {
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const wrapper = ({
|
|
166
|
+
children
|
|
167
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
168
|
+
data: data
|
|
169
|
+
}, children);
|
|
170
|
+
|
|
171
|
+
const {
|
|
172
|
+
result,
|
|
173
|
+
waitFor
|
|
174
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation, {
|
|
175
|
+
onError
|
|
176
|
+
}), {
|
|
177
|
+
wrapper
|
|
47
178
|
});
|
|
179
|
+
expect(onError).toHaveBeenCalledTimes(0);
|
|
180
|
+
const [mutate] = result.current;
|
|
48
181
|
(0, _reactHooks.act)(() => {
|
|
49
182
|
mutate();
|
|
50
183
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
184
|
+
await waitFor(() => {
|
|
185
|
+
const [, state] = result.current;
|
|
186
|
+
expect(state).toMatchObject({
|
|
187
|
+
loading: false,
|
|
188
|
+
called: true,
|
|
189
|
+
error
|
|
190
|
+
});
|
|
56
191
|
});
|
|
192
|
+
expect(onError).toHaveBeenCalledTimes(1);
|
|
193
|
+
expect(onError).toHaveBeenLastCalledWith(error);
|
|
57
194
|
});
|
|
58
|
-
it('
|
|
59
|
-
|
|
60
|
-
|
|
195
|
+
it('should resolve variables', async () => {
|
|
196
|
+
const mutation = {
|
|
197
|
+
type: 'update',
|
|
198
|
+
resource: 'answer',
|
|
199
|
+
id: ({
|
|
200
|
+
id
|
|
201
|
+
}) => id,
|
|
202
|
+
data: {
|
|
203
|
+
answer: '?'
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const answerSpy = jest.fn(() => 42);
|
|
207
|
+
const data = {
|
|
208
|
+
answer: answerSpy
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const wrapper = ({
|
|
212
|
+
children
|
|
213
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
214
|
+
data: data
|
|
215
|
+
}, children);
|
|
216
|
+
|
|
217
|
+
const {
|
|
218
|
+
result,
|
|
219
|
+
waitFor
|
|
220
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation, {
|
|
221
|
+
lazy: false,
|
|
222
|
+
variables: {
|
|
223
|
+
id: '1'
|
|
224
|
+
}
|
|
225
|
+
}), {
|
|
226
|
+
wrapper
|
|
227
|
+
});
|
|
228
|
+
await waitFor(() => {
|
|
229
|
+
expect(answerSpy).toHaveBeenLastCalledWith(expect.any(String), expect.objectContaining({
|
|
230
|
+
id: '1'
|
|
231
|
+
}), expect.any(Object));
|
|
232
|
+
});
|
|
233
|
+
const [mutate] = result.current;
|
|
61
234
|
(0, _reactHooks.act)(() => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}), {
|
|
65
|
-
wrapper
|
|
235
|
+
mutate({
|
|
236
|
+
id: '2'
|
|
66
237
|
});
|
|
67
238
|
});
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
239
|
+
await waitFor(() => {
|
|
240
|
+
expect(answerSpy).toHaveBeenLastCalledWith(expect.any(String), expect.objectContaining({
|
|
241
|
+
id: '2'
|
|
242
|
+
}), expect.any(Object));
|
|
72
243
|
});
|
|
73
|
-
|
|
74
|
-
|
|
244
|
+
});
|
|
245
|
+
it('should return a reference to the engine', async () => {
|
|
246
|
+
const mutation = {
|
|
247
|
+
type: 'create',
|
|
248
|
+
resource: 'answer',
|
|
249
|
+
data: {
|
|
250
|
+
answer: '?'
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const wrapper = ({
|
|
255
|
+
children
|
|
256
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
257
|
+
data: {}
|
|
258
|
+
}, children);
|
|
259
|
+
|
|
260
|
+
const engineHook = (0, _reactHooks.renderHook)(() => (0, _useDataEngine.useDataEngine)(), {
|
|
261
|
+
wrapper
|
|
262
|
+
});
|
|
263
|
+
const mutationHook = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation), {
|
|
264
|
+
wrapper
|
|
265
|
+
});
|
|
266
|
+
/**
|
|
267
|
+
* Ideally we'd check referential equality here with .toBe, but since
|
|
268
|
+
* both hooks run in a different context that doesn't work.
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
expect(mutationHook.result.current[1].engine).toStrictEqual(engineHook.result.current);
|
|
272
|
+
});
|
|
273
|
+
it('should return a stable mutate function', async () => {
|
|
274
|
+
const mutation = {
|
|
275
|
+
type: 'create',
|
|
276
|
+
resource: 'answer',
|
|
277
|
+
data: {
|
|
278
|
+
answer: '?'
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
const data = {
|
|
282
|
+
answer: 42
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const wrapper = ({
|
|
286
|
+
children
|
|
287
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
288
|
+
data: data
|
|
289
|
+
}, children);
|
|
290
|
+
|
|
291
|
+
const {
|
|
292
|
+
result
|
|
293
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation), {
|
|
294
|
+
wrapper
|
|
295
|
+
});
|
|
296
|
+
const [firstMutate] = result.current;
|
|
297
|
+
await (0, _reactHooks.act)(async () => {
|
|
298
|
+
await firstMutate({
|
|
299
|
+
variable: 'variable'
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
const [secondMutate, state] = result.current;
|
|
75
303
|
expect(state).toMatchObject({
|
|
76
304
|
loading: false,
|
|
77
|
-
|
|
305
|
+
called: true
|
|
306
|
+
});
|
|
307
|
+
expect(firstMutate).toBe(secondMutate);
|
|
308
|
+
});
|
|
309
|
+
it('should resolve with the data from mutate on success', async () => {
|
|
310
|
+
const mutation = {
|
|
311
|
+
type: 'create',
|
|
312
|
+
resource: 'answer',
|
|
313
|
+
data: {
|
|
314
|
+
answer: '?'
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
const data = {
|
|
318
|
+
answer: 42
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const wrapper = ({
|
|
322
|
+
children
|
|
323
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
324
|
+
data: data
|
|
325
|
+
}, children);
|
|
326
|
+
|
|
327
|
+
const {
|
|
328
|
+
result,
|
|
329
|
+
waitFor
|
|
330
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataMutation.useDataMutation)(mutation), {
|
|
331
|
+
wrapper
|
|
332
|
+
});
|
|
333
|
+
let mutatePromise;
|
|
334
|
+
const [mutate] = result.current;
|
|
335
|
+
(0, _reactHooks.act)(() => {
|
|
336
|
+
mutatePromise = mutate();
|
|
337
|
+
});
|
|
338
|
+
await waitFor(() => {
|
|
339
|
+
const [, state] = result.current;
|
|
340
|
+
expect(state).toMatchObject({
|
|
341
|
+
loading: false,
|
|
342
|
+
called: true,
|
|
343
|
+
data: 42
|
|
344
|
+
});
|
|
345
|
+
expect(mutatePromise).resolves.toBe(42);
|
|
78
346
|
});
|
|
79
347
|
});
|
|
80
348
|
});
|
|
@@ -96,9 +96,13 @@ const useDataQuery = (query, {
|
|
|
96
96
|
/**
|
|
97
97
|
* Refetch allows a user to update the variables or just
|
|
98
98
|
* trigger a refetch of the query with the current variables.
|
|
99
|
+
*
|
|
100
|
+
* We're using useCallback to make the identity of the function
|
|
101
|
+
* as stable as possible, so that it won't trigger excessive
|
|
102
|
+
* rerenders when used for side-effects.
|
|
99
103
|
*/
|
|
100
104
|
|
|
101
|
-
const refetch = newVariables => {
|
|
105
|
+
const refetch = (0, _react.useCallback)(newVariables => {
|
|
102
106
|
/**
|
|
103
107
|
* If there are no updates that will trigger an automatic refetch
|
|
104
108
|
* we'll need to call react-query's refetch directly
|
|
@@ -112,10 +116,6 @@ const useDataQuery = (query, {
|
|
|
112
116
|
}) => data);
|
|
113
117
|
}
|
|
114
118
|
|
|
115
|
-
if (!enabled) {
|
|
116
|
-
setEnabled(true);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
119
|
if (newVariables) {
|
|
120
120
|
// Use cached hash if it exists
|
|
121
121
|
const currentHash = variablesHash.current || (0, _stableVariablesHash.stableVariablesHash)(variables);
|
|
@@ -125,8 +125,11 @@ const useDataQuery = (query, {
|
|
|
125
125
|
const mergedHash = (0, _stableVariablesHash.stableVariablesHash)(mergedVariables);
|
|
126
126
|
const identical = currentHash === mergedHash;
|
|
127
127
|
|
|
128
|
-
if (identical) {
|
|
129
|
-
|
|
128
|
+
if (identical && enabled) {
|
|
129
|
+
/**
|
|
130
|
+
* If the variables are identical and the query is enabled
|
|
131
|
+
* we'll need to trigger the refetch manually
|
|
132
|
+
*/
|
|
130
133
|
return queryRefetch({
|
|
131
134
|
cancelRefetch: true,
|
|
132
135
|
throwOnError: false
|
|
@@ -137,6 +140,11 @@ const useDataQuery = (query, {
|
|
|
137
140
|
variablesHash.current = mergedHash;
|
|
138
141
|
setVariables(mergedVariables);
|
|
139
142
|
}
|
|
143
|
+
} // Enable the query after the variables have been set to prevent extra request
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if (!enabled) {
|
|
147
|
+
setEnabled(true);
|
|
140
148
|
} // This promise does not currently reject on errors
|
|
141
149
|
|
|
142
150
|
|
|
@@ -145,13 +153,12 @@ const useDataQuery = (query, {
|
|
|
145
153
|
resolve(data);
|
|
146
154
|
};
|
|
147
155
|
});
|
|
148
|
-
};
|
|
156
|
+
}, [enabled, queryRefetch, variables]);
|
|
149
157
|
/**
|
|
150
158
|
* react-query returns null or an error, but we return undefined
|
|
151
159
|
* or an error, so this ensures consistency with the other types.
|
|
152
160
|
*/
|
|
153
161
|
|
|
154
|
-
|
|
155
162
|
const ourError = error || undefined;
|
|
156
163
|
return {
|
|
157
164
|
engine,
|
|
@@ -507,6 +507,149 @@ describe('useDataQuery', () => {
|
|
|
507
507
|
});
|
|
508
508
|
});
|
|
509
509
|
describe('return values: refetch', () => {
|
|
510
|
+
it('Should only trigger a single request when refetch is called on a lazy query with new variables', async () => {
|
|
511
|
+
const spy = jest.fn((type, query) => {
|
|
512
|
+
if (query.id === '1') {
|
|
513
|
+
return 42;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return 0;
|
|
517
|
+
});
|
|
518
|
+
const data = {
|
|
519
|
+
answer: spy
|
|
520
|
+
};
|
|
521
|
+
const query = {
|
|
522
|
+
x: {
|
|
523
|
+
resource: 'answer',
|
|
524
|
+
id: ({
|
|
525
|
+
id
|
|
526
|
+
}) => id
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
const wrapper = ({
|
|
531
|
+
children
|
|
532
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
533
|
+
data: data
|
|
534
|
+
}, children);
|
|
535
|
+
|
|
536
|
+
const {
|
|
537
|
+
result,
|
|
538
|
+
waitFor
|
|
539
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataQuery.useDataQuery)(query, {
|
|
540
|
+
lazy: true
|
|
541
|
+
}), {
|
|
542
|
+
wrapper
|
|
543
|
+
});
|
|
544
|
+
expect(spy).not.toHaveBeenCalled();
|
|
545
|
+
(0, _reactHooks.act)(() => {
|
|
546
|
+
result.current.refetch({
|
|
547
|
+
id: '1'
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
await waitFor(() => {
|
|
551
|
+
expect(result.current).toMatchObject({
|
|
552
|
+
loading: false,
|
|
553
|
+
called: true,
|
|
554
|
+
data: {
|
|
555
|
+
x: 42
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
560
|
+
});
|
|
561
|
+
it('Should only trigger a single request when refetch is called on a lazy query with identical variables', async () => {
|
|
562
|
+
const spy = jest.fn((type, query) => {
|
|
563
|
+
if (query.id === '1') {
|
|
564
|
+
return 42;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return 0;
|
|
568
|
+
});
|
|
569
|
+
const data = {
|
|
570
|
+
answer: spy
|
|
571
|
+
};
|
|
572
|
+
const query = {
|
|
573
|
+
x: {
|
|
574
|
+
resource: 'answer',
|
|
575
|
+
id: ({
|
|
576
|
+
id
|
|
577
|
+
}) => id
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
const wrapper = ({
|
|
582
|
+
children
|
|
583
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
584
|
+
data: data
|
|
585
|
+
}, children);
|
|
586
|
+
|
|
587
|
+
const {
|
|
588
|
+
result,
|
|
589
|
+
waitFor
|
|
590
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataQuery.useDataQuery)(query, {
|
|
591
|
+
lazy: true,
|
|
592
|
+
variables: {
|
|
593
|
+
id: '1'
|
|
594
|
+
}
|
|
595
|
+
}), {
|
|
596
|
+
wrapper
|
|
597
|
+
});
|
|
598
|
+
expect(spy).not.toHaveBeenCalled();
|
|
599
|
+
(0, _reactHooks.act)(() => {
|
|
600
|
+
result.current.refetch({
|
|
601
|
+
id: '1'
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
await waitFor(() => {
|
|
605
|
+
expect(result.current).toMatchObject({
|
|
606
|
+
loading: false,
|
|
607
|
+
called: true,
|
|
608
|
+
data: {
|
|
609
|
+
x: 42
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
});
|
|
613
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
614
|
+
});
|
|
615
|
+
it('Should have a stable identity if the variables have not changed', async () => {
|
|
616
|
+
const data = {
|
|
617
|
+
answer: () => 42
|
|
618
|
+
};
|
|
619
|
+
const query = {
|
|
620
|
+
x: {
|
|
621
|
+
resource: 'answer'
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
const wrapper = ({
|
|
626
|
+
children
|
|
627
|
+
}) => /*#__PURE__*/React.createElement(_CustomDataProvider.CustomDataProvider, {
|
|
628
|
+
data: data
|
|
629
|
+
}, children);
|
|
630
|
+
|
|
631
|
+
const {
|
|
632
|
+
result,
|
|
633
|
+
waitForNextUpdate,
|
|
634
|
+
rerender
|
|
635
|
+
} = (0, _reactHooks.renderHook)(() => (0, _useDataQuery.useDataQuery)(query), {
|
|
636
|
+
wrapper
|
|
637
|
+
});
|
|
638
|
+
const firstRefetch = result.current.refetch;
|
|
639
|
+
await waitForNextUpdate();
|
|
640
|
+
(0, _reactHooks.act)(() => {
|
|
641
|
+
result.current.refetch();
|
|
642
|
+
/**
|
|
643
|
+
* FIXME: https://github.com/tannerlinsley/react-query/issues/2481
|
|
644
|
+
* This forced rerender is not necessary in the app, just when testing.
|
|
645
|
+
* It is unclear why.
|
|
646
|
+
*/
|
|
647
|
+
|
|
648
|
+
rerender();
|
|
649
|
+
});
|
|
650
|
+
await waitForNextUpdate();
|
|
651
|
+
expect(result.current.refetch).toBe(firstRefetch);
|
|
652
|
+
});
|
|
510
653
|
it('Should return stale data and set loading to true on refetch', async () => {
|
|
511
654
|
const answers = [42, 43];
|
|
512
655
|
const mockSpy = jest.fn(() => Promise.resolve(answers.shift()));
|