UNPKG

7.61 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.addMocksToSchema = void 0;
4const graphql_1 = require("graphql");
5const utils_1 = require("@graphql-tools/utils");
6const schema_1 = require("@graphql-tools/schema");
7const types_js_1 = require("./types.js");
8const utils_js_1 = require("./utils.js");
9const 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 */
69function 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
203 ? (0, schema_1.addResolversToSchema)({
204 schema: schemaWithMocks,
205 resolvers: resolvers,
206 })
207 : schemaWithMocks;
208}
209exports.addMocksToSchema = addMocksToSchema;