@graphql-tools/mock 8.6.13 → 8.7.0-alpha-b76ec274.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.
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addMocksToSchema = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const utils_1 = require("@graphql-tools/utils");
6
+ const schema_1 = require("@graphql-tools/schema");
7
+ const types_js_1 = require("./types.js");
8
+ const utils_js_1 = require("./utils.js");
9
+ const MockStore_js_1 = require("./MockStore.js");
10
+ // todo: add option to preserve resolver
11
+ /**
12
+ * Given a `schema` and a `MockStore`, returns an executable schema that
13
+ * will use the provided `MockStore` to execute queries.
14
+ *
15
+ * ```ts
16
+ * const schema = buildSchema(`
17
+ * type User {
18
+ * id: ID!
19
+ * name: String!
20
+ * }
21
+ * type Query {
22
+ * me: User!
23
+ * }
24
+ * `)
25
+ *
26
+ * const store = createMockStore({ schema });
27
+ * const mockedSchema = addMocksToSchema({ schema, store });
28
+ * ```
29
+ *
30
+ *
31
+ * If a `resolvers` parameter is passed, the query execution will use
32
+ * the provided `resolvers` if, one exists, instead of the default mock
33
+ * resolver.
34
+ *
35
+ *
36
+ * ```ts
37
+ * const schema = buildSchema(`
38
+ * type User {
39
+ * id: ID!
40
+ * name: String!
41
+ * }
42
+ * type Query {
43
+ * me: User!
44
+ * }
45
+ * type Mutation {
46
+ * setMyName(newName: String!): User!
47
+ * }
48
+ * `)
49
+ *
50
+ * const store = createMockStore({ schema });
51
+ * const mockedSchema = addMocksToSchema({
52
+ * schema,
53
+ * store,
54
+ * resolvers: {
55
+ * Mutation: {
56
+ * setMyName: (_, { newName }) => {
57
+ * const ref = store.get('Query', 'ROOT', 'viewer');
58
+ * store.set(ref, 'name', newName);
59
+ * return ref;
60
+ * }
61
+ * }
62
+ * }
63
+ * });
64
+ * ```
65
+ *
66
+ *
67
+ * `Query` and `Mutation` type will use `key` `'ROOT'`.
68
+ */
69
+ function addMocksToSchema({ schema, store: maybeStore, mocks, typePolicies, resolvers: resolversOrFnResolvers, preserveResolvers = false, }) {
70
+ if (!schema) {
71
+ throw new Error('Must provide schema to mock');
72
+ }
73
+ if (!(0, graphql_1.isSchema)(schema)) {
74
+ throw new Error('Value at "schema" must be of type GraphQLSchema');
75
+ }
76
+ if (mocks && !(0, utils_js_1.isObject)(mocks)) {
77
+ throw new Error('mocks must be of type Object');
78
+ }
79
+ const store = maybeStore ||
80
+ (0, MockStore_js_1.createMockStore)({
81
+ schema,
82
+ mocks,
83
+ typePolicies,
84
+ });
85
+ const resolvers = typeof resolversOrFnResolvers === 'function'
86
+ ? resolversOrFnResolvers(store)
87
+ : resolversOrFnResolvers;
88
+ const mockResolver = (source, args, contex, info) => {
89
+ const defaultResolvedValue = (0, graphql_1.defaultFieldResolver)(source, args, contex, info);
90
+ // priority to default resolved value
91
+ if (defaultResolvedValue !== undefined)
92
+ return defaultResolvedValue;
93
+ if ((0, types_js_1.isRef)(source)) {
94
+ return store.get({
95
+ typeName: source.$ref.typeName,
96
+ key: source.$ref.key,
97
+ fieldName: info.fieldName,
98
+ fieldArgs: args,
99
+ });
100
+ }
101
+ // we have to handle the root mutation, root query and root subscription types
102
+ // differently, because no resolver is called at the root
103
+ if ((0, utils_js_1.isRootType)(info.parentType, info.schema)) {
104
+ return store.get({
105
+ typeName: info.parentType.name,
106
+ key: 'ROOT',
107
+ fieldName: info.fieldName,
108
+ fieldArgs: args,
109
+ });
110
+ }
111
+ if (defaultResolvedValue === undefined) {
112
+ // any is used here because generateFieldValue is a private method at time of writing
113
+ return store.generateFieldValue(info.parentType.name, info.fieldName);
114
+ }
115
+ return undefined;
116
+ };
117
+ const typeResolver = data => {
118
+ if ((0, types_js_1.isRef)(data)) {
119
+ return data.$ref.typeName;
120
+ }
121
+ };
122
+ const mockSubscriber = () => ({
123
+ [Symbol.asyncIterator]() {
124
+ return {
125
+ async next() {
126
+ return {
127
+ done: true,
128
+ value: {},
129
+ };
130
+ },
131
+ };
132
+ },
133
+ });
134
+ const schemaWithMocks = (0, utils_1.mapSchema)(schema, {
135
+ [utils_1.MapperKind.OBJECT_FIELD]: fieldConfig => {
136
+ const newFieldConfig = {
137
+ ...fieldConfig,
138
+ };
139
+ const oldResolver = fieldConfig.resolve;
140
+ if (!preserveResolvers || !oldResolver) {
141
+ newFieldConfig.resolve = mockResolver;
142
+ }
143
+ else {
144
+ newFieldConfig.resolve = async (rootObject, args, context, info) => {
145
+ const [mockedValue, resolvedValue] = await Promise.all([
146
+ mockResolver(rootObject, args, context, info),
147
+ oldResolver(rootObject, args, context, info),
148
+ ]);
149
+ // In case we couldn't mock
150
+ if (mockedValue instanceof Error) {
151
+ // only if value was not resolved, populate the error.
152
+ if (undefined === resolvedValue) {
153
+ throw mockedValue;
154
+ }
155
+ return resolvedValue;
156
+ }
157
+ if (resolvedValue instanceof Date && mockedValue instanceof Date) {
158
+ return undefined !== resolvedValue ? resolvedValue : mockedValue;
159
+ }
160
+ if ((0, utils_js_1.isObject)(mockedValue) && (0, utils_js_1.isObject)(resolvedValue)) {
161
+ // Object.assign() won't do here, as we need to all properties, including
162
+ // the non-enumerable ones and defined using Object.defineProperty
163
+ const emptyObject = Object.create(Object.getPrototypeOf(resolvedValue));
164
+ return (0, utils_js_1.copyOwnProps)(emptyObject, resolvedValue, mockedValue);
165
+ }
166
+ return undefined !== resolvedValue ? resolvedValue : mockedValue;
167
+ };
168
+ }
169
+ const fieldSubscriber = fieldConfig.subscribe;
170
+ if (!preserveResolvers || !fieldSubscriber) {
171
+ newFieldConfig.subscribe = mockSubscriber;
172
+ }
173
+ else {
174
+ newFieldConfig.subscribe = async (rootObject, args, context, info) => {
175
+ const [mockAsyncIterable, oldAsyncIterable] = await Promise.all([
176
+ mockSubscriber(rootObject, args, context, info),
177
+ fieldSubscriber(rootObject, args, context, info),
178
+ ]);
179
+ return oldAsyncIterable || mockAsyncIterable;
180
+ };
181
+ }
182
+ return newFieldConfig;
183
+ },
184
+ [utils_1.MapperKind.ABSTRACT_TYPE]: type => {
185
+ if (preserveResolvers && type.resolveType != null && type.resolveType.length) {
186
+ return;
187
+ }
188
+ if ((0, graphql_1.isUnionType)(type)) {
189
+ return new graphql_1.GraphQLUnionType({
190
+ ...type.toConfig(),
191
+ resolveType: typeResolver,
192
+ });
193
+ }
194
+ else {
195
+ return new graphql_1.GraphQLInterfaceType({
196
+ ...type.toConfig(),
197
+ resolveType: typeResolver,
198
+ });
199
+ }
200
+ },
201
+ });
202
+ return resolvers ? (0, schema_1.addResolversToSchema)(schemaWithMocks, resolvers) : schemaWithMocks;
203
+ }
204
+ exports.addMocksToSchema = addMocksToSchema;
package/cjs/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./MockStore.js"), exports);
5
+ tslib_1.__exportStar(require("./addMocksToSchema.js"), exports);
6
+ tslib_1.__exportStar(require("./mockServer.js"), exports);
7
+ tslib_1.__exportStar(require("./types.js"), exports);
8
+ tslib_1.__exportStar(require("./MockList.js"), exports);
9
+ tslib_1.__exportStar(require("./pagination.js"), exports);
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mockServer = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const schema_1 = require("@graphql-tools/schema");
6
+ const addMocksToSchema_js_1 = require("./addMocksToSchema.js");
7
+ /**
8
+ * A convenience wrapper on top of addMocksToSchema. It adds your mock resolvers
9
+ * to your schema and returns a client that will correctly execute your query with
10
+ * variables. Note: when executing queries from the returned server, context and
11
+ * root will both equal `{}`.
12
+ * @param schema The schema to which to add mocks. This can also be a set of type
13
+ * definitions instead.
14
+ * @param mocks The mocks to add to the schema.
15
+ * @param preserveResolvers Set to `true` to prevent existing resolvers from being
16
+ * overwritten to provide mock data. This can be used to mock some parts of the
17
+ * server and not others.
18
+ */
19
+ function mockServer(schema, mocks, preserveResolvers = false) {
20
+ const mockedSchema = (0, addMocksToSchema_js_1.addMocksToSchema)({
21
+ schema: (0, graphql_1.isSchema)(schema)
22
+ ? schema
23
+ : (0, schema_1.makeExecutableSchema)({
24
+ typeDefs: schema,
25
+ }),
26
+ mocks,
27
+ preserveResolvers,
28
+ });
29
+ return {
30
+ query: (query, vars) => (0, graphql_1.graphql)({
31
+ schema: mockedSchema,
32
+ source: query,
33
+ rootValue: {},
34
+ contextValue: {},
35
+ variableValues: vars,
36
+ }),
37
+ };
38
+ }
39
+ exports.mockServer = mockServer;
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.relayStylePaginationMock = void 0;
4
+ const utils_js_1 = require("./utils.js");
5
+ /**
6
+ * Produces a resolver that'll mock a [Relay-style cursor pagination](https://relay.dev/graphql/connections.htm).
7
+ *
8
+ * ```ts
9
+ * const schemaWithMocks = addMocksToSchema({
10
+ * schema,
11
+ * resolvers: (store) => ({
12
+ * User: {
13
+ * friends: relayStylePaginationMock(store),
14
+ * }
15
+ * }),
16
+ * })
17
+ * ```
18
+ * @param store the MockStore
19
+ */
20
+ const relayStylePaginationMock = (store, { cursorFn = node => `${node.$ref.key}`, applyOnNodes, allNodesFn, } = {}) => {
21
+ return (parent, args, context, info) => {
22
+ const source = (0, utils_js_1.isRootType)(info.parentType, info.schema) ? (0, utils_js_1.makeRef)(info.parentType.name, 'ROOT') : parent;
23
+ const allNodesFn_ = allNodesFn !== null && allNodesFn !== void 0 ? allNodesFn : defaultAllNodesFn(store);
24
+ let allNodes = allNodesFn_(source, args, context, info);
25
+ if (applyOnNodes) {
26
+ allNodes = applyOnNodes(allNodes, args);
27
+ }
28
+ const allEdges = allNodes.map(node => ({
29
+ node,
30
+ cursor: cursorFn(node),
31
+ }));
32
+ let start, end;
33
+ const { first, after, last, before } = args;
34
+ if (typeof first === 'number') {
35
+ // forward pagination
36
+ if (last || before) {
37
+ throw new Error("if `first` is provided, `last` or `before` can't be provided");
38
+ }
39
+ const afterIndex = after ? allEdges.findIndex(e => e.cursor === after) : -1;
40
+ start = afterIndex + 1;
41
+ end = afterIndex + 1 + first;
42
+ }
43
+ else if (typeof last === 'number') {
44
+ // backward pagination
45
+ if (first || after) {
46
+ throw new Error("if `last` is provided, `first` or `after` can't be provided");
47
+ }
48
+ const foundBeforeIndex = before ? allEdges.findIndex(e => e.cursor === before) : -1;
49
+ const beforeIndex = foundBeforeIndex !== -1 ? foundBeforeIndex : allNodes.length;
50
+ start = allEdges.length - (allEdges.length - beforeIndex) - last;
51
+ // negative index on Array.slice indicate offset from end of sequence => we don't want
52
+ if (start < 0)
53
+ start = 0;
54
+ end = beforeIndex;
55
+ }
56
+ else {
57
+ throw new Error('A `first` or a `last` arguments should be provided');
58
+ }
59
+ const edges = allEdges.slice(start, end);
60
+ const pageInfo = {
61
+ startCursor: edges.length > 0 ? edges[0].cursor : '',
62
+ endCursor: edges.length > 0 ? edges[edges.length - 1].cursor : '',
63
+ hasNextPage: end < allEdges.length - 1,
64
+ hasPreviousPage: start > 0,
65
+ };
66
+ return {
67
+ edges,
68
+ pageInfo,
69
+ totalCount: allEdges.length,
70
+ };
71
+ };
72
+ };
73
+ exports.relayStylePaginationMock = relayStylePaginationMock;
74
+ const defaultAllNodesFn = (store) => (parent, _, __, info) => store.get(parent, [info.fieldName, 'edges']).map(e => store.get(e, 'node'));
package/cjs/types.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRecord = exports.assertIsRef = exports.isRef = void 0;
4
+ function isRef(maybeRef) {
5
+ return !!(maybeRef && typeof maybeRef === 'object' && '$ref' in maybeRef);
6
+ }
7
+ exports.isRef = isRef;
8
+ function assertIsRef(maybeRef, message) {
9
+ if (!isRef(maybeRef)) {
10
+ throw new Error(message || `Expected ${maybeRef} to be a valid Ref.`);
11
+ }
12
+ }
13
+ exports.assertIsRef = assertIsRef;
14
+ function isRecord(obj) {
15
+ return typeof obj === 'object' && obj !== null;
16
+ }
17
+ exports.isRecord = isRecord;
package/cjs/utils.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRootType = exports.copyOwnProps = exports.copyOwnPropsIfNotPresent = exports.isObject = exports.makeRef = exports.takeRandom = exports.randomListLength = exports.uuidv4 = void 0;
4
+ const utils_1 = require("@graphql-tools/utils");
5
+ function uuidv4() {
6
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
7
+ const r = (Math.random() * 16) | 0;
8
+ // eslint-disable-next-line eqeqeq
9
+ const v = c == 'x' ? r : (r & 0x3) | 0x8;
10
+ return v.toString(16);
11
+ });
12
+ }
13
+ exports.uuidv4 = uuidv4;
14
+ const randomListLength = () => {
15
+ // Mocking has always returned list of length 2 by default
16
+ // return 1 + Math.round(Math.random() * 10)
17
+ return 2;
18
+ };
19
+ exports.randomListLength = randomListLength;
20
+ const takeRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
21
+ exports.takeRandom = takeRandom;
22
+ function makeRef(typeName, key) {
23
+ return { $ref: { key, typeName } };
24
+ }
25
+ exports.makeRef = makeRef;
26
+ function isObject(thing) {
27
+ return thing === Object(thing) && !Array.isArray(thing);
28
+ }
29
+ exports.isObject = isObject;
30
+ function copyOwnPropsIfNotPresent(target, source) {
31
+ for (const prop of Object.getOwnPropertyNames(source)) {
32
+ if (!Object.getOwnPropertyDescriptor(target, prop)) {
33
+ const propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
34
+ Object.defineProperty(target, prop, propertyDescriptor == null ? {} : propertyDescriptor);
35
+ }
36
+ }
37
+ }
38
+ exports.copyOwnPropsIfNotPresent = copyOwnPropsIfNotPresent;
39
+ function copyOwnProps(target, ...sources) {
40
+ for (const source of sources) {
41
+ let chain = source;
42
+ while (chain != null) {
43
+ copyOwnPropsIfNotPresent(target, chain);
44
+ chain = Object.getPrototypeOf(chain);
45
+ }
46
+ }
47
+ return target;
48
+ }
49
+ exports.copyOwnProps = copyOwnProps;
50
+ const isRootType = (type, schema) => {
51
+ const rootTypeNames = (0, utils_1.getRootTypeNames)(schema);
52
+ return rootTypeNames.has(type.name);
53
+ };
54
+ exports.isRootType = isRootType;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export function isMockList(obj) {
5
+ 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')) {
6
+ if (typeof obj.wrappedFunction === 'undefined' || typeof obj.wrappedFunction === 'function') {
7
+ return true;
8
+ }
9
+ }
10
+ return false;
11
+ }
12
+ /**
13
+ * This is an object you can return from your mock resolvers which calls the
14
+ * provided `mockFunction` once for each list item.
15
+ */
16
+ export class MockList {
17
+ /**
18
+ * @param length Either the exact length of items to return or an inclusive
19
+ * range of possible lengths.
20
+ * @param mockFunction The function to call for each item in the list to
21
+ * resolve it. It can return another MockList or a value.
22
+ */
23
+ constructor(length, mockFunction) {
24
+ this.len = length;
25
+ if (typeof mockFunction !== 'undefined') {
26
+ if (typeof mockFunction !== 'function') {
27
+ throw new Error('Second argument to MockList must be a function or undefined');
28
+ }
29
+ this.wrappedFunction = mockFunction;
30
+ }
31
+ }
32
+ /**
33
+ * @internal
34
+ */
35
+ mock() {
36
+ let arr;
37
+ if (Array.isArray(this.len)) {
38
+ arr = new Array(this.randint(this.len[0], this.len[1]));
39
+ }
40
+ else {
41
+ arr = new Array(this.len);
42
+ }
43
+ for (let i = 0; i < arr.length; i++) {
44
+ if (typeof this.wrappedFunction === 'function') {
45
+ const res = this.wrappedFunction();
46
+ if (isMockList(res)) {
47
+ arr[i] = res.mock();
48
+ }
49
+ else {
50
+ arr[i] = res;
51
+ }
52
+ }
53
+ else {
54
+ arr[i] = undefined;
55
+ }
56
+ }
57
+ return arr;
58
+ }
59
+ randint(low, high) {
60
+ return Math.floor(Math.random() * (high - low + 1) + low);
61
+ }
62
+ }
63
+ export function deepResolveMockList(mockList) {
64
+ return mockList.mock().map(v => {
65
+ if (isMockList(v))
66
+ return deepResolveMockList(v);
67
+ return v;
68
+ });
69
+ }