UNPKG

unmock-core

Version:

[![npm](https://img.shields.io/npm/v/unmock-core.svg)][npmjs] [![CircleCI](https://circleci.com/gh/unmock/unmock-js.svg?style=svg)](https://circleci.com/gh/unmock/unmock-js) [![codecov](https://codecov.io/gh/unmock/unmock-js/branch/dev/graph/badge.svg)](h

180 lines 7.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const jsf = require("json-schema-faker"); const lodash_1 = require("lodash"); function firstOrRandomOrUndefined(arr) { return arr.length === 0 ? undefined : arr.length === 1 ? arr[0] : arr[Math.floor(Math.random() * arr.length)]; } function responseCreatorFactory({ listeners = [], options, store, }) { const match = (sreq) => Object.values(store.cores) .map(service => service.match(sreq)) .filter(res => res !== undefined) .shift(); return (req) => { setupJSFUnmockProperties(req); const matcherResponse = match(req); const res = generateMockFromTemplate(options, matcherResponse); if (typeof matcherResponse !== "undefined" && typeof res !== "undefined") { matcherResponse.service.track({ req, res }); } listeners.forEach((listener) => listener.notify({ req, res })); jsf.reset(); return res; }; } exports.responseCreatorFactory = responseCreatorFactory; const normalizeHeaders = (headers) => headers === undefined ? undefined : Object.keys(headers).reduce((acc, h) => (Object.assign(Object.assign({}, acc), { [h]: headers[h].schema })), {}); const toJSONSchemaType = (input) => Array.isArray(input) ? "array" : input === null || input === undefined ? "null" : typeof input; const setupJSFUnmockProperties = (sreq) => { jsf.extend("faker", () => require("faker")); jsf.define("unmock-function", (fn, schema) => { const res = fn(sreq); delete schema.format; schema.type = toJSONSchemaType(res); return res; }); }; const chooseResponseCode = (codes) => { if (codes.length === 1) { return codes[0]; } const validCodes = codes.filter((cd) => parseInt(cd) > 199 && parseInt(cd) < 300); if (validCodes.length > 1) { return validCodes; } return validCodes[0]; }; const getStateForOperation = (operation, state, deref, genOptions) => { const responses = operation.responses; const operationCodes = Object.keys(responses); if (state === undefined || Object.keys(state).length === 0) { return undefined; } const stateCodes = Object.keys(state); const possibleResponseCodes = stateCodes.filter((code) => operationCodes.includes(code)); let operationStatusCode; let stateStatusCode; if (possibleResponseCodes.length === 0) { if (operationCodes.indexOf("default") === -1) { return undefined; } operationStatusCode = "default"; stateStatusCode = firstOrRandomOrUndefined(stateCodes); } else { stateStatusCode = operationStatusCode = genOptions.isFlaky ? firstOrRandomOrUndefined(possibleResponseCodes) : chooseResponseCode(possibleResponseCodes); } if (operationStatusCode === undefined || stateStatusCode === undefined) { throw new Error(`Too many matching response codes to choose from in '${operation.description}'!\n` + `Try flaky mode (\`unmock.flaky()\`) or explictly set a status code (\`{ $code: N }\`)`); } else if (Array.isArray(operationStatusCode) || Array.isArray(stateStatusCode)) { throw new Error(`Too many 2XX responses to choose from in '${operation.description}'!\n` + `Try flaky mode (\`unmock.flaky()\`) or explictly set a status code (\`{ $code: N }\`)`); } const operationResponse = responses[operationStatusCode]; if (operationResponse === undefined) { return undefined; } const resolvedResponse = deref(operationResponse); const operationContent = resolvedResponse.content; if (operationContent === undefined) { return undefined; } const operationContentKeys = Object.keys(operationContent); const mediaTypes = Object.keys(state[stateStatusCode]).filter((type) => operationContentKeys.includes(type)); const mediaType = firstOrRandomOrUndefined(mediaTypes); if (mediaType === undefined) { return undefined; } const requestedState = state[stateStatusCode][mediaType]; const matchedOperation = operationContent[mediaType].schema; return { $code: stateStatusCode, template: lodash_1.defaultsDeep(requestedState, matchedOperation), headers: deref(resolvedResponse.headers), }; }; const chooseResponseFromOperation = (operation, deref, genOptions) => { const responses = operation.responses; const codes = Object.keys(responses); const chosenCode = genOptions.isFlaky ? firstOrRandomOrUndefined(codes) : chooseResponseCode(codes); if (chosenCode === undefined) { if (genOptions.isFlaky) { throw new Error(`Could not find any responses in operation '${operation.description}'`); } else { throw new Error(`No valid 2XX responses in '${operation.description}'`); } } else if (Array.isArray(chosenCode)) { throw new Error(`Too many 2XX responses to choose from in '${operation.description}'!\n` + `Try flaky mode (\`unmock.flaky()\`) or explictly set a status code (\`{ $code: N }\`)`); } const response = responses[chosenCode]; if (response === undefined) { throw new Error(`Could not load response for status code '${chosenCode}' in '${operation.description}'`); } const deRefedResponse = deref(response); const content = deRefedResponse.content; if (content === undefined) { return { $code: chosenCode, template: undefined, headers: deref(deRefedResponse.headers), }; } const chosenMediaType = firstOrRandomOrUndefined(Object.keys(content)); if (chosenMediaType === undefined) { throw new Error(`Chosen response (${JSON.stringify(content)}) does not have any content!`); } const schema = content[chosenMediaType].schema; if (schema === undefined) { throw new Error("Missing schema for a response!"); } return { $code: chosenCode, template: deref(schema), headers: deref(deRefedResponse.headers), }; }; const generateMockFromTemplate = (options, matchedService) => { if (matchedService === undefined) { return undefined; } const { operation, state, service } = matchedService; const { template, $code, headers } = getStateForOperation(operation, state, service.dereferencer, { isFlaky: options.flaky(), }) || chooseResponseFromOperation(operation, service.dereferencer, { isFlaky: options.flaky(), }); jsf.option("alwaysFakeOptionals", true); jsf.option("useDefaultValue", false); const resolvedTemplate = jsf.generate(template); const body = JSON.stringify(resolvedTemplate); jsf.option("useDefaultValue", true); const resHeaders = jsf.generate(normalizeHeaders(headers)); jsf.option("useDefaultValue", false); return { body, headers: resHeaders, statusCode: +$code || 200, }; }; //# sourceMappingURL=generator.js.map