@graphql-mesh/plugin-mock
Version:
154 lines (153 loc) • 9 kB
JavaScript
import faker from 'faker';
import { execute } from 'graphql';
import { mocks as graphqlScalarsMocks } from 'graphql-scalars';
import { getInterpolatedStringFactory } from '@graphql-mesh/string-interpolation';
import { loadFromModuleExportExpression } from '@graphql-mesh/utils';
import { addMocksToSchema, createMockStore } from '@graphql-tools/mock';
const mockedSchemas = new WeakSet();
export default function useMock(config) {
// eslint-disable-next-line no-new-func
const configIf = config != null && 'if' in config ? new Function(`return ${config.if}`)() : true;
if (configIf) {
return {
onSchemaChange({ schema, replaceSchema }) {
if (mockedSchemas.has(schema)) {
return;
}
const mocks = {
...graphqlScalarsMocks,
};
const resolvers = {};
const typeMap = schema.getTypeMap();
for (const typeName in typeMap) {
const type = typeMap[typeName];
const examples = type.extensions.examples;
if (examples?.length) {
mocks[typeName] = () => examples[Math.floor(Math.random() * examples.length)];
}
}
if (config?.mocks?.length) {
for (const fieldConfig of config.mocks) {
const fieldConfigIf = 'if' in fieldConfig ? fieldConfig.if : true;
if (fieldConfigIf) {
const [typeName, fieldName] = fieldConfig.apply.split('.');
if (fieldName) {
if (fieldConfig.faker) {
let fakerFn; // eslint-disable-line
const [service, method] = fieldConfig.faker.split('.');
if (service in faker) {
fakerFn = () => faker[service][method]();
}
else {
fakerFn = () => faker.fake(fieldConfig.faker || '');
}
resolvers[typeName] = resolvers[typeName] || {};
resolvers[typeName][fieldName] = fakerFn;
}
else if (fieldConfig.custom) {
const exportedVal$ = loadFromModuleExportExpression(fieldConfig.custom, {
cwd: config.baseDir,
defaultExportName: 'default',
importFn: config.importFn,
});
resolvers[typeName] = resolvers[typeName] || {};
resolvers[typeName][fieldName] = (root, args, context, info) => {
context = context || {};
context.mockStore = store;
return exportedVal$.then(exportedVal => typeof exportedVal === 'function'
? exportedVal(root, args, context, info)
: exportedVal);
};
}
else if ('length' in fieldConfig) {
resolvers[typeName] = resolvers[typeName] || {};
resolvers[typeName][fieldName] = () => new Array(fieldConfig.length).fill({});
}
else if ('updateStore' in fieldConfig) {
const getFromStoreKeyFactory = getInterpolatedStringFactory(fieldConfig.store.key);
const updateStoreFactories = fieldConfig.updateStore.map(updateStoreConfig => ({
updateStoreConfig,
keyFactory: getInterpolatedStringFactory(updateStoreConfig.key),
valueFactory: getInterpolatedStringFactory(updateStoreConfig.value),
}));
resolvers[typeName] = resolvers[typeName] || {};
resolvers[typeName][fieldName] = (root, args, context, info) => {
const resolverData = {
root,
args,
context,
info,
random: Date.now().toString(),
env: process.env,
};
updateStoreFactories.forEach(({ updateStoreConfig, keyFactory, valueFactory }) => {
const key = keyFactory(resolverData);
const value = valueFactory(resolverData);
store.set(updateStoreConfig.type, key, updateStoreConfig.fieldName, value);
});
const key = getFromStoreKeyFactory(resolverData);
return store.get(fieldConfig.store.type, key, fieldConfig.store.fieldName);
};
}
else if ('store' in fieldConfig) {
const keyFactory = getInterpolatedStringFactory(fieldConfig.store.key);
resolvers[typeName] = resolvers[typeName] || {};
resolvers[typeName][fieldName] = (root, args, context, info) => {
const key = keyFactory({ root, args, context, info, env: process.env });
return store.get(fieldConfig.store.type, key, fieldConfig.store.fieldName);
};
}
}
else {
if (fieldConfig.faker) {
let fakerFn;
const [service, method] = fieldConfig.faker.split('.');
if (service in faker) {
fakerFn = () => faker[service][method]();
}
else {
fakerFn = () => faker.fake(fieldConfig.faker || '');
}
mocks[typeName] = fakerFn;
}
else if (fieldConfig.custom) {
const exportedVal$ = loadFromModuleExportExpression(fieldConfig.custom, {
cwd: config.baseDir,
defaultExportName: 'default',
importFn: config.importFn,
});
mocks[typeName] = () => {
return exportedVal$.then(exportedVal => typeof exportedVal === 'function' ? exportedVal(store) : exportedVal);
};
}
}
}
}
}
const store = createMockStore({ schema, mocks });
if (config?.initializeStore) {
const initializeStoreFn$ = loadFromModuleExportExpression(config.initializeStore, {
cwd: config.baseDir,
defaultExportName: 'default',
importFn: config.importFn,
});
// eslint-disable-next-line no-void
void initializeStoreFn$.then(fn => fn(store));
}
const mockedSchema = addMocksToSchema({
schema,
store,
mocks,
resolvers,
preserveResolvers: config?.preserveResolvers,
});
mockedSchemas.add(mockedSchema);
replaceSchema(mockedSchema);
},
onExecute({ setExecuteFn }) {
setExecuteFn(execute);
},
};
}
return {};
}