graphql-data-generator 0.4.0-alpha.6 → 0.4.0-alpha.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/README.md +28 -0
- package/esm/jest.js +45 -38
- package/package.json +1 -1
- package/script/jest.js +45 -38
- package/types/jest.d.ts +1 -1
package/README.md
CHANGED
|
@@ -279,10 +279,38 @@ be helpful to disable asserting all requests are mocked. A helper,
|
|
|
279
279
|
`allowMissingMocks`, exists to disable these assertions and can be called before
|
|
280
280
|
any tests.
|
|
281
281
|
|
|
282
|
+
### Issues
|
|
283
|
+
|
|
284
|
+
#### Refetch warnings
|
|
285
|
+
|
|
282
286
|
If you are using an old version of `@apollo/client`, missing refetch requests
|
|
283
287
|
will emit warnings instead of errors. You can use `failRefetchWarnings` to
|
|
284
288
|
convert these warnings to errors.
|
|
285
289
|
|
|
290
|
+
#### Early unmounts
|
|
291
|
+
|
|
292
|
+
`@testing-library/react` automatically registers an `afterEach` hook to clean up
|
|
293
|
+
the DOM after each test. Similarly, `graphql-data-generator` adds its own
|
|
294
|
+
`afterEach` hook to verify that all mocks are consumed by the end of the test.
|
|
295
|
+
|
|
296
|
+
This can lead to unexpected errors or noisy logs if the DOM is unmounted before
|
|
297
|
+
`graphql-data-generator` runs its checks.
|
|
298
|
+
|
|
299
|
+
To avoid this, `graphql-data-generator` disables `@testing-library/react`'s
|
|
300
|
+
cleanup by default — **but only if it is loaded first**. If you can’t guarantee
|
|
301
|
+
the load order, you should manually disable the automatic cleanup:
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import "npm:@testing-library/react/dont-cleanup-after-each";
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
If instead you want to disable `graphql-data-generator`'s cleanup behavior,
|
|
308
|
+
call:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
import { skipCleanupAfterEach } from "graphql-data-generator";
|
|
312
|
+
```
|
|
313
|
+
|
|
286
314
|
## Extra
|
|
287
315
|
|
|
288
316
|
The `init` function supports a 6th optional generic parameter, `Extra`, which
|
package/esm/jest.js
CHANGED
|
@@ -8,10 +8,20 @@ import { Kind, print } from "graphql";
|
|
|
8
8
|
import { diff as jestDiff } from "jest-diff";
|
|
9
9
|
import "@testing-library/react/dont-cleanup-after-each";
|
|
10
10
|
import { cleanup } from "@testing-library/react";
|
|
11
|
+
import { addTypenameToDocument } from "@apollo/client/utilities";
|
|
11
12
|
let currentSpecResult;
|
|
12
|
-
jasmine
|
|
13
|
+
globalThis.jasmine
|
|
14
|
+
?.getEnv()
|
|
15
|
+
.addReporter({
|
|
13
16
|
specStarted: (result) => currentSpecResult = result,
|
|
14
17
|
});
|
|
18
|
+
const alreadyFailed = () => {
|
|
19
|
+
if ((currentSpecResult?.failedExpectations.length ?? 0) > 0)
|
|
20
|
+
return true;
|
|
21
|
+
const state = expect.getState();
|
|
22
|
+
return state.assertionCalls > state.numPassingAsserts ||
|
|
23
|
+
state.suppressedErrors.length > 0;
|
|
24
|
+
};
|
|
15
25
|
let _skipCleanupAfterEach = false;
|
|
16
26
|
/**
|
|
17
27
|
* `@testing-library/react` automatically unmounts React trees that were mounted
|
|
@@ -48,7 +58,7 @@ const getOperationInfo = (document) => {
|
|
|
48
58
|
const getErrorMessage = (operation, mockLink) => {
|
|
49
59
|
const operationType = getOperationType(operation);
|
|
50
60
|
const key = JSON.stringify({
|
|
51
|
-
query: print(operation.query),
|
|
61
|
+
query: print(addTypenameToDocument(operation.query)),
|
|
52
62
|
});
|
|
53
63
|
// Bypassing private variable
|
|
54
64
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -83,7 +93,7 @@ let _failRefetchWarnings = false;
|
|
|
83
93
|
* warnings instead of being treated as standard missing mocks.
|
|
84
94
|
* This utility converts those warnings into failures and ensures watch queries
|
|
85
95
|
* are installed for queries with `watch: true`. This must be set when
|
|
86
|
-
* `
|
|
96
|
+
* `MockedProvider` is mounted.
|
|
87
97
|
*
|
|
88
98
|
* This is not required on modern version of `@apollo/client`.
|
|
89
99
|
*/
|
|
@@ -114,7 +124,7 @@ const _waitForMocks = async (mocks, { cause, timeout }) => {
|
|
|
114
124
|
continue;
|
|
115
125
|
try {
|
|
116
126
|
await waitFor(() => {
|
|
117
|
-
if (
|
|
127
|
+
if (alreadyFailed())
|
|
118
128
|
return;
|
|
119
129
|
if (mock.result.mock.calls.length === 0) {
|
|
120
130
|
throw new Error("");
|
|
@@ -134,11 +144,8 @@ const _waitForMocks = async (mocks, { cause, timeout }) => {
|
|
|
134
144
|
}
|
|
135
145
|
else if (cause)
|
|
136
146
|
err.stack = cause;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
message: err.message,
|
|
140
|
-
stack: err.stack,
|
|
141
|
-
});
|
|
147
|
+
err.stack = `${err.message}\n${err.stack?.split("\n").slice(1).join("\n")}`;
|
|
148
|
+
expect.getState().suppressedErrors.push(err);
|
|
142
149
|
}
|
|
143
150
|
}
|
|
144
151
|
};
|
|
@@ -152,11 +159,11 @@ export const waitForMocks = async (mock = lastMocks.length, { timeout, offset =
|
|
|
152
159
|
const matches = lastMocks.map((m, i) => [m, i])
|
|
153
160
|
.filter(([m]) => getOperationName(m.request.query) === mock);
|
|
154
161
|
if (matches.length <= offset) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
stack
|
|
159
|
-
|
|
162
|
+
const err = new Error(`Expected mock ${mock} to have been mocked`);
|
|
163
|
+
Error.captureStackTrace(err, waitForMocks);
|
|
164
|
+
err.stack = err.message + "\n" +
|
|
165
|
+
err.stack?.split("\n").slice(1).join("\n");
|
|
166
|
+
throw err;
|
|
160
167
|
}
|
|
161
168
|
expect(matches.length).toBeGreaterThan(offset);
|
|
162
169
|
mock = matches[offset][1] + 1;
|
|
@@ -166,6 +173,15 @@ export const waitForMocks = async (mock = lastMocks.length, { timeout, offset =
|
|
|
166
173
|
cause: getStack(waitForMocks),
|
|
167
174
|
});
|
|
168
175
|
};
|
|
176
|
+
const isDocument = (thing) => !!thing && typeof thing === "object" && "kind" in thing &&
|
|
177
|
+
thing.kind === "Document";
|
|
178
|
+
const getBareOperationName = (operation) => {
|
|
179
|
+
if (typeof operation === "string")
|
|
180
|
+
return operation;
|
|
181
|
+
if (isDocument(operation))
|
|
182
|
+
return getOperationName(operation) ?? "<unknown>";
|
|
183
|
+
return "<unknown>";
|
|
184
|
+
};
|
|
169
185
|
/**
|
|
170
186
|
* A wrapper for `@apollo/client/testing`, this component will assert all
|
|
171
187
|
* requests have matching mocks and all defined mocks are used unless marked
|
|
@@ -190,20 +206,17 @@ export const MockedProvider = ({ mocks, stack: renderStack, children, link: pass
|
|
|
190
206
|
!networkError?.message?.includes("No more mocked responses"))
|
|
191
207
|
return;
|
|
192
208
|
const { message, stack: altStack } = getErrorMessage(operation, mockLink);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
: altStack;
|
|
199
|
-
}
|
|
200
|
-
else if (renderStack)
|
|
201
|
-
networkError.stack = renderStack;
|
|
202
|
-
fail({ name: "Error", message, stack: networkError.stack });
|
|
203
|
-
}
|
|
204
|
-
catch {
|
|
205
|
-
// fail both throws and marks the test as failed in jest; we only need the latter
|
|
209
|
+
networkError.message = message;
|
|
210
|
+
if (altStack) {
|
|
211
|
+
networkError.stack = renderStack
|
|
212
|
+
? `${altStack}\nCaused By: ${renderStack}`
|
|
213
|
+
: altStack;
|
|
206
214
|
}
|
|
215
|
+
else if (renderStack)
|
|
216
|
+
networkError.stack = renderStack;
|
|
217
|
+
networkError.stack = message + "\n" +
|
|
218
|
+
networkError.stack?.split("\n").slice(1).join("\n");
|
|
219
|
+
expect.getState().suppressedErrors.push(networkError);
|
|
207
220
|
});
|
|
208
221
|
return ApolloLink.from([
|
|
209
222
|
errorLoggingLink,
|
|
@@ -215,18 +228,12 @@ export const MockedProvider = ({ mocks, stack: renderStack, children, link: pass
|
|
|
215
228
|
const oldWarn = console.warn.bind(console.warn);
|
|
216
229
|
console.warn = (message, operation, ...etc) => {
|
|
217
230
|
if (typeof message !== "string" ||
|
|
218
|
-
!message.match(/Unknown query
|
|
231
|
+
!message.match(/Unknown query.*refetchQueries/))
|
|
219
232
|
return oldWarn(message, operation, ...etc);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
stack: renderStack,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
// eat
|
|
229
|
-
}
|
|
233
|
+
const error = new Error(`Expected query ${getBareOperationName(operation)} requested in refetchQueries options.include array to have been mocked`);
|
|
234
|
+
error.stack = error.message + "\n" +
|
|
235
|
+
renderStack?.split("\n").slice(1).join("\n");
|
|
236
|
+
expect.getState().suppressedErrors.push(error);
|
|
230
237
|
};
|
|
231
238
|
afterTest.push(() => {
|
|
232
239
|
console.warn = oldWarn;
|
package/package.json
CHANGED
package/script/jest.js
CHANGED
|
@@ -34,10 +34,20 @@ const graphql_1 = require("graphql");
|
|
|
34
34
|
const jest_diff_1 = require("jest-diff");
|
|
35
35
|
require("@testing-library/react/dont-cleanup-after-each");
|
|
36
36
|
const react_2 = require("@testing-library/react");
|
|
37
|
+
const utilities_1 = require("@apollo/client/utilities");
|
|
37
38
|
let currentSpecResult;
|
|
38
|
-
jasmine
|
|
39
|
+
globalThis.jasmine
|
|
40
|
+
?.getEnv()
|
|
41
|
+
.addReporter({
|
|
39
42
|
specStarted: (result) => currentSpecResult = result,
|
|
40
43
|
});
|
|
44
|
+
const alreadyFailed = () => {
|
|
45
|
+
if ((currentSpecResult?.failedExpectations.length ?? 0) > 0)
|
|
46
|
+
return true;
|
|
47
|
+
const state = expect.getState();
|
|
48
|
+
return state.assertionCalls > state.numPassingAsserts ||
|
|
49
|
+
state.suppressedErrors.length > 0;
|
|
50
|
+
};
|
|
41
51
|
let _skipCleanupAfterEach = false;
|
|
42
52
|
/**
|
|
43
53
|
* `@testing-library/react` automatically unmounts React trees that were mounted
|
|
@@ -75,7 +85,7 @@ const getOperationInfo = (document) => {
|
|
|
75
85
|
const getErrorMessage = (operation, mockLink) => {
|
|
76
86
|
const operationType = getOperationType(operation);
|
|
77
87
|
const key = JSON.stringify({
|
|
78
|
-
query: (0, graphql_1.print)(operation.query),
|
|
88
|
+
query: (0, graphql_1.print)((0, utilities_1.addTypenameToDocument)(operation.query)),
|
|
79
89
|
});
|
|
80
90
|
// Bypassing private variable
|
|
81
91
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -110,7 +120,7 @@ let _failRefetchWarnings = false;
|
|
|
110
120
|
* warnings instead of being treated as standard missing mocks.
|
|
111
121
|
* This utility converts those warnings into failures and ensures watch queries
|
|
112
122
|
* are installed for queries with `watch: true`. This must be set when
|
|
113
|
-
* `
|
|
123
|
+
* `MockedProvider` is mounted.
|
|
114
124
|
*
|
|
115
125
|
* This is not required on modern version of `@apollo/client`.
|
|
116
126
|
*/
|
|
@@ -143,7 +153,7 @@ const _waitForMocks = async (mocks, { cause, timeout }) => {
|
|
|
143
153
|
continue;
|
|
144
154
|
try {
|
|
145
155
|
await (0, dom_1.waitFor)(() => {
|
|
146
|
-
if (
|
|
156
|
+
if (alreadyFailed())
|
|
147
157
|
return;
|
|
148
158
|
if (mock.result.mock.calls.length === 0) {
|
|
149
159
|
throw new Error("");
|
|
@@ -163,11 +173,8 @@ const _waitForMocks = async (mocks, { cause, timeout }) => {
|
|
|
163
173
|
}
|
|
164
174
|
else if (cause)
|
|
165
175
|
err.stack = cause;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
message: err.message,
|
|
169
|
-
stack: err.stack,
|
|
170
|
-
});
|
|
176
|
+
err.stack = `${err.message}\n${err.stack?.split("\n").slice(1).join("\n")}`;
|
|
177
|
+
expect.getState().suppressedErrors.push(err);
|
|
171
178
|
}
|
|
172
179
|
}
|
|
173
180
|
};
|
|
@@ -181,11 +188,11 @@ const waitForMocks = async (mock = lastMocks.length, { timeout, offset = 0 } = {
|
|
|
181
188
|
const matches = lastMocks.map((m, i) => [m, i])
|
|
182
189
|
.filter(([m]) => getOperationName(m.request.query) === mock);
|
|
183
190
|
if (matches.length <= offset) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
stack
|
|
188
|
-
|
|
191
|
+
const err = new Error(`Expected mock ${mock} to have been mocked`);
|
|
192
|
+
Error.captureStackTrace(err, exports.waitForMocks);
|
|
193
|
+
err.stack = err.message + "\n" +
|
|
194
|
+
err.stack?.split("\n").slice(1).join("\n");
|
|
195
|
+
throw err;
|
|
189
196
|
}
|
|
190
197
|
expect(matches.length).toBeGreaterThan(offset);
|
|
191
198
|
mock = matches[offset][1] + 1;
|
|
@@ -196,6 +203,15 @@ const waitForMocks = async (mock = lastMocks.length, { timeout, offset = 0 } = {
|
|
|
196
203
|
});
|
|
197
204
|
};
|
|
198
205
|
exports.waitForMocks = waitForMocks;
|
|
206
|
+
const isDocument = (thing) => !!thing && typeof thing === "object" && "kind" in thing &&
|
|
207
|
+
thing.kind === "Document";
|
|
208
|
+
const getBareOperationName = (operation) => {
|
|
209
|
+
if (typeof operation === "string")
|
|
210
|
+
return operation;
|
|
211
|
+
if (isDocument(operation))
|
|
212
|
+
return getOperationName(operation) ?? "<unknown>";
|
|
213
|
+
return "<unknown>";
|
|
214
|
+
};
|
|
199
215
|
/**
|
|
200
216
|
* A wrapper for `@apollo/client/testing`, this component will assert all
|
|
201
217
|
* requests have matching mocks and all defined mocks are used unless marked
|
|
@@ -220,20 +236,17 @@ const MockedProvider = ({ mocks, stack: renderStack, children, link: passedLink,
|
|
|
220
236
|
!networkError?.message?.includes("No more mocked responses"))
|
|
221
237
|
return;
|
|
222
238
|
const { message, stack: altStack } = getErrorMessage(operation, mockLink);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
: altStack;
|
|
229
|
-
}
|
|
230
|
-
else if (renderStack)
|
|
231
|
-
networkError.stack = renderStack;
|
|
232
|
-
fail({ name: "Error", message, stack: networkError.stack });
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
// fail both throws and marks the test as failed in jest; we only need the latter
|
|
239
|
+
networkError.message = message;
|
|
240
|
+
if (altStack) {
|
|
241
|
+
networkError.stack = renderStack
|
|
242
|
+
? `${altStack}\nCaused By: ${renderStack}`
|
|
243
|
+
: altStack;
|
|
236
244
|
}
|
|
245
|
+
else if (renderStack)
|
|
246
|
+
networkError.stack = renderStack;
|
|
247
|
+
networkError.stack = message + "\n" +
|
|
248
|
+
networkError.stack?.split("\n").slice(1).join("\n");
|
|
249
|
+
expect.getState().suppressedErrors.push(networkError);
|
|
237
250
|
});
|
|
238
251
|
return client_1.ApolloLink.from([
|
|
239
252
|
errorLoggingLink,
|
|
@@ -245,18 +258,12 @@ const MockedProvider = ({ mocks, stack: renderStack, children, link: passedLink,
|
|
|
245
258
|
const oldWarn = console.warn.bind(console.warn);
|
|
246
259
|
console.warn = (message, operation, ...etc) => {
|
|
247
260
|
if (typeof message !== "string" ||
|
|
248
|
-
!message.match(/Unknown query
|
|
261
|
+
!message.match(/Unknown query.*refetchQueries/))
|
|
249
262
|
return oldWarn(message, operation, ...etc);
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
stack: renderStack,
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
catch {
|
|
258
|
-
// eat
|
|
259
|
-
}
|
|
263
|
+
const error = new Error(`Expected query ${getBareOperationName(operation)} requested in refetchQueries options.include array to have been mocked`);
|
|
264
|
+
error.stack = error.message + "\n" +
|
|
265
|
+
renderStack?.split("\n").slice(1).join("\n");
|
|
266
|
+
expect.getState().suppressedErrors.push(error);
|
|
260
267
|
};
|
|
261
268
|
afterTest.push(() => {
|
|
262
269
|
console.warn = oldWarn;
|
package/types/jest.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const skipCleanupAfterEach: (value?: boolean) => void;
|
|
|
19
19
|
* warnings instead of being treated as standard missing mocks.
|
|
20
20
|
* This utility converts those warnings into failures and ensures watch queries
|
|
21
21
|
* are installed for queries with `watch: true`. This must be set when
|
|
22
|
-
* `
|
|
22
|
+
* `MockedProvider` is mounted.
|
|
23
23
|
*
|
|
24
24
|
* This is not required on modern version of `@apollo/client`.
|
|
25
25
|
*/
|