graphql-data-generator 0.3.0-alpha.8 → 0.3.0

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 CHANGED
@@ -1,11 +1,34 @@
1
1
  # graphql-data-generator
2
2
 
3
- A tool to generate objects and operation mocks from a GraphQL schema. Allows
4
- defining _transforms_ to simplify common variations.
3
+ graphql-data-generator is a testing utility for generating GraphQL data objects
4
+ and operation mocks from your schema. It simplifies test setup by combining
5
+ generated types, patching mechanisms, and customizable **transforms** for common
6
+ object variations. It also includes helpers for asserting mock coverage in
7
+ tests.
5
8
 
6
- ## Example
9
+ - [Example](#example-setting-up-a-builder-and-building-objects)
10
+ - [CLI options](#cli-options)
11
+ - [Patches](#patches)
12
+ - [Transforms](#transforms)
13
+ - [Testing](#testing)
14
+ - [Extra properties](#extra)
7
15
 
8
- First generate types and type lists:
16
+ ### Key Concepts
17
+
18
+ - **Patch:** Like a `DeepPartial`, but with functions and array helpers.
19
+ - **Transform:** Predefined reusable patches.
20
+ - **MockedProvider:** A helper that wraps `@apollo/client`'s `MockedProvider`
21
+ with built-in assertions and better stack traces.
22
+
23
+ ## Example: Setting up a builder and building objects
24
+
25
+ ### Step 1: Generating types
26
+
27
+ To use `graphql-data-generator` with TypeScript, you must pregenerated some a
28
+ types file. This file can optionally include your entire schema types, but at
29
+ minimal includes an index of types, inputs, and operations. You can generated
30
+ the types via the following CLI command or by plugging `@graphql-codegen` (see
31
+ docs).
9
32
 
10
33
  ```sh
11
34
  npx graphql-data-generator --schema src/graphql/schema.graphql --outfile src/util/test/types.ts
@@ -86,31 +109,19 @@ const createPost = build.CreatePost({ data: { createPost: { id: "post-id" } } })
86
109
 
87
110
  ## CLI options
88
111
 
89
- - `banner=file|copy`: Places copy at the beginning of the generated output. If a
90
- file path is detected, will use the contents of the file.
91
- - `enums=[enums|literals|none|import:*]`: Describes how enums are generated.
92
- - `enums`: Use TypeScript enum. E.g., `enum Status { Draft, Submitted }`
93
- - `literals`: Use string literals. E.g.,
94
- `type Status = "Draft" | "Submitted";`
95
- - `none`: Skip generating of enums all together.
96
- - `import:file` Import enums from the provided path. E.g.,
97
- `import { Status } from "file";`
98
- - `exports=[operations|types]`: Toggle exporting of operations and/or types.
99
- - `namingConvention=NamingConvention`: Specify a
100
- [`NamingConvention`](https://the-guild.dev/graphql/codegen/docs/config-reference/naming-convention)
101
- for generated types. Defaults to `change-case-all#pascalCase` if using the
102
- plugin, otherwise defaults to `keep`.
103
- - `notypenames`: Toggle automatic inclusion of `__typename`.
104
- - `operations=dir`: Restrict generation of operations to a specific directory.
105
- Can be used multiple times for multiple directories.
106
- - `outfile=file`: Switch output to right to `file` instead of stdout.
107
- - `scalar=Scalar:Type`: Specify the type of an individual scalar. E.g.,
108
- `type Scalar = Type;`
109
- - `scalars=file.json`: Specify multiple scalars from a json file.
110
- - `schema=file`: Specify the GraphQL schema file to use.
111
- - `typesFile=file`: Specify file generated by
112
- [`@graphql-codegen`](https://the-guild.dev/graphql/codegen) to import types
113
- from.
112
+ | Option | Value | Description |
113
+ | ------------------ | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
114
+ | `banner` | `<filepath>` or `<string>` | Places copy at the beginning of the generated output. |
115
+ | `enums` | `enums`, `literals`, `none`, or `import:<filepath>` | Controls how enums are generated. |
116
+ | `exports` | `operations` or `types` | Toggles exporting operations and/or types. |
117
+ | `namingConvention` | `NamingConvention` | Sets the [naming convention](https://the-guild.dev/graphql/codegen/docs/config-reference/naming-convention) for types. |
118
+ | `notypenames` | | Disables automatic inclusion of `__typename`. |
119
+ | `operations` | `<dir>` | Limits operation generation to a directory (repeatable). |
120
+ | `outfile` | `<file>` | Writes output to `file` instead of stdout. |
121
+ | `scalar` | `<Scalar>:<Type>` | Maps a scalar to a TypeScript type. |
122
+ | `scalars` | `<json filepath>` | Maps scalars from a JSON file. |
123
+ | `schema` | `<filepath>` | Specifies the schema file to use. |
124
+ | `typesFile` | `<filepath>` | Uses types generated by [`@graphql-codegen`](https://the-guild.dev/graphql/codegen) instead of generating them here. |
114
125
 
115
126
  ## @graphql-codegen plugin
116
127
 
@@ -158,7 +169,7 @@ file can then be consumed by a `build` script similar to the above example.
158
169
 
159
170
  A `patch` is similar to a `DeepPartial` with a few extensions. First, functions
160
171
  can be passed instead of literal properties. These functions will be invoked
161
- during instantiation and will receieve the previous host value as a property:
172
+ during instantiation and will receive the previous host value as a property:
162
173
 
163
174
  ```ts
164
175
  type Thing = { foo: string };
@@ -173,6 +184,8 @@ const patch3: ThingPatch = { foo: undefined };
173
184
  const patch4: ThingPatch = { foo: (prev: Thing) => `${prev.foo}2` };
174
185
  ```
175
186
 
187
+ ### Arrays
188
+
176
189
  `Patch` also has added semantics for arrays, including an object notation:
177
190
 
178
191
  ```ts
@@ -191,38 +204,93 @@ const patch4: ContainerPatch = { values: { length: 0 } };
191
204
  const patch5: ContainerPatch = { values: ["ok"] };
192
205
  ```
193
206
 
207
+ ### `clear`
208
+
209
+ In rare circumstances, you may want to patch a nullable array input field back
210
+ to `undefined`. Since `undefined` is purposefully ignored as a patch value and
211
+ `null` is semantically different, the `clear` value exported from
212
+ `graphql-data-generator` can be used revert the field back to `undefined`.
213
+
194
214
  ## Transforms
195
215
 
196
- `graphql-data-generator` creates objects and operations by applying **patches**
197
- in sequence. A **patch** is similar to a `DeepPartial`, but supports functions
198
- for each property and has . Transforms are a mechanism to define shorthands for
199
- common patches for particular objects or operations. There are several built in
200
- transforms:
216
+ Transforms make it easy to define reusable **patches** for objects and
217
+ operations. For example, if you frequently need to build a User with a post, or
218
+ a `CreatePost` mutation with a pre-filled author, you can encode that logic into
219
+ a transform like `withPost` or `withAuthorId`. This keeps your test setup
220
+ concise and consistent. There are several built in transforms:
201
221
 
202
222
  Objects:
203
223
 
204
224
  - `default`: A special transform that is automatically called for all
205
- instantations.
225
+ instantiations
206
226
  - `patch`: Accepts a list of patches
207
227
 
208
228
  Operations:
209
229
 
210
230
  - `patch`: Accepts a list of patches
211
- - `variables`: Accepts an operation variable patch
212
- - `data`: Accepts an operation data patch
231
+ - `variables`: Accepts an operation variable patch. Useful as an alternative to
232
+ `patch` if you don't need to specify `data`
233
+ - `data`: Accepts an operation data patch. Useful as an alternative to `patch`
234
+ if you don't need to specify `variables`
213
235
 
214
236
  When defining custom transforms, the `default` transform has special meaning: it
215
- will be automatically applied as the first aptch to all instances.
237
+ will be automatically applied as the first patch to all instances.
238
+
239
+ ## Testing
240
+
241
+ `graphql-data-generator` also provides test utilities that work seamlessly with
242
+ `@apollo/client` and `@testing-library/react`. These helpers ensure all GraphQL
243
+ requests are properly mocked and all mocks are fully consumed.
244
+
245
+ ```ts
246
+ import { MockedProvider, waitForMocks } from "graphql-data-generator";
247
+ import { render, screen } from "@testing-library/react";
248
+ import userEvent from "@testing-library/user-event";
249
+
250
+ import { build } from "util/tests/build.ts";
251
+
252
+ import Users from ".";
253
+
254
+ it("my test", async () => {
255
+ render(<Users />, {
256
+ wrapper: ({ children }) => (
257
+ <MockedProvider
258
+ mocks={[
259
+ build.users({ data: { users: [{ id: "user-0", name: "User 0" }] } }),
260
+ build.user({ variables: { id: "user-0" } }),
261
+ ]}
262
+ stack={new Error("Render").stack} // Useful if render is wrapped
263
+ >
264
+ {children}
265
+ </MockedProvider>
266
+ ),
267
+ });
268
+ await waitForMocks("users");
269
+ await userEvent.click(screen.getByText("User 0"));
270
+ });
271
+ ```
272
+
273
+ The `stack` property of `MockedProvider` will be appended to errors in which
274
+ mocks are missing, uncalled, or have mismatched variables.
275
+
276
+ When transitioning to using `graphql-data-generator`'s `MockedProvider`, it may
277
+ be helpful to disable asserting all requests are mocked. A helper,
278
+ `allowMissingMocks`, exists to disable these assertions and can be called before
279
+ any tests.
280
+
281
+ If you are using an old version of `@apollo/client`, missing refetch requests
282
+ will emit warnings instead of errors. You can use `failRefetchWarnings` to
283
+ convert these warnings to errors.
216
284
 
217
285
  ## Extra
218
286
 
219
- The `init` function supports a 6th optional generic parameter, Extra, which
287
+ The `init` function supports a 6th optional generic parameter, `Extra`, which
220
288
  allows defining extra properties for operation mocks, passable in operation
221
289
  patches. This is helpful to support extra Apollo-related properties or custom
222
290
  logic. Extra properties will always be optional in patches and the final object
223
291
  and will not be patched in but simply merged, such as by `Object.assign`.
224
292
 
225
- ### Example: Adding an extra optional property to bypass an assertion a mock is used
293
+ ### Example: Adding an extra property for your own use
226
294
 
227
295
  ```ts
228
296
  const build = init<
@@ -231,7 +299,7 @@ const build = init<
231
299
  Subscription,
232
300
  Types,
233
301
  Inputs,
234
- { optional: boolean }
302
+ { internal: boolean }
235
303
  >(
236
304
  schema,
237
305
  queries,
@@ -242,40 +310,5 @@ const build = init<
242
310
  scalars,
243
311
  )(() => ({}));
244
312
 
245
- build.CreatePost({ optional: true }).optional; // true
246
- ```
247
-
248
- ## finalizeOperation
249
-
250
- The `init`'s final parmaeter, `options`, supports a `finalizeOperation` key.
251
- This is used as final step when building an operation and acts as a generic
252
- transform on the final mock itself, which can be useful to attach spies or when
253
- building interactivity with other GQL tools.
254
-
255
- ### Exmaple: Enforcing a mock is used in Apollo & Jest
256
-
257
- ```ts
258
- const build = init<Query, Mutation, Subscription, Types, Inputs>(
259
- schema,
260
- queries,
261
- mutations,
262
- subscriptions,
263
- types,
264
- inputs,
265
- scalars,
266
- {
267
- finalizeOperation: (op) => {
268
- const fn = Object.assign(
269
- jest.fn(() => op.result),
270
- op.result,
271
- ) as typeof op["result"];
272
- op.result = fn;
273
- return op;
274
- },
275
- },
276
- )(() => ({}));
277
-
278
- const createPost = build.CreatePost();
279
- // ...
280
- expect(createPost.result).toHaveBeenCalled();
313
+ build.CreatePost({ internal: true }).internal; // true
281
314
  ```
package/esm/cli.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import "./_dnt.polyfills.js";
3
2
  import * as dntShim from "./_dnt.shims.js";
4
3
  import { readFile } from "node:fs";
5
4
  import fg from "fast-glob";
package/esm/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import "./_dnt.polyfills.js";
2
1
  export { init } from "./init.js";
3
2
  export { codegen } from "./codegen.js";
4
- export { proxy } from "./proxy.js";
3
+ export { clear, operation, proxy } from "./proxy.js";
5
4
  export { formatCode, toObject } from "./util.js";
package/esm/init.js CHANGED
@@ -1,13 +1,24 @@
1
+ import * as dntShim from "./_dnt.shims.js";
2
+ import { createRequire } from "node:module";
1
3
  import { readFileSync } from "node:fs";
2
4
  import { Kind, parse } from "graphql";
3
- import { dirname, join } from "node:path";
4
5
  import { gqlPluckFromCodeStringSync } from "@graphql-tools/graphql-tag-pluck";
5
6
  import { operation, proxy, withGetDefaultPatch } from "./proxy.js";
6
7
  import { toObject } from "./util.js";
8
+ import { dirname, resolve } from "node:path";
9
+ globalThis.require ??= createRequire(dntShim.Deno.cwd());
7
10
  const files = {};
8
- const loadFile = (path) => files[path] || (files[path] = readFileSync(path, "utf-8").replace(/#import "(.*)"/, (_, fragmentPath) => loadFile(fragmentPath.startsWith(".")
9
- ? join(dirname(path), fragmentPath)
10
- : new URL(fragmentPath, import.meta.url).href)));
11
+ const loadFile = (path) => {
12
+ if (files[path])
13
+ return files[path];
14
+ const raw = files[path] = readFileSync(path, "utf-8");
15
+ const imports = Array.from(raw.matchAll(/#import "(.*)"/gm), ([, importPath]) => loadFile(require.resolve(importPath.startsWith(".")
16
+ ? resolve(dntShim.Deno.cwd(), dirname(path), importPath)
17
+ : importPath, { paths: [dntShim.Deno.cwd()] })));
18
+ if (!imports.length)
19
+ return raw;
20
+ return [raw, ...imports].join("\n\n");
21
+ };
11
22
  const getOperationContentMap = {};
12
23
  const getOperationContent = (path, operationName) => {
13
24
  const existing = getOperationContentMap[path];
@@ -23,7 +34,7 @@ const getOperationContent = (path, operationName) => {
23
34
  const document = parse(s);
24
35
  const firstOp = document.definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
25
36
  if (!firstOp)
26
- throw new Error(`Cound not find an operation in ${path}`);
37
+ throw new Error(`Could not find an operation in ${path}`);
27
38
  return [firstOp.name?.value, document];
28
39
  }));
29
40
  }
@@ -32,7 +43,16 @@ const getOperationContent = (path, operationName) => {
32
43
  }
33
44
  return getOperationContent(path, operationName);
34
45
  };
35
- // - Types will be suffixed with their type: fooQuery or fooMutation
46
+ /**
47
+ * Initialize the data builder.
48
+ * @param schema The plain text of your schema.
49
+ * @param queries List of queries exported from generated types.
50
+ * @param mutations List of mutations exported from generated types.
51
+ * @param subscriptions List of subscriptions exported from generated types.
52
+ * @param types List of types exported from generated types.
53
+ * @param inputs List of types exported from generated types.
54
+ * @param scalars A mapping to generate scalar values. Function values will be invoked with their `__typename`.
55
+ */
36
56
  export const init = (schema, queries, mutations, subscriptions, types, inputs, scalars, options) => (fn) => {
37
57
  const doc = parse(schema);
38
58
  const build = {};
@@ -157,10 +177,13 @@ export const init = (schema, queries, mutations, subscriptions, types, inputs, s
157
177
  if (transforms[name] && "default" in transforms[name]) {
158
178
  patches = [transforms[name].default, ...patches];
159
179
  }
160
- const { request: { query: parsedQuery, ...request }, ...raw } = operation(doc.definitions, scalars, query, ...patches);
161
- const mock = toObject({
162
- request: { ...request },
163
- ...raw,
180
+ const { mock, parsedQuery } = withGetDefaultPatch((type) => transforms[type]?.default, () => {
181
+ const { request: { query: parsedQuery, ...request }, ...raw } = operation(doc.definitions, scalars, query, ...patches);
182
+ const mock = toObject({
183
+ request: { ...request },
184
+ ...raw,
185
+ });
186
+ return { mock, parsedQuery };
164
187
  });
165
188
  mock.request.query = parsedQuery;
166
189
  Error.captureStackTrace(mock, builder);
package/esm/jest.js CHANGED
@@ -1,30 +1,52 @@
1
- import "./_dnt.polyfills.js";
2
1
  import * as dntShim from "./_dnt.shims.js";
3
2
  import React, { useMemo } from "react";
4
3
  import { ApolloLink, useApolloClient, } from "@apollo/client";
5
4
  import { onError } from "@apollo/client/link/error";
6
- import { MockedProvider, MockLink, } from "@apollo/client/testing";
5
+ import { MockedProvider as ApolloMockedProvider, MockLink, } from "@apollo/client/testing";
7
6
  import { waitFor } from "@testing-library/dom";
8
7
  import { Kind, print } from "graphql";
9
8
  import { diff as jestDiff } from "jest-diff";
9
+ import "@testing-library/react/dont-cleanup-after-each";
10
+ import { cleanup } from "@testing-library/react";
10
11
  let currentSpecResult;
11
12
  jasmine.getEnv().addReporter({
12
13
  specStarted: (result) => currentSpecResult = result,
13
14
  });
15
+ let _skipCleanupAfterEach = false;
16
+ /**
17
+ * `@testing-library/react` automatically unmounts React trees that were mounted
18
+ * with render after each test, which `graphql-data-generator` hijacks to ensure
19
+ * cleanup is done after all mocks are consumed. Invoke this functions to
20
+ * disable automatic cleanup.
21
+ * @param value
22
+ */
23
+ export const skipCleanupAfterEach = (value = false) => {
24
+ _skipCleanupAfterEach = value;
25
+ };
14
26
  const afterTest = [];
15
27
  afterEach(async () => {
16
28
  const hooks = afterTest.splice(0);
17
29
  for (const hook of hooks)
18
30
  await hook();
31
+ if (!_skipCleanupAfterEach)
32
+ cleanup();
19
33
  });
20
34
  const diff = (a, b) => jestDiff(a, b, { omitAnnotationLines: true })
21
35
  ?.replace(/\w+ \{/g, "{") // Remove class names
22
36
  .replace(/\w+ \[/g, "["); // Remove array class names
37
+ const getOperationDefinition = (document) => document.definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
38
+ const getOperationType = (operation) => getOperationDefinition(operation.query)?.operation ??
39
+ "<unknown operation type>";
40
+ const getOperationName = (document) => getOperationDefinition(document)?.name?.value;
41
+ const getOperationInfo = (document) => {
42
+ const def = getOperationDefinition(document);
43
+ return {
44
+ name: def?.name?.value ?? "<unknown operation>",
45
+ operationType: def?.operation ?? "<unknown operation type>",
46
+ };
47
+ };
23
48
  const getErrorMessage = (operation, mockLink) => {
24
- const definition = operation.query.definitions[0];
25
- const operationType = definition.kind === "OperationDefinition"
26
- ? definition.operation
27
- : "<unknown operation type>";
49
+ const operationType = getOperationType(operation);
28
50
  const key = JSON.stringify({
29
51
  query: print(operation.query),
30
52
  });
@@ -79,51 +101,89 @@ const AutoWatch = ({ mocks }) => {
79
101
  client.watchQuery(mock.request);
80
102
  return null;
81
103
  };
104
+ let lastMocks = [];
105
+ // deno-lint-ignore ban-types
106
+ const getStack = (to) => {
107
+ const obj = {};
108
+ Error.captureStackTrace(obj, to);
109
+ return obj.stack;
110
+ };
111
+ const _waitForMocks = async (mocks, cause) => {
112
+ for (const mock of mocks) {
113
+ if (mock.optional || mock.error)
114
+ continue;
115
+ await waitFor(() => {
116
+ if (currentSpecResult.failedExpectations.length)
117
+ return;
118
+ if (mock.result.mock.calls.length === 0) {
119
+ const { name, operationType } = getOperationInfo(mock.request.query);
120
+ const err = new Error(`Expected to have used ${operationType} ${name}${mock.request.variables
121
+ ? ` with variables ${dntShim.Deno.inspect(mock.request.variables, {
122
+ depth: Infinity,
123
+ colors: true,
124
+ })}`
125
+ : ""}`);
126
+ if (mock.stack) {
127
+ err.stack = `${mock.stack}${cause ? `\nCaused by: ${cause}` : ""}`;
128
+ }
129
+ else if (cause)
130
+ err.stack = cause;
131
+ throw err;
132
+ }
133
+ });
134
+ }
135
+ };
136
+ /**
137
+ * Wait for mocks to have been used.
138
+ * @param mock If `undefined`, waits for all mocks. If a number, waits fort he first `mocks` mocks. If a string, waits for all mocks up until and including that mock.
139
+ * @param offset If `mocks` is a string, grabs the `offset`th mock of that name (e.g., the third `getReport` mock)
140
+ */
141
+ export const waitForMocks = async (mock = lastMocks.length, offset = 0) => {
142
+ if (typeof mock === "string") {
143
+ const matches = lastMocks.map((m, i) => [m, i])
144
+ .filter(([m]) => getOperationName(m.request.query) === mock);
145
+ if (matches.length <= offset) {
146
+ fail({
147
+ name: "Error",
148
+ message: `Expected mock ${mock} to have been mocked`,
149
+ stack: getStack(waitForMocks),
150
+ });
151
+ }
152
+ expect(matches.length).toBeGreaterThan(offset);
153
+ mock = matches[offset][1] + 1;
154
+ }
155
+ await _waitForMocks(lastMocks.slice(0, mock), getStack(waitForMocks));
156
+ };
82
157
  /**
83
158
  * A wrapper for `@apollo/client/testing`, this component will assert all
84
159
  * requests have matching mocks and all defined mocks are used unless marked
85
160
  * `optional`.
86
161
  */
87
- export const MockProvider = ({ mocks, stack: renderStack, children, link: passedLink, ...rest }) => {
162
+ export const MockedProvider = ({ mocks, stack: renderStack, children, link: passedLink, ...rest }) => {
88
163
  const observableMocks = useMemo(() => {
89
164
  const observableMocks = mocks.flatMap((m) => [
90
- {
165
+ typeof m.result === "function" && "mock" in m.result ? m : {
91
166
  ...m,
92
167
  stack: m.stack,
93
- result: Object.assign(jest.fn(() => m.result), m.result),
168
+ result: Object.assign(jest.fn((vars) => typeof m.result === "function" ? m.result(vars) : m.result), m.result),
94
169
  },
95
170
  ...(m.watch
96
171
  ? [{
97
172
  ...m,
98
173
  stack: m.stack,
99
- result: Object.assign(jest.fn(() => m.result), m.result),
174
+ result: typeof m.result === "function" && "mock" in m.result
175
+ ? m.result
176
+ : Object.assign(jest.fn((vars) => typeof m.result === "function" ? m.result(vars) : m.result), m.result),
100
177
  watch: false,
178
+ // TODO: this might be dependent on Apollo version or refetch method,
179
+ // ideally should be asserted when we can (maybe when
180
+ // _failRefetchWarnings is false?)
181
+ optional: true,
101
182
  }]
102
183
  : []),
103
184
  ]);
104
- afterTest.push(async () => {
105
- if (currentSpecResult.failedExpectations.length)
106
- return;
107
- for (const mock of observableMocks) {
108
- if (mock.optional || mock.error)
109
- continue;
110
- await waitFor(() => {
111
- if (currentSpecResult.failedExpectations.length)
112
- return;
113
- if (mock.result.mock.calls.length === 0) {
114
- const operation = mock.request.query.definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
115
- const err = new Error(`Expected to have used ${operation?.operation} ${operation?.name?.value}${mock.request.variables
116
- ? ` with variables ${dntShim.Deno.inspect(mock.request.variables, {
117
- depth: Infinity,
118
- colors: true,
119
- })}`
120
- : ""}`);
121
- err.stack = mock.stack ?? renderStack ?? err.stack;
122
- throw err;
123
- }
124
- }, { onTimeout: (e) => e });
125
- }
126
- });
185
+ lastMocks = observableMocks;
186
+ afterTest.push(() => _waitForMocks(lastMocks, renderStack));
127
187
  return observableMocks;
128
188
  }, [mocks]);
129
189
  const link = useMemo(() => {
@@ -131,14 +191,18 @@ export const MockProvider = ({ mocks, stack: renderStack, children, link: passed
131
191
  mockLink.showWarnings = false;
132
192
  const errorLoggingLink = onError(({ networkError, operation }) => {
133
193
  if (_allowMissingMocks ||
134
- !networkError?.message.includes("No more mocked responses"))
194
+ !networkError?.message?.includes("No more mocked responses"))
135
195
  return;
136
196
  const { message, stack: altStack } = getErrorMessage(operation, mockLink);
137
197
  try {
138
198
  networkError.message = message;
139
- const stack = altStack ?? renderStack;
140
- if (stack)
141
- networkError.stack = stack;
199
+ if (altStack) {
200
+ networkError.stack = renderStack
201
+ ? `${altStack}\nCaused By: ${renderStack}`
202
+ : altStack;
203
+ }
204
+ else if (renderStack)
205
+ networkError.stack = renderStack;
142
206
  fail({ name: "Error", message, stack: networkError.stack });
143
207
  }
144
208
  catch {
@@ -154,14 +218,13 @@ export const MockProvider = ({ mocks, stack: renderStack, children, link: passed
154
218
  if (_failRefetchWarnings) {
155
219
  const oldWarn = console.warn.bind(console.warn);
156
220
  console.warn = (message, operation, ...etc) => {
157
- if (message !==
158
- 'Unknown query named "%s" requested in refetchQueries in options.include array') {
221
+ if (typeof message !== "string" ||
222
+ !message.match(/Unknown query named.*refetchQueries/))
159
223
  return oldWarn(message, operation, ...etc);
160
- }
161
224
  try {
162
225
  fail({
163
226
  name: "Error",
164
- message: `Expected query ${operation} requested in refetchQueries options.include array to have bene mocked`,
227
+ message: `Expected query ${operation} requested in refetchQueries options.include array to have been mocked`,
165
228
  stack: renderStack,
166
229
  });
167
230
  }
@@ -173,7 +236,7 @@ export const MockProvider = ({ mocks, stack: renderStack, children, link: passed
173
236
  console.warn = oldWarn;
174
237
  });
175
238
  }
176
- return (React.createElement(MockedProvider, { ...rest, link: link },
239
+ return (React.createElement(ApolloMockedProvider, { ...rest, link: link },
177
240
  React.createElement(React.Fragment, null,
178
241
  React.createElement(AutoWatch, { mocks: observableMocks }),
179
242
  children)));
package/esm/plugin.cjs CHANGED
@@ -1,4 +1,4 @@
1
- import "./_dnt.polyfills.js";
1
+ "use strict";
2
2
  module.exports = {
3
3
  async plugin(schema, documents, config) {
4
4
  const { codegen } = await import("./codegen.js");