UNPKG

@devniel/graphql-query-test-mock

Version:

Mock queries to your GraphQL backend in your Jest tests.

140 lines (117 loc) 6.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getNockRequestHandlerFn = getNockRequestHandlerFn; var _deepEqual = _interopRequireDefault(require("deep-equal")); var _getOperationNameFromQuery = require("./getOperationNameFromQuery"); var _handleErrors = require("./handleErrors"); var _index = require("./index"); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function getNockRequestHandlerFn(queryMock) { return function handleNockRequest(uri, data, cb) { try { let parsedData = data; if (typeof parsedData === 'string') { try { // In case of multipart form data, the proper data is located the // multipart annotation, so first extract it. const rg = /({.*})/gi; const matches = parsedData.match(rg); if (!matches) throw new Error(); parsedData = JSON.parse(matches[0]); } catch (e) { throw new Error("Invalid data in request. Please make sure you're actually sending the query in your fetch."); } } if (parsedData && typeof parsedData === 'object') { const query = String(parsedData.query); const operationName = (0, _getOperationNameFromQuery.getOperationNameFromQuery)(query); if (operationName) { const variables = parsedData.variables !== null && typeof parsedData.variables === 'object' ? parsedData.variables : {}; const mockedQueryRecord = queryMock._getQueryMock(operationName, variables); if (mockedQueryRecord) { const { queryMockConfig, resolveQueryPromise } = mockedQueryRecord; const { status } = queryMockConfig; if (status && status >= 400) { // Bail early if status is a failure throw queryMockConfig.error || new Error(`Request for operation "${operationName || 'unknown'}" failed with status ${status}. This is intentional and set up in the mock.`); } const hasVariablesOrMatchFn = !!(queryMockConfig.variables || queryMockConfig.matchVariables); const shouldMatchOnVariables = queryMockConfig.matchOnVariables && hasVariablesOrMatchFn; if (!shouldMatchOnVariables || ( // Bypass if we should not match on variables queryMockConfig.matchVariables ? queryMockConfig.matchVariables(variables) : (0, _deepEqual.default)((0, _utils.getVariables)(variables, queryMockConfig.ignoreThesePropertiesInVariables || []), (0, _utils.getVariables)(queryMockConfig.variables, queryMockConfig.ignoreThesePropertiesInVariables || [])))) { /** * We turn our request handler function into an async one at this point and not earlier, * because this is the first time we're absolutely sure we will resolve the query and that * we won't need to throw an error. Throwing inside the async function will make the Promise swallow * the error, which we do not want. */ (async () => { const serverResponseData = { data: queryMockConfig.data, errors: queryMockConfig.graphqlErrors }; /** * This is a default function that just returns itself (ie does not change the server response) * unless provided a custom function. **/ const changeServerResponseFn = queryMockConfig.changeServerResponse || queryMock._changeServerResponseFn; const serverResponse = changeServerResponseFn(queryMockConfig, serverResponseData); let nockReturnVal = [queryMockConfig.status || 200, serverResponse]; const { customHandler } = queryMockConfig; if (customHandler) { const returnValue = customHandler(this.req, { query, operationName, variables }); nockReturnVal = returnValue instanceof Promise ? await returnValue : // $FlowFixMe returnValue; } // Make sure we add the call to our list queryMock._addCall({ id: operationName, variables, headers: this.req.headers, // $FlowFixMe response: nockReturnVal[1] }); // Wait for resolution control promise to resolve if it exists if (resolveQueryPromise) { await resolveQueryPromise; } cb(null, nockReturnVal); })(); } else { // More useful errors (0, _handleErrors.printVariablesDoesNotMatchError)(queryMockConfig, shouldMatchOnVariables, operationName, variables); } } else { (0, _handleErrors.printNoMockFoundError)(queryMock, operationName, variables); } } else { throw new Error("Could not find operation name in request. Please make sure you're actually sending the query in your fetch."); } } else { // If parsedData can't be processed then return error to avoid timeouts for the invoker. throw new Error("Invalid data in request. Please make sure you're actually sending the query in your fetch."); } } catch (e) { //this.req.emit('error', new Error(e.message)); // Returns errors just like graphql (https://graphql.org/learn/serving-over-http/#response) // and don't throw it because some clients can't catch it (eg. axios) const serverResponse = { errors: [JSON.parse(JSON.stringify(e, Object.getOwnPropertyNames(e)))] }; const nockReturnVal = [500, serverResponse]; return cb(null, nockReturnVal); } }; }