UNPKG

9.91 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.mockServer = exports.MockList = exports.addMockFunctionsToSchema = undefined;
7
8var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
9
10var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
11
12var _type = require('graphql/type');
13
14var _casualBrowserify = require('casual-browserify');
15
16var _casualBrowserify2 = _interopRequireDefault(_casualBrowserify);
17
18var _graphql = require('graphql');
19
20var _nodeUuid = require('node-uuid');
21
22var _nodeUuid2 = _interopRequireDefault(_nodeUuid);
23
24var _schemaGenerator = require('./schemaGenerator');
25
26function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
28function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
29
30function mockServer(schema) {
31 var mocks = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
32 var preserveResolvers = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
33
34 var mySchema = schema;
35 if (!(schema instanceof _type.GraphQLSchema)) {
36 console.log('is shorthand');
37 mySchema = (0, _schemaGenerator.buildSchemaFromTypeDefinitions)(schema);
38 }
39 addMockFunctionsToSchema({ schema: mySchema, mocks: mocks, preserveResolvers: preserveResolvers });
40
41 return { query: function query(_query, vars) {
42 return (0, _graphql.graphql)(mySchema, _query, {}, {}, vars);
43 } };
44}
45
46function addMockFunctionsToSchema() {
47 var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
48
49 var schema = _ref.schema;
50 var _ref$mocks = _ref.mocks;
51 var mocks = _ref$mocks === undefined ? {} : _ref$mocks;
52 var _ref$preserveResolver = _ref.preserveResolvers;
53 var preserveResolvers = _ref$preserveResolver === undefined ? false : _ref$preserveResolver;
54
55 function isObject(thing) {
56 return thing === Object(thing) && !Array.isArray(thing);
57 }
58 if (!schema) {
59 // XXX should we check that schema is an instance of GraphQLSchema?
60 throw new Error('Must provide schema to mock');
61 }
62 if (!isObject(mocks)) {
63 throw new Error('mocks must be of type Object');
64 }
65
66 // use Map internally, because that API is nicer.
67 var mockFunctionMap = new Map();
68 Object.keys(mocks).forEach(function (typeName) {
69 mockFunctionMap.set(typeName, mocks[typeName]);
70 });
71
72 mockFunctionMap.forEach(function (mockFunction, mockTypeName) {
73 if (typeof mockFunction !== 'function') {
74 throw new Error('mockFunctionMap[' + mockTypeName + '] must be a function');
75 }
76 });
77
78 var defaultMockMap = new Map();
79 defaultMockMap.set('Int', function () {
80 return _casualBrowserify2.default.integer();
81 });
82 defaultMockMap.set('Float', function () {
83 return _casualBrowserify2.default.double();
84 });
85 defaultMockMap.set('String', function () {
86 return _casualBrowserify2.default.words(2);
87 });
88 defaultMockMap.set('Boolean', function () {
89 return _casualBrowserify2.default.coin_flip;
90 });
91 defaultMockMap.set('ID', function () {
92 return _nodeUuid2.default.v4();
93 });
94
95 function mergeObjects(a, b) {
96 return Object.assign(a, b);
97 }
98
99 // takes either an object or a (possibly nested) array
100 // and completes the customMock object with any fields
101 // defined on genericMock
102 // only merges objects or arrays. Scalars are returned as is
103 function mergeMocks(genericMockFunction, customMock) {
104 if (Array.isArray(customMock)) {
105 return customMock.map(function (el) {
106 return mergeMocks(genericMockFunction, el);
107 });
108 }
109 if (isObject(customMock)) {
110 return mergeObjects(genericMockFunction(), customMock);
111 }
112 return customMock;
113 }
114
115 var mockType = function mockType(type, typeName, fieldName) {
116 // order of precendence for mocking:
117 // 1. if the object passed in already has fieldName, just use that
118 // --> if it's a function, that becomes your resolver
119 // --> if it's a value, the mock resolver will return that
120 // 2. if the nullableType is a list, recurse
121 // 2. if there's a mock defined for this typeName, that will be used
122 // 3. if there's no mock defined, use the default mocks for this type
123 return function (o, a, c, r) {
124 // nullability doesn't matter for the purpose of mocking.
125 var fieldType = (0, _type.getNullableType)(type);
126 var namedFieldType = (0, _type.getNamedType)(fieldType);
127
128 if (o && typeof o[fieldName] !== 'undefined') {
129 var result = void 0;
130 // if we're here, the field is already defined
131 if (typeof o[fieldName] === 'function') {
132 result = o[fieldName](o, a, c, r);
133 if (result instanceof MockList) {
134 result = result.mock(o, a, c, r, fieldType, mockType);
135 }
136 } else {
137 result = o[fieldName];
138 }
139
140 // Now we merge the result with the default mock for this type.
141 // This allows overriding defaults while writing very little code.
142 if (mockFunctionMap.has(namedFieldType.name)) {
143 result = mergeMocks(mockFunctionMap.get(namedFieldType.name).bind(null, o, a, c, r), result);
144 }
145 return result;
146 }
147
148 if (fieldType instanceof _type.GraphQLList) {
149 return [mockType(type.ofType)(o, a, c, r), mockType(type.ofType)(o, a, c, r)];
150 }
151 if (mockFunctionMap.has(fieldType.name)) {
152 // the object passed doesn't have this field, so we apply the default mock
153 return mockFunctionMap.get(fieldType.name)(o, a, c, r);
154 }
155 if (fieldType instanceof _type.GraphQLObjectType) {
156 return {};
157 }
158 if (defaultMockMap.has(fieldType.name)) {
159 return defaultMockMap.get(fieldType.name)(o, a, c, r);
160 }
161 // if we get to here, we don't have a value, and we don't have a mock for this type,
162 // we could return undefined, but that would be hard to debug, so we throw instead.
163 throw new Error('No mock defined for type "' + fieldType.name + '"');
164 };
165 };
166
167 (0, _schemaGenerator.forEachField)(schema, function (field, typeName, fieldName) {
168 if (preserveResolvers && field.resolve) {
169 return;
170 }
171
172 // we have to handle the root mutation and root query types differently,
173 // because no resolver is called at the root.
174 var isOnQueryType = typeName === (schema.getQueryType() || {}).name;
175 var isOnMutationType = typeName === (schema.getMutationType() || {}).name;
176 if (isOnQueryType || isOnMutationType) {
177 if (mockFunctionMap.has(typeName)) {
178 var _ret = function () {
179 var rootMock = mockFunctionMap.get(typeName);
180 if (rootMock()[fieldName]) {
181 // TODO: assert that it's a function
182 // eslint-disable-next-line no-param-reassign
183 field.resolve = function (o, a, c, r) {
184 var u = o || {}; // TODO: should we clone instead?
185 u[fieldName] = rootMock()[fieldName];
186 // XXX this is a bit of a hack to still use mockType, which
187 // lets you mock lists etc. as well
188 // otherwise we could just set field.resolve to rootMock()[fieldName]
189 // it's like pretending there was a resolve function that ran before
190 // the root resolve function.
191 return mockType(field.type, typeName, fieldName)(u, a, c, r);
192 };
193 return {
194 v: void 0
195 };
196 }
197 }();
198
199 if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
200 }
201 }
202 // eslint-disable-next-line no-param-reassign
203 field.resolve = mockType(field.type, typeName, fieldName);
204 });
205}
206
207var MockList = function () {
208 // wrappedFunction can return another MockList or a value
209
210 function MockList(len, wrappedFunction) {
211 _classCallCheck(this, MockList);
212
213 this.len = len;
214 if (typeof wrappedFunction !== 'undefined') {
215 if (typeof wrappedFunction !== 'function') {
216 throw new Error('Second argument to MockList must be a function or undefined');
217 }
218 this.wrappedFunction = wrappedFunction;
219 }
220 }
221
222 _createClass(MockList, [{
223 key: 'mock',
224 value: function mock(o, a, c, r, fieldType, mockTypeFunc) {
225 function randint(low, high) {
226 return Math.floor(Math.random() * (high - low + 1) + low);
227 }
228 var arr = void 0;
229 if (Array.isArray(this.len)) {
230 arr = new Array(randint(this.len[0], this.len[1]));
231 } else {
232 arr = new Array(this.len);
233 }
234 for (var i = 0; i < arr.length; i++) {
235 if (typeof this.wrappedFunction === 'function') {
236 var res = this.wrappedFunction(o, a, c, r);
237 if (res instanceof MockList) {
238 arr[i] = res.mock(o, a, c, r, (0, _type.getNullableType)(fieldType.ofType), mockTypeFunc);
239 } else {
240 arr[i] = res;
241 }
242 } else {
243 arr[i] = mockTypeFunc(fieldType.ofType)(o, a, c, r);
244 }
245 }
246 return arr;
247 }
248 }]);
249
250 return MockList;
251}();
252
253exports.addMockFunctionsToSchema = addMockFunctionsToSchema;
254exports.MockList = MockList;
255exports.mockServer = mockServer;
\No newline at end of file