@graphql-tools/mock 8.6.13 → 8.7.0-alpha-6c480b2d.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/index.js DELETED
@@ -1,925 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- const graphql = require('graphql');
8
- const stringify = _interopDefault(require('fast-json-stable-stringify'));
9
- const utils = require('@graphql-tools/utils');
10
- const schema = require('@graphql-tools/schema');
11
-
12
- function isRef(maybeRef) {
13
- return !!(maybeRef && typeof maybeRef === 'object' && '$ref' in maybeRef);
14
- }
15
- function assertIsRef(maybeRef, message) {
16
- if (!isRef(maybeRef)) {
17
- throw new Error(message || `Expected ${maybeRef} to be a valid Ref.`);
18
- }
19
- }
20
- function isRecord(obj) {
21
- return typeof obj === 'object' && obj !== null;
22
- }
23
-
24
- function uuidv4() {
25
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
26
- const r = (Math.random() * 16) | 0;
27
- // eslint-disable-next-line eqeqeq
28
- const v = c == 'x' ? r : (r & 0x3) | 0x8;
29
- return v.toString(16);
30
- });
31
- }
32
- const randomListLength = () => {
33
- // Mocking has always returned list of length 2 by default
34
- // return 1 + Math.round(Math.random() * 10)
35
- return 2;
36
- };
37
- const takeRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
38
- function makeRef(typeName, key) {
39
- return { $ref: { key, typeName } };
40
- }
41
- function isObject(thing) {
42
- return thing === Object(thing) && !Array.isArray(thing);
43
- }
44
- function copyOwnPropsIfNotPresent(target, source) {
45
- for (const prop of Object.getOwnPropertyNames(source)) {
46
- if (!Object.getOwnPropertyDescriptor(target, prop)) {
47
- const propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
48
- Object.defineProperty(target, prop, propertyDescriptor == null ? {} : propertyDescriptor);
49
- }
50
- }
51
- }
52
- function copyOwnProps(target, ...sources) {
53
- for (const source of sources) {
54
- let chain = source;
55
- while (chain != null) {
56
- copyOwnPropsIfNotPresent(target, chain);
57
- chain = Object.getPrototypeOf(chain);
58
- }
59
- }
60
- return target;
61
- }
62
- const isRootType = (type, schema) => {
63
- const rootTypeNames = utils.getRootTypeNames(schema);
64
- return rootTypeNames.has(type.name);
65
- };
66
-
67
- /**
68
- * @internal
69
- */
70
- function isMockList(obj) {
71
- if (typeof (obj === null || obj === void 0 ? void 0 : obj.len) === 'number' || (Array.isArray(obj === null || obj === void 0 ? void 0 : obj.len) && typeof (obj === null || obj === void 0 ? void 0 : obj.len[0]) === 'number')) {
72
- if (typeof obj.wrappedFunction === 'undefined' || typeof obj.wrappedFunction === 'function') {
73
- return true;
74
- }
75
- }
76
- return false;
77
- }
78
- /**
79
- * This is an object you can return from your mock resolvers which calls the
80
- * provided `mockFunction` once for each list item.
81
- */
82
- class MockList {
83
- /**
84
- * @param length Either the exact length of items to return or an inclusive
85
- * range of possible lengths.
86
- * @param mockFunction The function to call for each item in the list to
87
- * resolve it. It can return another MockList or a value.
88
- */
89
- constructor(length, mockFunction) {
90
- this.len = length;
91
- if (typeof mockFunction !== 'undefined') {
92
- if (typeof mockFunction !== 'function') {
93
- throw new Error('Second argument to MockList must be a function or undefined');
94
- }
95
- this.wrappedFunction = mockFunction;
96
- }
97
- }
98
- /**
99
- * @internal
100
- */
101
- mock() {
102
- let arr;
103
- if (Array.isArray(this.len)) {
104
- arr = new Array(this.randint(this.len[0], this.len[1]));
105
- }
106
- else {
107
- arr = new Array(this.len);
108
- }
109
- for (let i = 0; i < arr.length; i++) {
110
- if (typeof this.wrappedFunction === 'function') {
111
- const res = this.wrappedFunction();
112
- if (isMockList(res)) {
113
- arr[i] = res.mock();
114
- }
115
- else {
116
- arr[i] = res;
117
- }
118
- }
119
- else {
120
- arr[i] = undefined;
121
- }
122
- }
123
- return arr;
124
- }
125
- randint(low, high) {
126
- return Math.floor(Math.random() * (high - low + 1) + low);
127
- }
128
- }
129
- function deepResolveMockList(mockList) {
130
- return mockList.mock().map(v => {
131
- if (isMockList(v))
132
- return deepResolveMockList(v);
133
- return v;
134
- });
135
- }
136
-
137
- const defaultMocks = {
138
- Int: () => Math.round(Math.random() * 200) - 100,
139
- Float: () => Math.random() * 200 - 100,
140
- String: () => 'Hello World',
141
- Boolean: () => Math.random() > 0.5,
142
- ID: () => uuidv4(),
143
- };
144
- const defaultKeyFieldNames = ['id', '_id'];
145
- class MockStore {
146
- constructor({ schema, mocks, typePolicies, }) {
147
- this.store = {};
148
- this.schema = schema;
149
- this.mocks = { ...defaultMocks, ...mocks };
150
- this.typePolicies = typePolicies || {};
151
- }
152
- has(typeName, key) {
153
- return !!this.store[typeName] && !!this.store[typeName][key];
154
- }
155
- get(_typeName, _key, _fieldName, _fieldArgs) {
156
- if (typeof _typeName !== 'string') {
157
- if (_key === undefined) {
158
- if (isRef(_typeName)) {
159
- throw new Error("Can't provide a ref as first argument and no other argument");
160
- }
161
- // get({...})
162
- return this.getImpl(_typeName);
163
- }
164
- else {
165
- assertIsRef(_typeName);
166
- const { $ref } = _typeName;
167
- // arguments shift
168
- _fieldArgs = _fieldName;
169
- _fieldName = _key;
170
- _key = $ref.key;
171
- _typeName = $ref.typeName;
172
- }
173
- }
174
- const args = {
175
- typeName: _typeName,
176
- };
177
- if (isRecord(_key) || _key === undefined) {
178
- // get('User', { name: 'Alex'})
179
- args.defaultValue = _key;
180
- return this.getImpl(args);
181
- }
182
- args.key = _key;
183
- if (Array.isArray(_fieldName) && _fieldName.length === 1) {
184
- _fieldName = _fieldName[0];
185
- }
186
- if (typeof _fieldName !== 'string' && !Array.isArray(_fieldName)) {
187
- // get('User', 'me', { name: 'Alex'})
188
- args.defaultValue = _fieldName;
189
- return this.getImpl(args);
190
- }
191
- if (Array.isArray(_fieldName)) {
192
- // get('User', 'me', ['father', 'name'])
193
- const ref = this.get(_typeName, _key, _fieldName[0], _fieldArgs);
194
- assertIsRef(ref);
195
- return this.get(ref.$ref.typeName, ref.$ref.key, _fieldName.slice(1, _fieldName.length));
196
- }
197
- // get('User', 'me', 'name'...);
198
- args.fieldName = _fieldName;
199
- args.fieldArgs = _fieldArgs;
200
- return this.getImpl(args);
201
- }
202
- set(_typeName, _key, _fieldName, _value) {
203
- if (typeof _typeName !== 'string') {
204
- if (_key === undefined) {
205
- if (isRef(_typeName)) {
206
- throw new Error("Can't provide a ref as first argument and no other argument");
207
- }
208
- // set({...})
209
- return this.setImpl(_typeName);
210
- }
211
- else {
212
- assertIsRef(_typeName);
213
- const { $ref } = _typeName;
214
- // arguments shift
215
- _value = _fieldName;
216
- _fieldName = _key;
217
- _key = $ref.key;
218
- _typeName = $ref.typeName;
219
- }
220
- }
221
- assertIsDefined(_key, 'key was not provided');
222
- const args = {
223
- typeName: _typeName,
224
- key: _key,
225
- };
226
- if (typeof _fieldName !== 'string') {
227
- // set('User', 1, { name: 'Foo' })
228
- if (!isRecord(_fieldName))
229
- throw new Error('Expected value to be a record');
230
- args.value = _fieldName;
231
- return this.setImpl(args);
232
- }
233
- args.fieldName = _fieldName;
234
- args.value = _value;
235
- return this.setImpl(args);
236
- }
237
- reset() {
238
- this.store = {};
239
- }
240
- filter(key, predicate) {
241
- const entity = this.store[key];
242
- return Object.values(entity).filter(predicate);
243
- }
244
- find(key, predicate) {
245
- const entity = this.store[key];
246
- return Object.values(entity).find(predicate);
247
- }
248
- getImpl(args) {
249
- const { typeName, key, fieldName, fieldArgs, defaultValue } = args;
250
- if (!fieldName) {
251
- if (defaultValue !== undefined && !isRecord(defaultValue)) {
252
- throw new Error('`defaultValue` should be an object');
253
- }
254
- let valuesToInsert = defaultValue || {};
255
- if (key) {
256
- valuesToInsert = { ...valuesToInsert, ...makeRef(typeName, key) };
257
- }
258
- return this.insert(typeName, valuesToInsert, true);
259
- }
260
- assertIsDefined(key, 'key argument should be given when fieldName is given');
261
- const fieldNameInStore = getFieldNameInStore(fieldName, fieldArgs);
262
- if (this.store[typeName] === undefined ||
263
- this.store[typeName][key] === undefined ||
264
- this.store[typeName][key][fieldNameInStore] === undefined) {
265
- let value;
266
- if (defaultValue !== undefined) {
267
- value = defaultValue;
268
- }
269
- else if (this.isKeyField(typeName, fieldName)) {
270
- value = key;
271
- }
272
- else {
273
- value = this.generateFieldValue(typeName, fieldName, (otherFieldName, otherValue) => {
274
- // if we get a key field in the mix we don't care
275
- if (this.isKeyField(typeName, otherFieldName))
276
- return;
277
- this.set({ typeName, key, fieldName: otherFieldName, value: otherValue, noOverride: true });
278
- });
279
- }
280
- this.set({ typeName, key, fieldName, fieldArgs, value, noOverride: true });
281
- }
282
- return this.store[typeName][key][fieldNameInStore];
283
- }
284
- setImpl(args) {
285
- const { typeName, key, fieldName, fieldArgs, noOverride } = args;
286
- let { value } = args;
287
- if (isMockList(value)) {
288
- value = deepResolveMockList(value);
289
- }
290
- if (this.store[typeName] === undefined) {
291
- this.store[typeName] = {};
292
- }
293
- if (this.store[typeName][key] === undefined) {
294
- this.store[typeName][key] = {};
295
- }
296
- if (!fieldName) {
297
- if (!isRecord(value)) {
298
- throw new Error('When no `fieldName` is provided, `value` should be a record.');
299
- }
300
- for (const fieldName in value) {
301
- this.setImpl({
302
- typeName,
303
- key,
304
- fieldName,
305
- value: value[fieldName],
306
- noOverride,
307
- });
308
- }
309
- return;
310
- }
311
- const fieldNameInStore = getFieldNameInStore(fieldName, fieldArgs);
312
- if (this.isKeyField(typeName, fieldName) && value !== key) {
313
- throw new Error(`Field ${fieldName} is a key field of ${typeName} and you are trying to set it to ${value} while the key is ${key}`);
314
- }
315
- // if already set and we don't override
316
- if (this.store[typeName][key][fieldNameInStore] !== undefined && noOverride) {
317
- return;
318
- }
319
- const fieldType = this.getFieldType(typeName, fieldName);
320
- const currentValue = this.store[typeName][key][fieldNameInStore];
321
- let valueToStore;
322
- try {
323
- valueToStore = this.normalizeValueToStore(fieldType, value, currentValue, (typeName, values) => this.insert(typeName, values, noOverride));
324
- }
325
- catch (e) {
326
- throw new Error(`Value to set in ${typeName}.${fieldName} in not normalizable: ${e.message}`);
327
- }
328
- this.store[typeName][key] = {
329
- ...this.store[typeName][key],
330
- [fieldNameInStore]: valueToStore,
331
- };
332
- }
333
- normalizeValueToStore(fieldType, value, currentValue, onInsertType) {
334
- const fieldTypeName = fieldType.toString();
335
- if (value === null) {
336
- if (!graphql.isNullableType(fieldType)) {
337
- throw new Error(`should not be null because ${fieldTypeName} is not nullable. Received null.`);
338
- }
339
- return null;
340
- }
341
- const nullableFieldType = graphql.getNullableType(fieldType);
342
- if (value === undefined)
343
- return this.generateValueFromType(nullableFieldType);
344
- // deal with nesting insert
345
- if (graphql.isCompositeType(nullableFieldType)) {
346
- if (!isRecord(value))
347
- throw new Error(`should be an object or null or undefined. Received ${value}`);
348
- let joinedTypeName;
349
- if (graphql.isAbstractType(nullableFieldType)) {
350
- if (isRef(value)) {
351
- joinedTypeName = value.$ref.typeName;
352
- }
353
- else {
354
- if (typeof value['__typename'] !== 'string') {
355
- throw new Error(`should contain a '__typename' because ${nullableFieldType.name} an abstract type`);
356
- }
357
- joinedTypeName = value['__typename'];
358
- }
359
- }
360
- else {
361
- joinedTypeName = nullableFieldType.name;
362
- }
363
- return onInsertType(joinedTypeName, isRef(currentValue) ? { ...currentValue, ...value } : value);
364
- }
365
- if (graphql.isListType(nullableFieldType)) {
366
- if (!Array.isArray(value))
367
- throw new Error(`should be an array or null or undefined. Received ${value}`);
368
- return value.map((v, index) => {
369
- return this.normalizeValueToStore(nullableFieldType.ofType, v, typeof currentValue === 'object' && currentValue != null && currentValue[index] ? currentValue : undefined, onInsertType);
370
- });
371
- }
372
- return value;
373
- }
374
- insert(typeName, values, noOverride) {
375
- const keyFieldName = this.getKeyFieldName(typeName);
376
- let key;
377
- // when we generate a key for the type, we might produce
378
- // other associated values with it
379
- // We keep track of them and we'll insert them, with propririty
380
- // for the ones that we areasked to insert
381
- const otherValues = {};
382
- if (isRef(values)) {
383
- key = values.$ref.key;
384
- }
385
- else if (keyFieldName && keyFieldName in values) {
386
- key = values[keyFieldName];
387
- }
388
- else {
389
- key = this.generateKeyForType(typeName, (otherFieldName, otherFieldValue) => {
390
- otherValues[otherFieldName] = otherFieldValue;
391
- });
392
- }
393
- const toInsert = { ...otherValues, ...values };
394
- for (const fieldName in toInsert) {
395
- if (fieldName === '$ref')
396
- continue;
397
- if (fieldName === '__typename')
398
- continue;
399
- this.set({
400
- typeName,
401
- key,
402
- fieldName,
403
- value: toInsert[fieldName],
404
- noOverride,
405
- });
406
- }
407
- if (this.store[typeName] === undefined) {
408
- this.store[typeName] = {};
409
- }
410
- if (this.store[typeName][key] === undefined) {
411
- this.store[typeName][key] = {};
412
- }
413
- return makeRef(typeName, key);
414
- }
415
- generateFieldValue(typeName, fieldName, onOtherFieldsGenerated) {
416
- const mockedValue = this.generateFieldValueFromMocks(typeName, fieldName, onOtherFieldsGenerated);
417
- if (mockedValue !== undefined)
418
- return mockedValue;
419
- const fieldType = this.getFieldType(typeName, fieldName);
420
- return this.generateValueFromType(fieldType);
421
- }
422
- generateFieldValueFromMocks(typeName, fieldName, onOtherFieldsGenerated) {
423
- let value;
424
- const mock = this.mocks ? this.mocks[typeName] : undefined;
425
- if (mock) {
426
- if (typeof mock === 'function') {
427
- const values = mock();
428
- if (typeof values !== 'object' || values == null) {
429
- throw new Error(`Value returned by the mock for ${typeName} is not an object`);
430
- }
431
- for (const otherFieldName in values) {
432
- if (otherFieldName === fieldName)
433
- continue;
434
- if (typeof values[otherFieldName] === 'function')
435
- continue;
436
- onOtherFieldsGenerated && onOtherFieldsGenerated(otherFieldName, values[otherFieldName]);
437
- }
438
- value = values[fieldName];
439
- if (typeof value === 'function')
440
- value = value();
441
- }
442
- else if (typeof mock === 'object' && mock != null && typeof mock[fieldName] === 'function') {
443
- value = mock[fieldName]();
444
- }
445
- }
446
- if (value !== undefined)
447
- return value;
448
- const type = this.getType(typeName);
449
- // GraphQL 14 Compatibility
450
- const interfaces = 'getInterfaces' in type ? type.getInterfaces() : [];
451
- if (interfaces.length > 0) {
452
- for (const interface_ of interfaces) {
453
- if (value)
454
- break;
455
- value = this.generateFieldValueFromMocks(interface_.name, fieldName, onOtherFieldsGenerated);
456
- }
457
- }
458
- return value;
459
- }
460
- generateKeyForType(typeName, onOtherFieldsGenerated) {
461
- const keyFieldName = this.getKeyFieldName(typeName);
462
- if (!keyFieldName)
463
- return uuidv4();
464
- return this.generateFieldValue(typeName, keyFieldName, onOtherFieldsGenerated);
465
- }
466
- generateValueFromType(fieldType) {
467
- const nullableType = graphql.getNullableType(fieldType);
468
- if (graphql.isScalarType(nullableType)) {
469
- const mockFn = this.mocks[nullableType.name];
470
- if (typeof mockFn !== 'function')
471
- throw new Error(`No mock defined for type "${nullableType.name}"`);
472
- return mockFn();
473
- }
474
- else if (graphql.isEnumType(nullableType)) {
475
- const mockFn = this.mocks[nullableType.name];
476
- if (typeof mockFn === 'function')
477
- return mockFn();
478
- const values = nullableType.getValues().map(v => v.value);
479
- return takeRandom(values);
480
- }
481
- else if (graphql.isObjectType(nullableType)) {
482
- // this will create a new random ref
483
- return this.insert(nullableType.name, {});
484
- }
485
- else if (graphql.isListType(nullableType)) {
486
- return [...new Array(randomListLength())].map(() => this.generateValueFromType(nullableType.ofType));
487
- }
488
- else if (graphql.isAbstractType(nullableType)) {
489
- const mock = this.mocks[nullableType.name];
490
- let typeName;
491
- let values = {};
492
- if (!mock) {
493
- typeName = takeRandom(this.schema.getPossibleTypes(nullableType).map(t => t.name));
494
- }
495
- else if (typeof mock === 'function') {
496
- const mockRes = mock();
497
- if (mockRes === null)
498
- return null;
499
- if (!isRecord(mockRes)) {
500
- throw new Error(`Value returned by the mock for ${nullableType.name} is not an object or null`);
501
- }
502
- values = mockRes;
503
- if (typeof values['__typename'] !== 'string') {
504
- throw new Error(`Please return a __typename in "${nullableType.name}"`);
505
- }
506
- typeName = values['__typename'];
507
- }
508
- else if (typeof mock === 'object' && mock != null && typeof mock['__typename'] === 'function') {
509
- const mockRes = mock['__typename']();
510
- if (typeof mockRes !== 'string')
511
- throw new Error(`'__typename' returned by the mock for abstract type ${nullableType.name} is not a string`);
512
- typeName = mockRes;
513
- }
514
- else {
515
- throw new Error(`Please return a __typename in "${nullableType.name}"`);
516
- }
517
- const toInsert = {};
518
- for (const fieldName in values) {
519
- if (fieldName === '__typename')
520
- continue;
521
- const fieldValue = values[fieldName];
522
- toInsert[fieldName] = typeof fieldValue === 'function' ? fieldValue() : fieldValue;
523
- }
524
- return this.insert(typeName, toInsert);
525
- }
526
- else {
527
- throw new Error(`${nullableType} not implemented`);
528
- }
529
- }
530
- getFieldType(typeName, fieldName) {
531
- if (fieldName === '__typename') {
532
- return graphql.GraphQLString;
533
- }
534
- const type = this.getType(typeName);
535
- const field = type.getFields()[fieldName];
536
- if (!field) {
537
- throw new Error(`${fieldName} does not exist on type ${typeName}`);
538
- }
539
- return field.type;
540
- }
541
- getType(typeName) {
542
- const type = this.schema.getType(typeName);
543
- if (!type || !(graphql.isObjectType(type) || graphql.isInterfaceType(type))) {
544
- throw new Error(`${typeName} does not exist on schema or is not an object or interface`);
545
- }
546
- return type;
547
- }
548
- isKeyField(typeName, fieldName) {
549
- return this.getKeyFieldName(typeName) === fieldName;
550
- }
551
- getKeyFieldName(typeName) {
552
- var _a;
553
- const typePolicyKeyField = (_a = this.typePolicies[typeName]) === null || _a === void 0 ? void 0 : _a.keyFieldName;
554
- if (typePolicyKeyField !== undefined) {
555
- if (typePolicyKeyField === false)
556
- return null;
557
- return typePolicyKeyField;
558
- }
559
- // How about common key field names?
560
- const gqlType = this.getType(typeName);
561
- for (const fieldName in gqlType.getFields()) {
562
- if (defaultKeyFieldNames.includes(fieldName)) {
563
- return fieldName;
564
- }
565
- }
566
- return null;
567
- }
568
- }
569
- const getFieldNameInStore = (fieldName, fieldArgs) => {
570
- if (!fieldArgs)
571
- return fieldName;
572
- if (typeof fieldArgs === 'string') {
573
- return `${fieldName}:${fieldArgs}`;
574
- }
575
- // empty args
576
- if (Object.keys(fieldArgs).length === 0) {
577
- return fieldName;
578
- }
579
- return `${fieldName}:${stringify(fieldArgs)}`;
580
- };
581
- function assertIsDefined(value, message) {
582
- if (value !== undefined && value !== null) {
583
- return;
584
- }
585
- throw new Error(process.env['NODE_ENV'] === 'production' ? 'Invariant failed:' : `Invariant failed: ${message || ''}`);
586
- }
587
- /**
588
- * Will create `MockStore` for the given `schema`.
589
- *
590
- * A `MockStore` will generate mock values for the given schem when queried.
591
- *
592
- * It will stores generated mocks, so that, provided with same arguments
593
- * the returned values will be the same.
594
- *
595
- * Its API also allows to modify the stored values.
596
- *
597
- * Basic example:
598
- * ```ts
599
- * store.get('User', 1, 'name');
600
- * // > "Hello World"
601
- * store.set('User', 1, 'name', 'Alexandre');
602
- * store.get('User', 1, 'name');
603
- * // > "Alexandre"
604
- * ```
605
- *
606
- * The storage key will correspond to the "key field"
607
- * of the type. Field with name `id` or `_id` will be
608
- * by default considered as the key field for the type.
609
- * However, use `typePolicies` to precise the field to use
610
- * as key.
611
- */
612
- function createMockStore(options) {
613
- return new MockStore(options);
614
- }
615
-
616
- // todo: add option to preserve resolver
617
- /**
618
- * Given a `schema` and a `MockStore`, returns an executable schema that
619
- * will use the provided `MockStore` to execute queries.
620
- *
621
- * ```ts
622
- * const schema = buildSchema(`
623
- * type User {
624
- * id: ID!
625
- * name: String!
626
- * }
627
- * type Query {
628
- * me: User!
629
- * }
630
- * `)
631
- *
632
- * const store = createMockStore({ schema });
633
- * const mockedSchema = addMocksToSchema({ schema, store });
634
- * ```
635
- *
636
- *
637
- * If a `resolvers` parameter is passed, the query execution will use
638
- * the provided `resolvers` if, one exists, instead of the default mock
639
- * resolver.
640
- *
641
- *
642
- * ```ts
643
- * const schema = buildSchema(`
644
- * type User {
645
- * id: ID!
646
- * name: String!
647
- * }
648
- * type Query {
649
- * me: User!
650
- * }
651
- * type Mutation {
652
- * setMyName(newName: String!): User!
653
- * }
654
- * `)
655
- *
656
- * const store = createMockStore({ schema });
657
- * const mockedSchema = addMocksToSchema({
658
- * schema,
659
- * store,
660
- * resolvers: {
661
- * Mutation: {
662
- * setMyName: (_, { newName }) => {
663
- * const ref = store.get('Query', 'ROOT', 'viewer');
664
- * store.set(ref, 'name', newName);
665
- * return ref;
666
- * }
667
- * }
668
- * }
669
- * });
670
- * ```
671
- *
672
- *
673
- * `Query` and `Mutation` type will use `key` `'ROOT'`.
674
- */
675
- function addMocksToSchema({ schema: schema$1, store: maybeStore, mocks, typePolicies, resolvers: resolversOrFnResolvers, preserveResolvers = false, }) {
676
- if (!schema$1) {
677
- throw new Error('Must provide schema to mock');
678
- }
679
- if (!graphql.isSchema(schema$1)) {
680
- throw new Error('Value at "schema" must be of type GraphQLSchema');
681
- }
682
- if (mocks && !isObject(mocks)) {
683
- throw new Error('mocks must be of type Object');
684
- }
685
- const store = maybeStore ||
686
- createMockStore({
687
- schema: schema$1,
688
- mocks,
689
- typePolicies,
690
- });
691
- const resolvers = typeof resolversOrFnResolvers === 'function'
692
- ? resolversOrFnResolvers(store)
693
- : resolversOrFnResolvers;
694
- const mockResolver = (source, args, contex, info) => {
695
- const defaultResolvedValue = graphql.defaultFieldResolver(source, args, contex, info);
696
- // priority to default resolved value
697
- if (defaultResolvedValue !== undefined)
698
- return defaultResolvedValue;
699
- if (isRef(source)) {
700
- return store.get({
701
- typeName: source.$ref.typeName,
702
- key: source.$ref.key,
703
- fieldName: info.fieldName,
704
- fieldArgs: args,
705
- });
706
- }
707
- // we have to handle the root mutation, root query and root subscription types
708
- // differently, because no resolver is called at the root
709
- if (isRootType(info.parentType, info.schema)) {
710
- return store.get({
711
- typeName: info.parentType.name,
712
- key: 'ROOT',
713
- fieldName: info.fieldName,
714
- fieldArgs: args,
715
- });
716
- }
717
- if (defaultResolvedValue === undefined) {
718
- // any is used here because generateFieldValue is a private method at time of writing
719
- return store.generateFieldValue(info.parentType.name, info.fieldName);
720
- }
721
- return undefined;
722
- };
723
- const typeResolver = data => {
724
- if (isRef(data)) {
725
- return data.$ref.typeName;
726
- }
727
- };
728
- const mockSubscriber = () => ({
729
- [Symbol.asyncIterator]() {
730
- return {
731
- async next() {
732
- return {
733
- done: true,
734
- value: {},
735
- };
736
- },
737
- };
738
- },
739
- });
740
- const schemaWithMocks = utils.mapSchema(schema$1, {
741
- [utils.MapperKind.OBJECT_FIELD]: fieldConfig => {
742
- const newFieldConfig = {
743
- ...fieldConfig,
744
- };
745
- const oldResolver = fieldConfig.resolve;
746
- if (!preserveResolvers || !oldResolver) {
747
- newFieldConfig.resolve = mockResolver;
748
- }
749
- else {
750
- newFieldConfig.resolve = async (rootObject, args, context, info) => {
751
- const [mockedValue, resolvedValue] = await Promise.all([
752
- mockResolver(rootObject, args, context, info),
753
- oldResolver(rootObject, args, context, info),
754
- ]);
755
- // In case we couldn't mock
756
- if (mockedValue instanceof Error) {
757
- // only if value was not resolved, populate the error.
758
- if (undefined === resolvedValue) {
759
- throw mockedValue;
760
- }
761
- return resolvedValue;
762
- }
763
- if (resolvedValue instanceof Date && mockedValue instanceof Date) {
764
- return undefined !== resolvedValue ? resolvedValue : mockedValue;
765
- }
766
- if (isObject(mockedValue) && isObject(resolvedValue)) {
767
- // Object.assign() won't do here, as we need to all properties, including
768
- // the non-enumerable ones and defined using Object.defineProperty
769
- const emptyObject = Object.create(Object.getPrototypeOf(resolvedValue));
770
- return copyOwnProps(emptyObject, resolvedValue, mockedValue);
771
- }
772
- return undefined !== resolvedValue ? resolvedValue : mockedValue;
773
- };
774
- }
775
- const fieldSubscriber = fieldConfig.subscribe;
776
- if (!preserveResolvers || !fieldSubscriber) {
777
- newFieldConfig.subscribe = mockSubscriber;
778
- }
779
- else {
780
- newFieldConfig.subscribe = async (rootObject, args, context, info) => {
781
- const [mockAsyncIterable, oldAsyncIterable] = await Promise.all([
782
- mockSubscriber(),
783
- fieldSubscriber(rootObject, args, context, info),
784
- ]);
785
- return oldAsyncIterable || mockAsyncIterable;
786
- };
787
- }
788
- return newFieldConfig;
789
- },
790
- [utils.MapperKind.ABSTRACT_TYPE]: type => {
791
- if (preserveResolvers && type.resolveType != null && type.resolveType.length) {
792
- return;
793
- }
794
- if (graphql.isUnionType(type)) {
795
- return new graphql.GraphQLUnionType({
796
- ...type.toConfig(),
797
- resolveType: typeResolver,
798
- });
799
- }
800
- else {
801
- return new graphql.GraphQLInterfaceType({
802
- ...type.toConfig(),
803
- resolveType: typeResolver,
804
- });
805
- }
806
- },
807
- });
808
- return resolvers ? schema.addResolversToSchema(schemaWithMocks, resolvers) : schemaWithMocks;
809
- }
810
-
811
- /**
812
- * A convenience wrapper on top of addMocksToSchema. It adds your mock resolvers
813
- * to your schema and returns a client that will correctly execute your query with
814
- * variables. Note: when executing queries from the returned server, context and
815
- * root will both equal `{}`.
816
- * @param schema The schema to which to add mocks. This can also be a set of type
817
- * definitions instead.
818
- * @param mocks The mocks to add to the schema.
819
- * @param preserveResolvers Set to `true` to prevent existing resolvers from being
820
- * overwritten to provide mock data. This can be used to mock some parts of the
821
- * server and not others.
822
- */
823
- function mockServer(schema$1, mocks, preserveResolvers = false) {
824
- const mockedSchema = addMocksToSchema({
825
- schema: graphql.isSchema(schema$1)
826
- ? schema$1
827
- : schema.makeExecutableSchema({
828
- typeDefs: schema$1,
829
- }),
830
- mocks,
831
- preserveResolvers,
832
- });
833
- return {
834
- query: (query, vars) => graphql.graphql({
835
- schema: mockedSchema,
836
- source: query,
837
- rootValue: {},
838
- contextValue: {},
839
- variableValues: vars,
840
- }),
841
- };
842
- }
843
-
844
- /**
845
- * Produces a resolver that'll mock a [Relay-style cursor pagination](https://relay.dev/graphql/connections.htm).
846
- *
847
- * ```ts
848
- * const schemaWithMocks = addMocksToSchema({
849
- * schema,
850
- * resolvers: (store) => ({
851
- * User: {
852
- * friends: relayStylePaginationMock(store),
853
- * }
854
- * }),
855
- * })
856
- * ```
857
- * @param store the MockStore
858
- */
859
- const relayStylePaginationMock = (store, { cursorFn = node => `${node.$ref.key}`, applyOnNodes, allNodesFn, } = {}) => {
860
- return (parent, args, context, info) => {
861
- const source = isRootType(info.parentType, info.schema) ? makeRef(info.parentType.name, 'ROOT') : parent;
862
- const allNodesFn_ = allNodesFn !== null && allNodesFn !== void 0 ? allNodesFn : defaultAllNodesFn(store);
863
- let allNodes = allNodesFn_(source, args, context, info);
864
- if (applyOnNodes) {
865
- allNodes = applyOnNodes(allNodes, args);
866
- }
867
- const allEdges = allNodes.map(node => ({
868
- node,
869
- cursor: cursorFn(node),
870
- }));
871
- let start, end;
872
- const { first, after, last, before } = args;
873
- if (typeof first === 'number') {
874
- // forward pagination
875
- if (last || before) {
876
- throw new Error("if `first` is provided, `last` or `before` can't be provided");
877
- }
878
- const afterIndex = after ? allEdges.findIndex(e => e.cursor === after) : -1;
879
- start = afterIndex + 1;
880
- end = afterIndex + 1 + first;
881
- }
882
- else if (typeof last === 'number') {
883
- // backward pagination
884
- if (first || after) {
885
- throw new Error("if `last` is provided, `first` or `after` can't be provided");
886
- }
887
- const foundBeforeIndex = before ? allEdges.findIndex(e => e.cursor === before) : -1;
888
- const beforeIndex = foundBeforeIndex !== -1 ? foundBeforeIndex : allNodes.length;
889
- start = allEdges.length - (allEdges.length - beforeIndex) - last;
890
- // negative index on Array.slice indicate offset from end of sequence => we don't want
891
- if (start < 0)
892
- start = 0;
893
- end = beforeIndex;
894
- }
895
- else {
896
- throw new Error('A `first` or a `last` arguments should be provided');
897
- }
898
- const edges = allEdges.slice(start, end);
899
- const pageInfo = {
900
- startCursor: edges.length > 0 ? edges[0].cursor : '',
901
- endCursor: edges.length > 0 ? edges[edges.length - 1].cursor : '',
902
- hasNextPage: end < allEdges.length - 1,
903
- hasPreviousPage: start > 0,
904
- };
905
- return {
906
- edges,
907
- pageInfo,
908
- totalCount: allEdges.length,
909
- };
910
- };
911
- };
912
- const defaultAllNodesFn = (store) => (parent, _, __, info) => store.get(parent, [info.fieldName, 'edges']).map(e => store.get(e, 'node'));
913
-
914
- exports.MockList = MockList;
915
- exports.MockStore = MockStore;
916
- exports.addMocksToSchema = addMocksToSchema;
917
- exports.assertIsRef = assertIsRef;
918
- exports.createMockStore = createMockStore;
919
- exports.deepResolveMockList = deepResolveMockList;
920
- exports.defaultMocks = defaultMocks;
921
- exports.isMockList = isMockList;
922
- exports.isRecord = isRecord;
923
- exports.isRef = isRef;
924
- exports.mockServer = mockServer;
925
- exports.relayStylePaginationMock = relayStylePaginationMock;