diff --git a/.eslintrc b/.eslintrc index c6c6b885c..88e6f0713 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,20 +1,31 @@ { "root": true, - "extends": "eslint-config-airbnb-base", "env": { "shared-node-browser": true, "es6": true, "es2017": true }, + "globals": { + "File": true, + "Blob": true + }, "parserOptions": { "sourceType": "module", "ecmaFeatures": { "impliedStrict": true } }, + "extends": ["eslint-config-airbnb-base", "prettier"], + "plugins": ["eslint-plugin-prettier", "prettier"], "rules": { - "arrow-body-style": 0, // will be eliminated by prettier - + "import/order": ["error", { + "groups": [ + ["builtin", "external", "internal"], + ["parent", "sibling", "index"] + ], + "newlines-between": "always" + }], + "prettier/prettier": "error", "no-param-reassign": 0, // needs to be eliminated in future "no-use-before-define": [2, "nofunc"] // needs to be eliminated in future } diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..a91f91670 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "trailingComma": "es5" +} diff --git a/package-lock.json b/package-lock.json index f2c5d16cc..e9241f838 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7164,6 +7164,23 @@ "object.entries": "^1.1.2" } }, + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + } + } + }, "eslint-import-resolver-node": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", @@ -7341,6 +7358,15 @@ } } }, + "eslint-plugin-prettier": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz", + "integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -7895,6 +7921,12 @@ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", @@ -8474,14 +8506,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8496,20 +8526,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -8626,8 +8653,7 @@ "inherits": { "version": "2.0.4", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -8639,7 +8665,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -8654,7 +8679,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8775,8 +8799,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -8788,7 +8811,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -8902,7 +8924,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -14059,6 +14080,21 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", diff --git a/package.json b/package.json index 736c46ee6..9519763fa 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,9 @@ "bundlesize": "=0.18.0", "eslint": "=7.2.0", "eslint-config-airbnb-base": "=14.2.0", + "eslint-config-prettier": "=6.11.0", "eslint-plugin-import": "=2.21.2", + "eslint-plugin-prettier": "=3.1.4", "expect": "=26.0.1", "fetch-mock": "=9.10.1", "glob": "=7.1.6", @@ -82,6 +84,7 @@ "node-fetch": "=2.6.0", "npm-audit-ci-wrapper": "=2.6.6", "npm-run-all": "=4.1.5", + "prettier": "=2.0.5", "release-it": "=12.4.3", "terser-webpack-plugin": "=3.0.6", "webpack": "=4.43.0", diff --git a/src/execute/index.js b/src/execute/index.js index bb3feed1d..de7bafe89 100755 --- a/src/execute/index.js +++ b/src/execute/index.js @@ -3,24 +3,24 @@ import isPlainObject from 'lodash/isPlainObject'; import isArray from 'lodash/isArray'; import url from 'url'; import cookie from 'cookie'; + import stockHttp, { mergeInQueryOrForm } from '../http'; import createError from '../specmap/lib/create-error'; - import SWAGGER2_PARAMETER_BUILDERS from './swagger2/parameter-builders'; import * as OAS3_PARAMETER_BUILDERS from './oas3/parameter-builders'; import oas3BuildRequest from './oas3/build-request'; import swagger2BuildRequest from './swagger2/build-request'; -import { - getOperationRaw, - legacyIdFromPathMethod, - isOAS3, -} from '../helpers'; +import { getOperationRaw, legacyIdFromPathMethod, isOAS3 } from '../helpers'; const arrayOrEmpty = (ar) => { return Array.isArray(ar) ? ar : []; }; -const OperationNotFoundError = createError('OperationNotFoundError', function cb(message, extra, oriError) { +const OperationNotFoundError = createError('OperationNotFoundError', function cb( + message, + extra, + oriError +) { this.originalError = oriError; Object.assign(this, extra || {}); }); @@ -74,7 +74,12 @@ export function execute({ } const request = self.buildRequest({ - spec, operationId, parameters, securities, http, ...extras, + spec, + operationId, + parameters, + securities, + http, + ...extras, }); if (request.body && (isPlainObject(request.body) || isArray(request.body))) { @@ -101,10 +106,7 @@ export function buildRequest(options) { http, } = options; - let { - parameters, - parameterBuilders, - } = options; + let { parameters, parameterBuilders } = options; const specIsOAS3 = isOAS3(spec); if (!parameterBuilders) { @@ -117,7 +119,7 @@ export function buildRequest(options) { } // Set credentials with 'http.withCredentials' value - const credentials = (http && http.withCredentials) ? 'include' : 'same-origin'; + const credentials = http && http.withCredentials ? 'include' : 'same-origin'; // Base Template let req = { @@ -145,7 +147,13 @@ export function buildRequest(options) { const { operation = {}, method, pathName } = operationRaw; req.url += baseUrl({ - spec, scheme, contextUrl, server, serverVariables, pathName, method, + spec, + scheme, + contextUrl, + server, + serverVariables, + pathName, + method, }); // Mostly for testing @@ -159,7 +167,7 @@ export function buildRequest(options) { } req.url += pathName; // Have not yet replaced the path parameters - req.method = (`${method}`).toUpperCase(); + req.method = `${method}`.toUpperCase(); parameters = parameters || {}; const path = spec.paths[pathName] || {}; @@ -168,9 +176,11 @@ export function buildRequest(options) { req.headers.accept = responseContentType; } - const combinedParameters = deduplicateParameters([] - .concat(arrayOrEmpty(operation.parameters)) // operation parameters - .concat(arrayOrEmpty(path.parameters))); // path parameters + const combinedParameters = deduplicateParameters( + [] + .concat(arrayOrEmpty(operation.parameters)) // operation parameters + .concat(arrayOrEmpty(path.parameters)) + ); // path parameters // REVIEW: OAS3: have any key names or parameter shapes changed? // Any new features that need to be plugged in here? @@ -193,7 +203,9 @@ export function buildRequest(options) { // value came from `parameters[parameter.name]` // check to see if this is an ambiguous parameter // eslint-disable-next-line no-console - console.warn(`Parameter '${parameter.name}' is ambiguous because the defined spec has more than one parameter with the name: '${parameter.name}' and the passed-in parameter values did not define an 'in' value.`); + console.warn( + `Parameter '${parameter.name}' is ambiguous because the defined spec has more than one parameter with the name: '${parameter.name}' and the passed-in parameter values did not define an 'in' value.` + ); } if (value === null) { @@ -208,7 +220,12 @@ export function buildRequest(options) { throw new Error(`Required parameter ${parameter.name} is not provided`); } - if (specIsOAS3 && parameter.schema && parameter.schema.type === 'object' && typeof value === 'string') { + if ( + specIsOAS3 && + parameter.schema && + parameter.schema.type === 'object' && + typeof value === 'string' + ) { try { value = JSON.parse(value); } catch (e) { @@ -218,7 +235,11 @@ export function buildRequest(options) { if (builder) { builder({ - req, parameter, value, operation, spec, + req, + parameter, + value, + operation, + spec, }); } }); @@ -268,12 +289,11 @@ export function baseUrl(obj) { return specIsOAS3 ? oas3BaseUrl(obj) : swagger2BaseUrl(obj); } -function oas3BaseUrl({ - spec, pathName, method, server, contextUrl, serverVariables = {}, -}) { - const servers = getIn(spec, ['paths', pathName, (method || '').toLowerCase(), 'servers']) - || getIn(spec, ['paths', pathName, 'servers']) - || getIn(spec, ['servers']); +function oas3BaseUrl({ spec, pathName, method, server, contextUrl, serverVariables = {} }) { + const servers = + getIn(spec, ['paths', pathName, (method || '').toLowerCase(), 'servers']) || + getIn(spec, ['paths', pathName, 'servers']) || + getIn(spec, ['servers']); let selectedServerUrl = ''; let selectedServerObj = null; @@ -315,7 +335,8 @@ function buildOas3UrlWithContext(ourUrl = '', contextUrl = '') { const parsedUrl = url.parse(ourUrl); const parsedContextUrl = url.parse(contextUrl); - const computedScheme = stripNonAlpha(parsedUrl.protocol) || stripNonAlpha(parsedContextUrl.protocol) || ''; + const computedScheme = + stripNonAlpha(parsedUrl.protocol) || stripNonAlpha(parsedContextUrl.protocol) || ''; const computedHost = parsedUrl.host || parsedContextUrl.host; const computedPath = parsedUrl.pathname || ''; let res; @@ -337,7 +358,7 @@ function getVariableTemplateNames(str) { let text; // eslint-disable-next-line no-cond-assign - while (text = re.exec(str)) { + while ((text = re.exec(str))) { results.push(text[1]); } return results; @@ -348,7 +369,8 @@ function swagger2BaseUrl({ spec, scheme, contextUrl = '' }) { const parsedContextUrl = url.parse(contextUrl); const firstSchemeInSpec = Array.isArray(spec.schemes) ? spec.schemes[0] : null; - const computedScheme = scheme || firstSchemeInSpec || stripNonAlpha(parsedContextUrl.protocol) || 'http'; + const computedScheme = + scheme || firstSchemeInSpec || stripNonAlpha(parsedContextUrl.protocol) || 'http'; const computedHost = spec.host || parsedContextUrl.host || ''; const computedPath = spec.basePath || ''; let res; diff --git a/src/execute/oas3/build-request.js b/src/execute/oas3/build-request.js index ec119ca72..4929d1495 100644 --- a/src/execute/oas3/build-request.js +++ b/src/execute/oas3/build-request.js @@ -5,26 +5,21 @@ import get from 'lodash/get'; import btoa from 'btoa'; export default function buildRequest(options, req) { - const { - operation, - requestBody, - securities, - spec, - attachContentTypeForEmptyPayload, - } = options; + const { operation, requestBody, securities, spec, attachContentTypeForEmptyPayload } = options; - let { - requestContentType, - } = options; + let { requestContentType } = options; req = applySecurities({ - request: req, securities, operation, spec, + request: req, + securities, + operation, + spec, }); const requestBodyDef = operation.requestBody || {}; const requestBodyMediaTypes = Object.keys(requestBodyDef.content || {}); - const isExplicitContentTypeValid = requestContentType - && requestBodyMediaTypes.indexOf(requestContentType) > -1; + const isExplicitContentTypeValid = + requestContentType && requestBodyMediaTypes.indexOf(requestContentType) > -1; // for OAS3: set the Content-Type if (requestBody || attachContentTypeForEmptyPayload) { @@ -49,7 +44,10 @@ export default function buildRequest(options, req) { if (requestBodyMediaTypes.indexOf(requestContentType) > -1) { // only attach body if the requestBody has a definition for the // contentType that has been explicitly set - if (requestContentType === 'application/x-www-form-urlencoded' || requestContentType === 'multipart/form-data') { + if ( + requestContentType === 'application/x-www-form-urlencoded' || + requestContentType === 'multipart/form-data' + ) { if (typeof requestBody === 'object') { const encoding = (requestBodyDef.content[requestContentType] || {}).encoding || {}; @@ -77,9 +75,7 @@ export default function buildRequest(options, req) { // Add security values, to operations - that declare their need on them // Adapted from the Swagger2 implementation -export function applySecurities({ - request, securities = {}, operation = {}, spec, -}) { +export function applySecurities({ request, securities = {}, operation = {}, spec }) { const result = assign({}, request); const { authorized = {} } = securities; const security = operation.security || spec.security || []; @@ -89,8 +85,12 @@ export function applySecurities({ result.headers = result.headers || {}; result.query = result.query || {}; - if (!Object.keys(securities).length || !isAuthorized || !security - || (Array.isArray(operation.security) && !operation.security.length)) { + if ( + !Object.keys(securities).length || + !isAuthorized || + !security || + (Array.isArray(operation.security) && !operation.security.length) + ) { return request; } diff --git a/src/execute/oas3/parameter-builders.js b/src/execute/oas3/parameter-builders.js index a17053269..845df3448 100644 --- a/src/execute/oas3/parameter-builders.js +++ b/src/execute/oas3/parameter-builders.js @@ -1,21 +1,17 @@ import pick from 'lodash/pick'; + import stylize, { encodeDisallowedCharacters } from './style-serializer'; import serialize from './content-serializer'; export function path({ req, value, parameter }) { - const { - name, style, explode, content, - } = parameter; + const { name, style, explode, content } = parameter; if (content) { const effectiveMediaType = Object.keys(content)[0]; - req.url = req.url.split(`{${name}}`).join( - encodeDisallowedCharacters( - serialize(value, effectiveMediaType), - { escape: true }, - ), - ); + req.url = req.url + .split(`{${name}}`) + .join(encodeDisallowedCharacters(serialize(value, effectiveMediaType), { escape: true })); return; } @@ -60,11 +56,7 @@ export function query({ req, value, parameter }) { } } -const PARAMETER_HEADER_BLACKLIST = [ - 'accept', - 'authorization', - 'content-type', -]; +const PARAMETER_HEADER_BLACKLIST = ['accept', 'authorization', 'content-type']; export function header({ req, parameter, value }) { req.headers = req.headers || {}; @@ -103,18 +95,17 @@ export function cookie({ req, parameter, value }) { } if (type !== 'undefined') { - const prefix = ( - type === 'object' - && !Array.isArray(value) - && parameter.explode - ) ? '' : `${parameter.name}=`; - - req.headers.Cookie = prefix + stylize({ - key: parameter.name, - value, - escape: false, - style: parameter.style || 'form', - explode: typeof parameter.explode === 'undefined' ? false : parameter.explode, - }); + const prefix = + type === 'object' && !Array.isArray(value) && parameter.explode ? '' : `${parameter.name}=`; + + req.headers.Cookie = + prefix + + stylize({ + key: parameter.name, + value, + escape: false, + style: parameter.style || 'form', + explode: typeof parameter.explode === 'undefined' ? false : parameter.explode, + }); } } diff --git a/src/execute/oas3/style-serializer.js b/src/execute/oas3/style-serializer.js index 36202a967..71ee3060a 100644 --- a/src/execute/oas3/style-serializer.js +++ b/src/execute/oas3/style-serializer.js @@ -1,8 +1,8 @@ const { Buffer } = require('buffer'); -const isRfc3986Reserved = (char) => ':/?#[]@!$&\'()*+,;='.indexOf(char) > -1; +const isRfc3986Reserved = (char) => ":/?#[]@!$&'()*+,;=".indexOf(char) > -1; const isRrc3986Unreserved = (char) => { - return (/^[a-z0-9\-._~]+$/i).test(char); + return /^[a-z0-9\-._~]+$/i.test(char); }; export function encodeDisallowedCharacters(str, { escape } = {}, parse) { @@ -25,22 +25,24 @@ export function encodeDisallowedCharacters(str, { escape } = {}, parse) { // This causes the string iterator (another new ES6 feature) to be used internally, // and because that iterator is designed to deal with // code points rather than UCS-2/UTF-16 code units. - return [...str].map((char) => { - if (isRrc3986Unreserved(char)) { - return char; - } - - if (isRfc3986Reserved(char) && escape === 'unsafe') { - return char; - } - - const encoded = (Buffer.from(char).toJSON().data || []) - .map((byte) => `0${byte.toString(16).toUpperCase()}`.slice(-2)) - .map((encodedByte) => `%${encodedByte}`) - .join(''); - - return encoded; - }).join(''); + return [...str] + .map((char) => { + if (isRrc3986Unreserved(char)) { + return char; + } + + if (isRfc3986Reserved(char) && escape === 'unsafe') { + return char; + } + + const encoded = (Buffer.from(char).toJSON().data || []) + .map((byte) => `0${byte.toString(16).toUpperCase()}`.slice(-2)) + .map((encodedByte) => `%${encodedByte}`) + .join(''); + + return encoded; + }) + .join(''); } export default function stylize(config) { @@ -55,12 +57,11 @@ export default function stylize(config) { return encodePrimitive(config); } -function encodeArray({ - key, value, style, explode, escape, -}) { - const valueEncoder = (str) => encodeDisallowedCharacters(str, { - escape, - }); +function encodeArray({ key, value, style, explode, escape }) { + const valueEncoder = (str) => + encodeDisallowedCharacters(str, { + escape, + }); if (style === 'simple') { return value.map((val) => valueEncoder(val)).join(','); @@ -71,12 +72,14 @@ function encodeArray({ } if (style === 'matrix') { - return value.map((val) => valueEncoder(val)).reduce((prev, curr) => { - if (!prev || explode) { - return `${(prev || '')};${key}=${curr}`; - } - return `${prev},${curr}`; - }, ''); + return value + .map((val) => valueEncoder(val)) + .reduce((prev, curr) => { + if (!prev || explode) { + return `${prev || ''};${key}=${curr}`; + } + return `${prev},${curr}`; + }, ''); } if (style === 'form') { @@ -97,12 +100,11 @@ function encodeArray({ return undefined; } -function encodeObject({ - key, value, style, explode, escape, -}) { - const valueEncoder = (str) => encodeDisallowedCharacters(str, { - escape, - }); +function encodeObject({ key, value, style, explode, escape }) { + const valueEncoder = (str) => + encodeDisallowedCharacters(str, { + escape, + }); const valueKeys = Object.keys(value); @@ -158,12 +160,11 @@ function encodeObject({ return undefined; } -function encodePrimitive({ - key, value, style, escape, -}) { - const valueEncoder = (str) => encodeDisallowedCharacters(str, { - escape, - }); +function encodePrimitive({ key, value, style, escape }) { + const valueEncoder = (str) => + encodeDisallowedCharacters(str, { + escape, + }); if (style === 'simple') { return valueEncoder(value); diff --git a/src/execute/swagger2/build-request.js b/src/execute/swagger2/build-request.js index fff016fa0..b24e367f0 100644 --- a/src/execute/swagger2/build-request.js +++ b/src/execute/swagger2/build-request.js @@ -13,7 +13,10 @@ export default function buildRequest(options, req) { } = options; // Add securities, which are applicable req = applySecurities({ - request: req, securities, operation, spec, + request: req, + securities, + operation, + spec, }); if (req.body || req.form || attachContentTypeForEmptyPayload) { @@ -24,14 +27,22 @@ export default function buildRequest(options, req) { [req.headers['Content-Type']] = operation.consumes; } else if (Array.isArray(spec.consumes)) { [req.headers['Content-Type']] = spec.consumes; - } else if (operation.parameters && operation.parameters.filter((p) => p.type === 'file').length) { + } else if ( + operation.parameters && + operation.parameters.filter((p) => p.type === 'file').length + ) { req.headers['Content-Type'] = 'multipart/form-data'; - } else if (operation.parameters && operation.parameters.filter((p) => p.in === 'formData').length) { + } else if ( + operation.parameters && + operation.parameters.filter((p) => p.in === 'formData').length + ) { req.headers['Content-Type'] = 'application/x-www-form-urlencoded'; } } else if (requestContentType) { - const isBodyParamPresent = operation.parameters && operation.parameters.filter((p) => p.in === 'body').length > 0; - const isFormDataParamPresent = operation.parameters && operation.parameters.filter((p) => p.in === 'formData').length > 0; + const isBodyParamPresent = + operation.parameters && operation.parameters.filter((p) => p.in === 'body').length > 0; + const isFormDataParamPresent = + operation.parameters && operation.parameters.filter((p) => p.in === 'formData').length > 0; if (isBodyParamPresent || isFormDataParamPresent) { req.headers['Content-Type'] = requestContentType; } @@ -41,9 +52,7 @@ export default function buildRequest(options, req) { } // Add security values, to operations - that declare their need on them -export function applySecurities({ - request, securities = {}, operation = {}, spec, -}) { +export function applySecurities({ request, securities = {}, operation = {}, spec }) { const result = assign({}, request); const { authorized = {}, specSecurity = [] } = securities; const security = operation.security || specSecurity; @@ -53,8 +62,12 @@ export function applySecurities({ result.headers = result.headers || {}; result.query = result.query || {}; - if (!Object.keys(securities).length || !isAuthorized || !security - || (Array.isArray(operation.security) && !operation.security.length)) { + if ( + !Object.keys(securities).length || + !isAuthorized || + !security || + (Array.isArray(operation.security) && !operation.security.length) + ) { return request; } @@ -88,7 +101,7 @@ export function applySecurities({ result.headers.authorization = `Basic ${value.base64}`; } } else if (type === 'oauth2' && oauthToken) { - tokenType = (!tokenType || tokenType.toLowerCase() === 'bearer') ? 'Bearer' : tokenType; + tokenType = !tokenType || tokenType.toLowerCase() === 'bearer' ? 'Bearer' : tokenType; result.headers.authorization = `${tokenType} ${oauthToken}`; } } diff --git a/src/helpers.js b/src/helpers.js index 0bf552272..73612a506 100755 --- a/src/helpers.js +++ b/src/helpers.js @@ -40,8 +40,10 @@ export function opId(operation, pathName, method = '', { v2OperationIdCompatibil // Create a generated operationId from pathName + method export function idFromPathMethod(pathName, method, { v2OperationIdCompatibilityMode } = {}) { if (v2OperationIdCompatibilityMode) { - let res = `${method.toLowerCase()}_${pathName}` - .replace(/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g, '_'); + let res = `${method.toLowerCase()}_${pathName}`.replace( + /[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g, + '_' + ); res = res || `${pathName.substring(1)}_${method}`; @@ -72,8 +74,7 @@ export function getOperationRaw(spec, id) { const operationId = opId(operation, pathName, method); const legacyOperationId = legacyIdFromPathMethod(pathName, method); - return [operationId, legacyOperationId, rawOperationId] - .some((val) => val && val === id); + return [operationId, legacyOperationId, rawOperationId].some((val) => val && val === id); }); } @@ -184,7 +185,8 @@ export function normalizeSwagger(parsedSpec) { const toBeInherit = {}; // Global-levels - for (const key in spec) { // eslint-disable-line no-restricted-syntax + // eslint-disable-next-line no-restricted-syntax + for (const key in spec) { if (key === 'produces' || key === 'consumes' || key === 'security') { toBeInherit[key] = spec[key]; inheritsList.push(toBeInherit); @@ -198,18 +200,22 @@ export function normalizeSwagger(parsedSpec) { } if (inheritsList.length) { - for (const inherits of inheritsList) { // eslint-disable-line no-restricted-syntax - for (const inheritName in inherits) { // eslint-disable-line no-restricted-syntax + // eslint-disable-next-line no-restricted-syntax + for (const inherits of inheritsList) { + // eslint-disable-next-line no-restricted-syntax + for (const inheritName in inherits) { if (!operation[inheritName]) { operation[inheritName] = inherits[inheritName]; } else if (inheritName === 'parameters') { // eslint-disable-next-line no-restricted-syntax for (const param of inherits[inheritName]) { const exists = operation[inheritName].some((opParam) => { - return (opParam.name && opParam.name === param.name) - || (opParam.$ref && opParam.$ref === param.$ref) - || (opParam.$$ref && opParam.$$ref === param.$$ref) - || (opParam === param); + return ( + (opParam.name && opParam.name === param.name) || + (opParam.$ref && opParam.$ref === param.$ref) || + (opParam.$$ref && opParam.$$ref === param.$$ref) || + opParam === param + ); }); if (!exists) { diff --git a/src/http.js b/src/http.js index a61e02674..9fbfe7cb5 100644 --- a/src/http.js +++ b/src/http.js @@ -4,6 +4,7 @@ import jsYaml from 'js-yaml'; import pick from 'lodash/pick'; import isFunction from 'lodash/isFunction'; import { Buffer } from 'buffer'; + import FormData from './internal/form-data-monkey-patch'; import { encodeDisallowedCharacters } from './execute/oas3/style-serializer'; @@ -45,7 +46,7 @@ export default async function http(url, request = {}) { // WARNING: don't put anything between this and the request firing unless // you have a good reason! if (request.requestInterceptor) { - request = await request.requestInterceptor(request) || request; + request = (await request.requestInterceptor(request)) || request; } // for content-type=multipart\/form-data remove content-type from request before fetch @@ -62,7 +63,7 @@ export default async function http(url, request = {}) { res = await (request.userFetch || fetch)(request.url, request); res = await self.serializeRes(res, url, request); if (request.responseInterceptor) { - res = await request.responseInterceptor(res) || res; + res = (await request.responseInterceptor(res)) || res; } } catch (resError) { if (!res) { @@ -87,10 +88,14 @@ export default async function http(url, request = {}) { } // exported for testing -export const shouldDownloadAsText = (contentType = '') => /(json|xml|yaml|text)\b/.test(contentType); +export const shouldDownloadAsText = (contentType = '') => + /(json|xml|yaml|text)\b/.test(contentType); function parseBody(body, contentType) { - if (contentType && (contentType.indexOf('application/json') === 0 || contentType.indexOf('+json') > 0)) { + if ( + contentType && + (contentType.indexOf('application/json') === 0 || contentType.indexOf('+json') > 0) + ) { return JSON.parse(body); } return jsYaml.safeLoad(body); @@ -107,7 +112,7 @@ export function serializeRes(oriRes, url, { loadSpec = false } = {}) { }; const contentType = res.headers['content-type']; const useText = loadSpec || shouldDownloadAsText(contentType); - const getBody = useText ? oriRes.text : (oriRes.blob || oriRes.buffer); + const getBody = useText ? oriRes.text : oriRes.blob || oriRes.buffer; return getBody.call(oriRes).then((body) => { res.text = body; res.data = body; @@ -138,12 +143,10 @@ function serializeHeaderValue(value) { export function serializeHeaders(headers = {}) { if (!isFunction(headers.entries)) return {}; - return Array - .from(headers.entries()) - .reduce((acc, [header, value]) => { - acc[header] = serializeHeaderValue(value); - return acc; - }, {}); + return Array.from(headers.entries()).reduce((acc, [header, value]) => { + acc[header] = serializeHeaderValue(value); + return acc; + }, {}); } export function isFile(obj, navigatorObj) { @@ -158,10 +161,12 @@ export function isFile(obj, navigatorObj) { return false; } - if (typeof File !== 'undefined' && obj instanceof File) { // eslint-disable-line no-undef + if (typeof File !== 'undefined' && obj instanceof File) { + // eslint-disable-line no-undef return true; } - if (typeof Blob !== 'undefined' && obj instanceof Blob) { // eslint-disable-line no-undef + if (typeof Blob !== 'undefined' && obj instanceof Blob) { + // eslint-disable-line no-undef return true; } if (typeof Buffer !== 'undefined' && obj instanceof Buffer) { @@ -172,7 +177,7 @@ export function isFile(obj, navigatorObj) { } function isArrayOfFile(obj, navigatorObj) { - return (Array.isArray(obj) && obj.some((v) => isFile(v, navigatorObj))); + return Array.isArray(obj) && obj.some((v) => isFile(v, navigatorObj)); } const STYLE_SEPARATORS = { @@ -197,12 +202,10 @@ const SEPARATORS = { // Return value example 5: [['R', '100'], ['G', '200'], ['B', '150']] // Return value example 6: [['color[R]', '100'], ['color[G]', '200'], ['color[B]', '150']] function formatKeyValue(key, input, skipEncoding = false) { - const { - collectionFormat, allowEmptyValue, serializationOption, encoding, - } = input; + const { collectionFormat, allowEmptyValue, serializationOption, encoding } = input; // `input` can be string - const value = (typeof input === 'object' && !Array.isArray(input)) ? input.value : input; - const encodeFn = skipEncoding ? ((k) => k.toString()) : ((k) => encodeURIComponent(k)); + const value = typeof input === 'object' && !Array.isArray(input) ? input.value : input; + const encodeFn = skipEncoding ? (k) => k.toString() : (k) => encodeURIComponent(k); const encodedKey = encodeFn(key); if (typeof value === 'undefined' && allowEmptyValue) { @@ -221,8 +224,17 @@ function formatKeyValue(key, input, skipEncoding = false) { // for OAS 3 Encoding Object if (encoding) { - if ([typeof encoding.style, typeof encoding.explode, typeof encoding.allowReserved].some((type) => type !== 'undefined')) { - return formatKeyValueBySerializationOption(key, value, skipEncoding, pick(encoding, ['style', 'explode', 'allowReserved'])); + if ( + [typeof encoding.style, typeof encoding.explode, typeof encoding.allowReserved].some( + (type) => type !== 'undefined' + ) + ) { + return formatKeyValueBySerializationOption( + key, + value, + skipEncoding, + pick(encoding, ['style', 'explode', 'allowReserved']) + ); } if (encoding.contentType) { @@ -271,12 +283,18 @@ function formatKeyValue(key, input, skipEncoding = false) { function formatKeyValueBySerializationOption(key, value, skipEncoding, serializationOption) { const style = serializationOption.style || 'form'; - const explode = typeof serializationOption.explode === 'undefined' ? style === 'form' : serializationOption.explode; + const explode = + typeof serializationOption.explode === 'undefined' + ? style === 'form' + : serializationOption.explode; // eslint-disable-next-line no-nested-ternary - const escape = skipEncoding ? false : (serializationOption && serializationOption.allowReserved ? 'unsafe' : 'reserved'); + const escape = skipEncoding + ? false + : serializationOption && serializationOption.allowReserved + ? 'unsafe' + : 'reserved'; const encodeFn = (v) => encodeDisallowedCharacters(v, { escape }); - const encodeKeyFn = skipEncoding - ? ((k) => k) : ((k) => encodeDisallowedCharacters(k, { escape })); + const encodeKeyFn = skipEncoding ? (k) => k : (k) => encodeDisallowedCharacters(k, { escape }); // Primitive if (typeof value !== 'object') { @@ -295,14 +313,24 @@ function formatKeyValueBySerializationOption(key, value, skipEncoding, serializa // Object if (style === 'deepObject') { - return Object.keys(value).map((valueKey) => [encodeKeyFn(`${key}[${valueKey}]`), encodeFn(value[valueKey])]); + return Object.keys(value).map((valueKey) => [ + encodeKeyFn(`${key}[${valueKey}]`), + encodeFn(value[valueKey]), + ]); } if (explode) { return Object.keys(value).map((valueKey) => [encodeKeyFn(valueKey), encodeFn(value[valueKey])]); } - return [[encodeKeyFn(key), Object.keys(value).map((valueKey) => [`${encodeKeyFn(valueKey)},${encodeFn(value[valueKey])}`]).join(',')]]; + return [ + [ + encodeKeyFn(key), + Object.keys(value) + .map((valueKey) => [`${encodeKeyFn(valueKey)},${encodeFn(value[valueKey])}`]) + .join(','), + ], + ]; } function buildFormData(reqForm) { @@ -317,7 +345,8 @@ function buildFormData(reqForm) { // eslint-disable-next-line no-restricted-syntax for (const [key, value] of formatKeyValue(name, input, true)) { if (Array.isArray(value)) { - for (const v of value) { // eslint-disable-line no-restricted-syntax + // eslint-disable-next-line no-restricted-syntax + for (const v of value) { formData.append(key, v); } } else { @@ -369,7 +398,7 @@ export function mergeInQueryOrForm(req = {}) { req.body = encodeFormOrQuery(form); } - delete (req.form); + delete req.form; } if (query) { @@ -385,7 +414,7 @@ export function mergeInQueryOrForm(req = {}) { const finalStr = joinSearch(newStr, encodeFormOrQuery(query)); req.url = baseUrl + finalStr; - delete (req.query); + delete req.query; } return req; } diff --git a/src/index.js b/src/index.js index 0dad4ad30..f17b4d622 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import assign from 'lodash/assign'; import startsWith from 'lodash/startsWith'; import Url from 'url'; + import Http, { makeHttp, serializeRes, serializeHeaders } from './http'; import Resolver, { clearCache } from './resolver'; import resolveSubtree from './subtree-resolver'; @@ -35,13 +36,12 @@ function Swagger(url, opts = {}) { assign(this, opts); - const prom = this.resolve() - .then(() => { - if (!this.disableInterfaces) { - assign(this, Swagger.makeApisTagOperation(this)); - } - return this; - }); + const prom = this.resolve().then(() => { + if (!this.disableInterfaces) { + assign(this, Swagger.makeApisTagOperation(this)); + } + return this; + }); // Expose this instance on the promise that gets returned prom.client = this; @@ -49,7 +49,6 @@ function Swagger(url, opts = {}) { } Swagger.prototype = { - http: Http, execute(options) { diff --git a/src/interfaces.js b/src/interfaces.js index 9e0c47373..860c7cb67 100644 --- a/src/interfaces.js +++ b/src/interfaces.js @@ -1,4 +1,5 @@ import pick from 'lodash/pick'; + import { eachOperation, opId } from './helpers'; const nullFn = () => null; @@ -78,7 +79,10 @@ export function makeApisTagOperation(swaggerJs = {}) { * */ export function mapTagOperations({ - spec, cb = nullFn, defaultTag = 'default', v2OperationIdCompatibilityMode, + spec, + cb = nullFn, + defaultTag = 'default', + v2OperationIdCompatibilityMode, }) { const operationIdCounter = {}; const tagOperations = {}; // Will house all tags + operations @@ -93,7 +97,11 @@ export function mapTagOperations({ const tagObj = tagOperations[tag]; const id = opId(operation, pathName, method, { v2OperationIdCompatibilityMode }); const cbResult = cb({ - spec, pathName, method, operation, operationId: id, + spec, + pathName, + method, + operation, + operationId: id, }); if (operationIdCounter[id]) { @@ -101,7 +109,7 @@ export function mapTagOperations({ tagObj[`${id}${operationIdCounter[id]}`] = cbResult; } else if (typeof tagObj[id] !== 'undefined') { // Bump counter ( for this operationId ) - const originalCounterValue = (operationIdCounter[id] || 1); + const originalCounterValue = operationIdCounter[id] || 1; operationIdCounter[id] = originalCounterValue + 1; // Append _x to the operationId tagObj[`${id}${operationIdCounter[id]}`] = cbResult; diff --git a/src/internal/form-data-monkey-patch.js b/src/internal/form-data-monkey-patch.js index ddf1bb736..d9c3e634f 100644 --- a/src/internal/form-data-monkey-patch.js +++ b/src/internal/form-data-monkey-patch.js @@ -15,10 +15,10 @@ export const patch = (FormData) => { * monkey-patch code should then compensate the library changes easily. */ if ( - isFunction(FormData.prototype.set) - || isFunction(FormData.prototype.get) - || isFunction(FormData.prototype.getAll) - || isFunction(FormData.prototype.has) + isFunction(FormData.prototype.set) || + isFunction(FormData.prototype.get) || + isFunction(FormData.prototype.getAll) || + isFunction(FormData.prototype.has) ) { return FormData; } diff --git a/src/resolver.js b/src/resolver.js index ca94ac047..50a7a3981 100644 --- a/src/resolver.js +++ b/src/resolver.js @@ -6,7 +6,7 @@ import { ACCEPT_HEADER_VALUE_FOR_DOCUMENTS } from './constants'; export function makeFetchJSON(http, opts = {}) { const { requestInterceptor, responseInterceptor } = opts; // Set credentials with 'http.withCredentials' value - const credentials = (http.withCredentials) ? 'include' : 'same-origin'; + const credentials = http.withCredentials ? 'include' : 'same-origin'; return (docPath) => { return http({ url: docPath, @@ -17,10 +17,9 @@ export function makeFetchJSON(http, opts = {}) { Accept: ACCEPT_HEADER_VALUE_FOR_DOCUMENTS, }, credentials, - }) - .then((res) => { - return res.body; - }); + }).then((res) => { + return res.body; + }); }; } @@ -31,9 +30,18 @@ export function clearCache() { export default function resolve(obj) { const { - fetch, spec, url, mode, allowMetaPatches = true, pathDiscriminator, - modelPropertyMacro, parameterMacro, requestInterceptor, - responseInterceptor, skipNormalization, useCircularStructures, + fetch, + spec, + url, + mode, + allowMetaPatches = true, + pathDiscriminator, + modelPropertyMacro, + parameterMacro, + requestInterceptor, + responseInterceptor, + skipNormalization, + useCircularStructures, } = obj; let { http, baseDoc } = obj; @@ -47,8 +55,9 @@ export default function resolve(obj) { http = fetch || http || Http; if (!spec) { - return makeFetchJSON(http, { requestInterceptor, responseInterceptor })(baseDoc) - .then(doResolve); + return makeFetchJSON(http, { requestInterceptor, responseInterceptor })(baseDoc).then( + doResolve + ); } return doResolve(spec); diff --git a/src/specmap/helpers.js b/src/specmap/helpers.js index be23cef0f..7eb24d2ca 100644 --- a/src/specmap/helpers.js +++ b/src/specmap/helpers.js @@ -2,15 +2,11 @@ import traverse from 'traverse'; import URL from 'url'; // This will match if the direct parent's key exactly matches an item. -const freelyNamedKeyParents = [ - 'properties', -]; +const freelyNamedKeyParents = ['properties']; // This will match if the grandparent's key exactly matches an item. // NOTE that this is for finding non-free paths! -const nonFreelyNamedKeyGrandparents = [ - 'properties', -]; +const nonFreelyNamedKeyGrandparents = ['properties']; // This will match if the joined parent path exactly matches an item. // @@ -34,10 +30,7 @@ const freelyNamedPaths = [ // parent path. // // Warning! These are powerful. Beware of edge cases. -const freelyNamedAncestors = [ - 'schema/example', - 'items/example', -]; +const freelyNamedAncestors = ['schema/example', 'items/example']; export function isFreelyNamed(parentPath) { const parentKey = parentPath[parentPath.length - 1]; @@ -46,17 +39,22 @@ export function isFreelyNamed(parentPath) { return ( // eslint-disable-next-line max-len - (freelyNamedKeyParents.indexOf(parentKey) > -1 && nonFreelyNamedKeyGrandparents.indexOf(grandparentKey) === -1) - || (freelyNamedPaths.indexOf(parentStr) > -1) - || (freelyNamedAncestors.some((el) => parentStr.indexOf(el) > -1)) + (freelyNamedKeyParents.indexOf(parentKey) > -1 && + nonFreelyNamedKeyGrandparents.indexOf(grandparentKey) === -1) || + freelyNamedPaths.indexOf(parentStr) > -1 || + freelyNamedAncestors.some((el) => parentStr.indexOf(el) > -1) ); } -export function generateAbsoluteRefPatches(obj, basePath, { - specmap, - getBaseUrlForNodePath = (path) => specmap.getContext([...basePath, ...path]).baseDoc, - targetKeys = ['$ref', '$$ref'], -} = {}) { +export function generateAbsoluteRefPatches( + obj, + basePath, + { + specmap, + getBaseUrlForNodePath = (path) => specmap.getContext([...basePath, ...path]).baseDoc, + targetKeys = ['$ref', '$$ref'], + } = {} +) { const patches = []; traverse(obj).forEach(function callback() { diff --git a/src/specmap/index.js b/src/specmap/index.js index 81af1a236..501bbbb54 100644 --- a/src/specmap/index.js +++ b/src/specmap/index.js @@ -20,35 +20,37 @@ class SpecMap { } constructor(opts) { - Object.assign(this, { - spec: '', - debugLevel: 'info', - plugins: [], - pluginHistory: {}, - errors: [], - mutations: [], - promisedPatches: [], - state: {}, - patches: [], - context: {}, - contextTree: new ContextTree(), - showDebug: false, - allPatches: [], // only populated if showDebug is true - pluginProp: 'specMap', - libMethods: Object.assign(Object.create(this), lib, { - getInstance: () => this, - }), - allowMetaPatches: false, - }, opts); + Object.assign( + this, + { + spec: '', + debugLevel: 'info', + plugins: [], + pluginHistory: {}, + errors: [], + mutations: [], + promisedPatches: [], + state: {}, + patches: [], + context: {}, + contextTree: new ContextTree(), + showDebug: false, + allPatches: [], // only populated if showDebug is true + pluginProp: 'specMap', + libMethods: Object.assign(Object.create(this), lib, { + getInstance: () => this, + }), + allowMetaPatches: false, + }, + opts + ); // Lib methods bound this.get = this._get.bind(this); // eslint-disable-line no-underscore-dangle this.getContext = this._getContext.bind(this); // eslint-disable-line no-underscore-dangle this.hasRun = this._hasRun.bind(this); // eslint-disable-line no-underscore-dangle - this.wrappedPlugins = this.plugins - .map(this.wrapPlugin.bind(this)) - .filter(lib.isFunction); + this.wrappedPlugins = this.plugins.map(this.wrapPlugin.bind(this)).filter(lib.isFunction); // Initial patch(s) this.patches.push(lib.add([], this.spec)); @@ -119,7 +121,8 @@ class SpecMap { const parentIndex = path.length - 1; const parent = path[parentIndex]; const indexOfFirstProperties = path.indexOf('properties'); - const isRootProperties = parent === 'properties' && parentIndex === indexOfFirstProperties; + const isRootProperties = + parent === 'properties' && parentIndex === indexOfFirstProperties; const traversed = specmap.allowMetaPatches && refCache[obj.$$ref]; // eslint-disable-next-line no-restricted-syntax @@ -247,7 +250,7 @@ class SpecMap { removePromisedPatch(patch) { const index = this.promisedPatches.indexOf(patch); if (index < 0) { - this.debug('Tried to remove a promisedPatch that isn\'t there!'); + this.debug("Tried to remove a promisedPatch that isn't there!"); return; } this.promisedPatches.splice(index, 1); @@ -292,11 +295,13 @@ class SpecMap { return this.libMethods; } - _get(path) { // eslint-disable-line no-underscore-dangle + // eslint-disable-next-line no-underscore-dangle + _get(path) { return lib.getIn(this.state, path); } - _getContext(path) { // eslint-disable-line no-underscore-dangle + // eslint-disable-next-line no-underscore-dangle + _getContext(path) { return this.contextTree.get(path); } @@ -304,7 +309,8 @@ class SpecMap { return this.contextTree.set(path, value); } - _hasRun(count) { // eslint-disable-line no-underscore-dangle + // eslint-disable-next-line no-underscore-dangle + _hasRun(count) { const times = this.getPluginRunCount(this.getCurrentPlugin()); return times > (count || 0); } @@ -316,9 +322,7 @@ class SpecMap { if (!plugin) { const nextPromise = this.nextPromisedPatch(); if (nextPromise) { - return nextPromise - .then(() => this.dispatch()) - .catch(() => this.dispatch()); + return nextPromise.then(() => this.dispatch()).catch(() => this.dispatch()); } // We're done! @@ -335,7 +339,9 @@ class SpecMap { if (that.pluginCount[plugin] > HARD_LIMIT) { return Promise.resolve({ spec: that.state, - errors: that.errors.concat(new Error(`We've reached a hard limit of ${HARD_LIMIT} plugin runs`)), + errors: that.errors.concat( + new Error(`We've reached a hard limit of ${HARD_LIMIT} plugin runs`) + ), }); } @@ -344,9 +350,11 @@ class SpecMap { const promises = this.promisedPatches.map((p) => p.value); // Waits for all to settle instead of Promise.all which stops on rejection - return Promise.all(promises.map((promise) => { - return promise.then(noop, noop); - })).then(() => this.dispatch()); + return Promise.all( + promises.map((promise) => { + return promise.then(noop, noop); + }) + ).then(() => this.dispatch()); } // Ok, run the plugin @@ -391,6 +399,9 @@ export default function mapSpec(opts) { } const plugins = { - refs, allOf, parameters, properties, + refs, + allOf, + parameters, + properties, }; export { SpecMap, plugins }; diff --git a/src/specmap/lib/context-tree.js b/src/specmap/lib/context-tree.js index 6338f289c..a3fb7b7e8 100644 --- a/src/specmap/lib/context-tree.js +++ b/src/specmap/lib/context-tree.js @@ -78,9 +78,7 @@ function createNode(value, parent) { function updateNode(node, value, parent) { node.value = value || {}; - node.protoValue = parent - ? { ...parent.protoValue, ...node.value } - : node.value; + node.protoValue = parent ? { ...parent.protoValue, ...node.value } : node.value; Object.keys(node.children).forEach((prop) => { const child = node.children[prop]; diff --git a/src/specmap/lib/create-error.js b/src/specmap/lib/create-error.js index 7cc2d7632..774450a3f 100644 --- a/src/specmap/lib/create-error.js +++ b/src/specmap/lib/create-error.js @@ -1,7 +1,7 @@ export default function createErrorType(name, init) { function E(...args) { if (!Error.captureStackTrace) { - this.stack = (new Error()).stack; + this.stack = new Error().stack; } else { Error.captureStackTrace(this, this.constructor); } diff --git a/src/specmap/lib/index.js b/src/specmap/lib/index.js index 6440fe2d7..249d7b02c 100644 --- a/src/specmap/lib/index.js +++ b/src/specmap/lib/index.js @@ -55,7 +55,8 @@ function applyPatch(obj, patch, opts) { // If it's an object, iterate it's keys and merge // if there are conflicting keys, merge deep, otherwise shallow merge let currentObj = { ...currentValue[prop] }; - for (const key in propVal) { // eslint-disable-line no-restricted-syntax + // eslint-disable-next-line no-restricted-syntax + for (const key in propVal) { if (Object.prototype.hasOwnProperty.call(currentObj, key)) { // if there is a single conflicting key, just deepExtend the entire value // and break from the loop (since all future keys are also merged) @@ -82,22 +83,25 @@ function applyPatch(obj, patch, opts) { // so let's break that patch down into a set of patches, // one for each key in the intended root value. - const patches = Object.keys(patch.value) - .reduce((arr, key) => { - arr.push({ - op: 'add', - path: `/${normalizeJSONPath(key)}`, - value: patch.value[key], - }); - return arr; - }, []); + const patches = Object.keys(patch.value).reduce((arr, key) => { + arr.push({ + op: 'add', + path: `/${normalizeJSONPath(key)}`, + value: patch.value[key], + }); + return arr; + }, []); jsonPatch.applyPatch(obj, patches); } else if (patch.op === 'replace' && patch.path === '') { let { value } = patch; - if (opts.allowMetaPatches && patch.meta && isAdditiveMutation(patch) - && (Array.isArray(patch.value) || isObject(patch.value))) { + if ( + opts.allowMetaPatches && + patch.meta && + isAdditiveMutation(patch) && + (Array.isArray(patch.value) || isObject(patch.value)) + ) { value = { ...value, ...patch.meta }; } obj = value; @@ -105,8 +109,12 @@ function applyPatch(obj, patch, opts) { jsonPatch.applyPatch(obj, [patch]); // Attach metadata to the resulting value. - if (opts.allowMetaPatches && patch.meta && isAdditiveMutation(patch) - && (Array.isArray(patch.value) || isObject(patch.value))) { + if ( + opts.allowMetaPatches && + patch.meta && + isAdditiveMutation(patch) && + (Array.isArray(patch.value) || isObject(patch.value)) + ) { const currentValue = getInByJsonPath(obj, patch.path); const newValue = { ...currentValue, ...patch.meta }; jsonPatch.applyPatch(obj, [replace(patch.path, newValue)]); @@ -122,9 +130,12 @@ function normalizeJSONPath(path) { return ''; } - return '/' + path.map((item) => { // eslint-disable-line prefer-template - return (item + '').replace(/~/g, '~0').replace(/\//g, '~1'); // eslint-disable-line prefer-template - }).join('/'); + return `/${path + .map((item) => { + // eslint-disable-line prefer-template + return (item + '').replace(/~/g, '~0').replace(/\//g, '~1'); // eslint-disable-line prefer-template + }) + .join('/')}`; } return path; @@ -144,7 +155,10 @@ function add(path, value) { function replace(path, value, meta) { return { - op: 'replace', path, value, meta, + op: 'replace', + path, + value, + meta, }; } @@ -155,14 +169,20 @@ function remove(path) { // Custom wrappers function merge(path, value) { return { - type: 'mutation', op: 'merge', path, value, + type: 'mutation', + op: 'merge', + path, + value, }; } // Custom wrappers function mergeDeep(path, value) { return { - type: 'mutation', op: 'mergeDeep', path, value, + type: 'mutation', + op: 'mergeDeep', + path, + value, }; } @@ -191,9 +211,10 @@ function forEachNewPrimitive(mutations, fn) { } function forEachNewPatch(mutations, fn, callback) { - const res = mutations.filter(isAdditiveMutation).map((mutation) => { - return fn(mutation.value, callback, mutation.path); - }) || []; + const res = + mutations.filter(isAdditiveMutation).map((mutation) => { + return fn(mutation.value, callback, mutation.path); + }) || []; const flat = flatten(res); const clean = cleanArray(flat); return clean; @@ -288,9 +309,11 @@ function normalizeArray(arr) { } function flatten(arr) { - return [].concat(...arr.map((val) => { - return Array.isArray(val) ? flatten(val) : val; - })); + return [].concat( + ...arr.map((val) => { + return Array.isArray(val) ? flatten(val) : val; + }) + ); } function cleanArray(arr) { @@ -334,7 +357,13 @@ function isMutation(patch) { } function isAdditiveMutation(patch) { - return isMutation(patch) && (patch.op === 'add' || patch.op === 'replace' || patch.op === 'merge' || patch.op === 'mergeDeep'); + return ( + isMutation(patch) && + (patch.op === 'add' || + patch.op === 'replace' || + patch.op === 'merge' || + patch.op === 'mergeDeep') + ); } function isContextPatch(patch) { diff --git a/src/specmap/lib/refs.js b/src/specmap/lib/refs.js index ed6abf6c3..462c9f273 100644 --- a/src/specmap/lib/refs.js +++ b/src/specmap/lib/refs.js @@ -2,6 +2,7 @@ import { fetch } from 'cross-fetch'; import jsYaml from 'js-yaml'; import qs from 'querystring-browser'; import url from 'url'; + import lib from '.'; import createError from './create-error'; import { isFreelyNamed, absolutifyPointer } from '../helpers'; @@ -18,22 +19,20 @@ const docCache = {}; const specmapRefs = new WeakMap(); const skipResolutionTestFns = [ - (path) => ( + (path) => // OpenAPI 3.0 Response Media Type Example // ["paths", *, *, "responses", *, "content", *, "example"] - path[0] === 'paths' - && path[3] === 'responses' - && path[5] === 'content' - && path[7] === 'example' - ), - (path) => ( + path[0] === 'paths' && + path[3] === 'responses' && + path[5] === 'content' && + path[7] === 'example', + (path) => // OpenAPI 3.0 Request Body Media Type Example // ["paths", *, *, "responses", *, "content", *, "example"] - path[0] === 'paths' - && path[3] === 'requestBody' - && path[4] === 'content' - && path[6] === 'example' - ), + path[0] === 'paths' && + path[3] === 'requestBody' && + path[4] === 'content' && + path[6] === 'example', ]; const shouldSkipResolution = (path) => skipResolutionTestFns.some((fn) => fn(path)); @@ -86,7 +85,7 @@ const plugin = { let basePath; try { - basePath = (baseDoc || refPath) ? absoluteify(refPath, baseDoc) : null; + basePath = baseDoc || refPath ? absoluteify(refPath, baseDoc) : null; } catch (e) { return wrapError(e, { pointer, @@ -130,7 +129,8 @@ const plugin = { } } else { promOrVal = extractFromDoc(basePath, pointer); - if (promOrVal.__value != null) { // eslint-disable-line no-underscore-dangle + // eslint-disable-next-line no-underscore-dangle + if (promOrVal.__value != null) { promOrVal = promOrVal.__value; // eslint-disable-line no-underscore-dangle } else { promOrVal = promOrVal.catch((e) => { @@ -205,7 +205,9 @@ export default mod; function absoluteify(path, basePath) { if (!ABSOLUTE_URL_REGEXP.test(path)) { if (!basePath) { - throw new JSONRefError(`Tried to resolve a relative URL, without having a basePath. path: '${path}' basePath: '${basePath}'`); + throw new JSONRefError( + `Tried to resolve a relative URL, without having a basePath. path: '${path}' basePath: '${basePath}'` + ); } return url.resolve(basePath, path); } @@ -329,7 +331,9 @@ function extract(pointer, obj) { const val = lib.getIn(obj, tokens); if (typeof val === 'undefined') { - throw new JSONRefError(`Could not resolve pointer: ${pointer} does not exist in document`, { pointer }); + throw new JSONRefError(`Could not resolve pointer: ${pointer} does not exist in document`, { + pointer, + }); } return val; } @@ -391,9 +395,11 @@ function pointerIsAParent(pointer, parentPointer) { const nextChar = pointer.charAt(parentPointer.length); const lastParentChar = parentPointer.slice(-1); - return pointer.indexOf(parentPointer) === 0 - && (!nextChar || nextChar === '/' || nextChar === '#') - && lastParentChar !== '#'; + return ( + pointer.indexOf(parentPointer) === 0 && + (!nextChar || nextChar === '/' || nextChar === '#') && + lastParentChar !== '#' + ); } // ========================= @@ -443,12 +449,15 @@ function pointerAlreadyInPath(pointer, basePath, parent, specmap) { let currPath = ''; const hasIndirectCycle = parent.some((token) => { currPath = `${currPath}/${escapeJsonPointerToken(token)}`; - return refs[currPath] && refs[currPath].some((ref) => { - return ( - pointerIsAParent(ref, fullyQualifiedPointer) - || pointerIsAParent(fullyQualifiedPointer, ref) - ); - }); + return ( + refs[currPath] && + refs[currPath].some((ref) => { + return ( + pointerIsAParent(ref, fullyQualifiedPointer) || + pointerIsAParent(fullyQualifiedPointer, ref) + ); + }) + ); }); if (hasIndirectCycle) { return true; @@ -474,8 +483,12 @@ function patchValueAlreadyInPath(root, patch) { return pointToAncestor(patch.value); function pointToAncestor(obj) { - return lib.isObject(obj) && (ancestors.indexOf(obj) >= 0 || Object.keys(obj).some((k) => { - return pointToAncestor(obj[k]); - })); + return ( + lib.isObject(obj) && + (ancestors.indexOf(obj) >= 0 || + Object.keys(obj).some((k) => { + return pointToAncestor(obj[k]); + })) + ); } } diff --git a/src/subtree-resolver/index.js b/src/subtree-resolver/index.js index 887a57b9d..9fcf3ccc0 100644 --- a/src/subtree-resolver/index.js +++ b/src/subtree-resolver/index.js @@ -22,6 +22,7 @@ // TODO: move the remarks above into project documentation import get from 'lodash/get'; + import resolve from '../resolver'; import { normalizeSwagger } from '../helpers'; diff --git a/test/.eslintrc b/test/.eslintrc index 0dfdac53e..16006fff5 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -2,6 +2,10 @@ "env": { "jest": true }, + "globals": { + "fetch": true, + "Response": true + }, "rules": { "global-require": 0, // needs to be eliminated in future "import/no-dynamic-require": 0, diff --git a/test/bugs/editor-1661.js b/test/bugs/editor-1661.js index 59677ccea..d8ac07a75 100644 --- a/test/bugs/editor-1661.js +++ b/test/bugs/editor-1661.js @@ -44,35 +44,32 @@ const spec = { }, }; -test( - 'should resolve a deeply-nested $ref series correctly', - async () => { - const res = await Swagger.resolve({ - spec, - }); +test('should resolve a deeply-nested $ref series correctly', async () => { + const res = await Swagger.resolve({ + spec, + }); - expect(res).toEqual({ - errors: [], - spec: { - $$normalized: true, - paths: { - '/path1': { - get: { - responses: { - 200: { - schema: { - $$ref: '#/definitions/DataObjectArray', - items: { - $$ref: '#/definitions/DataObject', - properties: { - modifiers: { - $$ref: '#/definitions/DataModifiers', - items: { - $$ref: '#/definitions/DataModifier', - properties: { - prop1: { - type: 'string', - }, + expect(res).toEqual({ + errors: [], + spec: { + $$normalized: true, + paths: { + '/path1': { + get: { + responses: { + 200: { + schema: { + $$ref: '#/definitions/DataObjectArray', + items: { + $$ref: '#/definitions/DataObject', + properties: { + modifiers: { + $$ref: '#/definitions/DataModifiers', + items: { + $$ref: '#/definitions/DataModifier', + properties: { + prop1: { + type: 'string', }, }, }, @@ -84,8 +81,26 @@ test( }, }, }, - definitions: { - DataObject: { + }, + definitions: { + DataObject: { + properties: { + modifiers: { + $$ref: '#/definitions/DataModifiers', + items: { + $$ref: '#/definitions/DataModifier', + properties: { + prop1: { + type: 'string', + }, + }, + }, + }, + }, + }, + DataObjectArray: { + items: { + $$ref: '#/definitions/DataObject', properties: { modifiers: { $$ref: '#/definitions/DataModifiers', @@ -100,43 +115,25 @@ test( }, }, }, - DataObjectArray: { - items: { - $$ref: '#/definitions/DataObject', - properties: { - modifiers: { - $$ref: '#/definitions/DataModifiers', - items: { - $$ref: '#/definitions/DataModifier', - properties: { - prop1: { - type: 'string', - }, - }, - }, - }, - }, + }, + DataModifier: { + properties: { + prop1: { + type: 'string', }, }, - DataModifier: { + }, + DataModifiers: { + items: { + $$ref: '#/definitions/DataModifier', properties: { prop1: { type: 'string', }, }, }, - DataModifiers: { - items: { - $$ref: '#/definitions/DataModifier', - properties: { - prop1: { - type: 'string', - }, - }, - }, - }, }, }, - }); - }, -); + }, + }); +}); diff --git a/test/bugs/ui-4071.js b/test/bugs/ui-4071.js index c6145ac2f..44185e455 100644 --- a/test/bugs/ui-4071.js +++ b/test/bugs/ui-4071.js @@ -12,7 +12,8 @@ const spec = { '/jobs': { post: { operationId: 'postJobs', - description: 'The job feed endpoint returns an array of job records that satisfy the supplied criteria.', + description: + 'The job feed endpoint returns an array of job records that satisfy the supplied criteria.', responses: { default: { description: 'Unexpected error', @@ -46,29 +47,23 @@ const spec = { }, }; -test( - 'should generate a request with application/x-www-form-urlencoded', - () => { - const req = buildRequest({ - spec, - requestContentType: 'application/x-www-form-urlencoded', - operationId: 'postJobs', - requestBody: { - industries: [ - 1, - 16, - ], - }, - }); +test('should generate a request with application/x-www-form-urlencoded', () => { + const req = buildRequest({ + spec, + requestContentType: 'application/x-www-form-urlencoded', + operationId: 'postJobs', + requestBody: { + industries: [1, 16], + }, + }); - expect(req).toEqual({ - url: 'https://workbcjobs.api.gov.bc.ca/v1/jobs', - method: 'POST', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: 'industries=1,16', - }); - }, -); + expect(req).toEqual({ + url: 'https://workbcjobs.api.gov.bc.ca/v1/jobs', + method: 'POST', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: 'industries=1,16', + }); +}); diff --git a/test/bugs/ui-4228.js b/test/bugs/ui-4228.js index dde1256ff..4ff46643b 100644 --- a/test/bugs/ui-4228.js +++ b/test/bugs/ui-4228.js @@ -7,9 +7,7 @@ const spec = { '/product/{productId}': { get: { operationId: 'Get', - produces: [ - 'application/json', - ], + produces: ['application/json'], responses: { 200: { description: 'Ok', @@ -39,9 +37,7 @@ const spec = { format: 'double', }, }, - required: [ - 'height', - ], + required: ['height'], type: 'object', }, ProductModel: { @@ -50,97 +46,92 @@ const spec = { $ref: '#/definitions/Props', }, }, - required: [ - 'properties', - ], + required: ['properties'], type: 'object', }, }, }; -test( - 'should resolve "properties" property name in model definition correctly', - async () => { - const res = await Swagger.resolve({ - spec, - }); +test('should resolve "properties" property name in model definition correctly', async () => { + const res = await Swagger.resolve({ + spec, + }); - expect(res).toEqual({ - errors: [], - spec: { - $$normalized: true, - definitions: { - ProductModel: { + expect(res).toEqual({ + errors: [], + spec: { + $$normalized: true, + definitions: { + ProductModel: { + properties: { properties: { + $$ref: '#/definitions/Props', properties: { - $$ref: '#/definitions/Props', - properties: { - height: { - format: 'double', - type: 'number', - }, + height: { + format: 'double', + type: 'number', }, - required: ['height'], - type: 'object', }, + required: ['height'], + type: 'object', }, - required: ['properties'], - type: 'object', }, - Props: { - properties: { - height: { - format: 'double', - type: 'number', - }, + required: ['properties'], + type: 'object', + }, + Props: { + properties: { + height: { + format: 'double', + type: 'number', }, - required: ['height'], - type: 'object', }, + required: ['height'], + type: 'object', }, - paths: { - '/product/{productId}': { - get: { - __originalOperationId: 'Get', - operationId: 'Get', - parameters: [ - { - format: 'double', - in: 'path', - name: 'productId', - required: true, - type: 'number', - }, - ], - produces: ['application/json'], - responses: { - 200: { - description: 'Ok', - schema: { - $$ref: '#/definitions/ProductModel', + }, + paths: { + '/product/{productId}': { + get: { + __originalOperationId: 'Get', + operationId: 'Get', + parameters: [ + { + format: 'double', + in: 'path', + name: 'productId', + required: true, + type: 'number', + }, + ], + produces: ['application/json'], + responses: { + 200: { + description: 'Ok', + schema: { + $$ref: '#/definitions/ProductModel', + properties: { properties: { + $$ref: '#/definitions/Props', properties: { - $$ref: '#/definitions/Props', - properties: { - height: { - format: 'double', - type: 'number', - }, + height: { + format: 'double', + type: 'number', }, - required: ['height'], - type: 'object', }, + required: ['height'], + type: 'object', }, - required: ['properties'], - type: 'object', }, + required: ['properties'], + type: 'object', }, }, - security: [], }, + security: [], }, }, }, - }); - }, -); + }, + }); +}); diff --git a/test/bugs/ui-4466.js b/test/bugs/ui-4466.js index 81a271107..37eb17e6e 100644 --- a/test/bugs/ui-4466.js +++ b/test/bugs/ui-4466.js @@ -10,9 +10,7 @@ const spec = { title: 'Foo', }, basePath: '/v1/foo', - produces: [ - 'application/json', - ], + produces: ['application/json'], parameters: { testHeader: { name: 'test-header', @@ -48,60 +46,31 @@ const spec = { }, }; -test( - 'should resolve test case from UI-4466 and UI-4467 correctly', - async () => { - const res = await resolveSubtree(spec, []); +test('should resolve test case from UI-4466 and UI-4467 correctly', async () => { + const res = await resolveSubtree(spec, []); - expect(res).toEqual({ - errors: [], - spec: { - swagger: '2.0', - $$normalized: true, - basePath: '/v1/foo', - info: { - title: 'Foo', - version: 'v1', - }, - parameters: { - testHeader: { - description: 'some request header', - in: 'header', - name: 'test-header', - required: false, - type: 'string', - }, + expect(res).toEqual({ + errors: [], + spec: { + swagger: '2.0', + $$normalized: true, + basePath: '/v1/foo', + info: { + title: 'Foo', + version: 'v1', + }, + parameters: { + testHeader: { + description: 'some request header', + in: 'header', + name: 'test-header', + required: false, + type: 'string', }, - paths: { - '/': { - get: { - parameters: [ - { - $$ref: '#/parameters/testHeader', - description: 'some request header', - in: 'header', - name: 'test-header', - required: false, - type: 'string', - }, - ], - produces: [ - 'application/json', - ], - responses: { - 200: { - description: 'Successful response', - schema: { - properties: { - bar: { - type: 'string', - }, - }, - type: 'object', - }, - }, - }, - }, + }, + paths: { + '/': { + get: { parameters: [ { $$ref: '#/parameters/testHeader', @@ -112,115 +81,122 @@ test( type: 'string', }, ], + produces: ['application/json'], + responses: { + 200: { + description: 'Successful response', + schema: { + properties: { + bar: { + type: 'string', + }, + }, + type: 'object', + }, + }, + }, }, + parameters: [ + { + $$ref: '#/parameters/testHeader', + description: 'some request header', + in: 'header', + name: 'test-header', + required: false, + type: 'string', + }, + ], }, - produces: [ - 'application/json', - ], }, - }); - }, -); + produces: ['application/json'], + }, + }); +}); -test( - 'should resolve modified test case where parameter is badly formatted', - async () => { - const invalidSpec = { +test('should resolve modified test case where parameter is badly formatted', async () => { + const invalidSpec = { + swagger: '2.0', + info: { + version: 'v1', + title: 'Foo', + }, + basePath: '/v1/foo', + produces: ['application/json'], + parameters: { + testHeader: { + name: 'test-header', + description: 'some request header', + type: 'string', + in: 'header', + required: false, + }, + }, + paths: { + '/': { + parameters: [{}], + get: { + responses: { + 200: { + description: 'Successful response', + schema: { + type: 'object', + properties: { + bar: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }, + }; + + const res = await resolveSubtree(invalidSpec, []); + + expect(res).toEqual({ + errors: [], + spec: { swagger: '2.0', + $$normalized: true, + basePath: '/v1/foo', info: { - version: 'v1', title: 'Foo', + version: 'v1', }, - basePath: '/v1/foo', - produces: [ - 'application/json', - ], parameters: { testHeader: { - name: 'test-header', description: 'some request header', - type: 'string', in: 'header', + name: 'test-header', required: false, + type: 'string', }, }, paths: { '/': { - parameters: [ - {}, - ], get: { + parameters: [{}], + produces: ['application/json'], responses: { 200: { description: 'Successful response', schema: { - type: 'object', properties: { bar: { type: 'string', }, }, + type: 'object', }, }, }, }, + parameters: [{}], }, }, - }; - - const res = await resolveSubtree(invalidSpec, []); - - expect(res).toEqual({ - errors: [], - spec: { - swagger: '2.0', - $$normalized: true, - basePath: '/v1/foo', - info: { - title: 'Foo', - version: 'v1', - }, - parameters: { - testHeader: { - description: 'some request header', - in: 'header', - name: 'test-header', - required: false, - type: 'string', - }, - }, - paths: { - '/': { - get: { - parameters: [ - {}, - ], - produces: [ - 'application/json', - ], - responses: { - 200: { - description: 'Successful response', - schema: { - properties: { - bar: { - type: 'string', - }, - }, - type: 'object', - }, - }, - }, - }, - parameters: [ - {}, - ], - }, - }, - produces: [ - 'application/json', - ], - }, - }); - }, -); + produces: ['application/json'], + }, + }); +}); diff --git a/test/bugs/ui-4924.js b/test/bugs/ui-4924.js index 29dbcb5d9..8d21f4263 100644 --- a/test/bugs/ui-4924.js +++ b/test/bugs/ui-4924.js @@ -50,20 +50,32 @@ const spec = { }, }; -test( - 'should not resolve $ref pointers within OpenAPI RequestBody/Response media type examples', - async () => { - const res = await resolveSubtree(spec, []); +test('should not resolve $ref pointers within OpenAPI RequestBody/Response media type examples', async () => { + const res = await resolveSubtree(spec, []); - expect(res).toEqual({ - errors: [], - spec: { - $$normalized: true, - openapi: '3.0.0', - paths: { - '/order': { - post: { - requestBody: { + expect(res).toEqual({ + errors: [], + spec: { + $$normalized: true, + openapi: '3.0.0', + paths: { + '/order': { + post: { + requestBody: { + content: { + 'application/json': { + example: { + user: { + $ref: '#/components/examples/User/value', + }, + quantity: 1, + }, + }, + }, + }, + responses: { + 200: { + description: 'OK', content: { 'application/json': { example: { @@ -75,35 +87,20 @@ test( }, }, }, - responses: { - 200: { - description: 'OK', - content: { - 'application/json': { - example: { - user: { - $ref: '#/components/examples/User/value', - }, - quantity: 1, - }, - }, - }, - }, - }, }, }, }, - components: { - examples: { - User: { - value: { - id: 1, - name: 'Sasha', - }, + }, + components: { + examples: { + User: { + value: { + id: 1, + name: 'Sasha', }, }, }, }, - }); - }, -); + }, + }); +}); diff --git a/test/client.js b/test/client.js index 2bcf11700..d8941cd42 100644 --- a/test/client.js +++ b/test/client.js @@ -8,67 +8,107 @@ import Swagger from '../src/index'; describe('http', () => { let server; beforeAll(() => { - server = http.createServer((req, res) => { - const { accept } = req.headers; - let contentType; - const uri = url.parse(req.url).pathname; - const filename = path.join('test', 'data', uri); - - if (filename.indexOf('.yaml') > 0) { - contentType = 'application/yaml'; - } else { - contentType = 'application/json'; - } - - if (typeof accept !== 'undefined') { - if (accept === 'invalid') { - res.writeHead(500); - res.end(); - return; - } + server = http + .createServer((req, res) => { + const { accept } = req.headers; + let contentType; + const uri = url.parse(req.url).pathname; + const filename = path.join('test', 'data', uri); - if (accept.indexOf('application/json') >= 0) { - contentType = accept; - res.setHeader('Content-Type', contentType); - } if (filename.indexOf('.yaml') > 0) { - res.setHeader('Content-Type', 'application/yaml'); + contentType = 'application/yaml'; + } else { + contentType = 'application/json'; } - } - if (req.headers['x-setcontenttype']) { - // Allow the test to explicitly set (or unset) a content type - if (req.headers['x-setcontenttype'] === 'none') { - res.removeHeader('Content-Type'); - } else { - res.setHeader('Content-Type', req.headers['x-setcontenttype']); + if (typeof accept !== 'undefined') { + if (accept === 'invalid') { + res.writeHead(500); + res.end(); + return; + } + + if (accept.indexOf('application/json') >= 0) { + contentType = accept; + res.setHeader('Content-Type', contentType); + } + if (filename.indexOf('.yaml') > 0) { + res.setHeader('Content-Type', 'application/yaml'); + } } - } - - fs.exists(filename, (exists) => { - if (exists) { - const fileStream = fs.createReadStream(filename); - res.setHeader('Access-Control-Allow-Origin', '*'); - res.writeHead(200, contentType); - fileStream.pipe(res); - } else { - res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.write('404 Not Found\n'); - res.end(); + + if (req.headers['x-setcontenttype']) { + // Allow the test to explicitly set (or unset) a content type + if (req.headers['x-setcontenttype'] === 'none') { + res.removeHeader('Content-Type'); + } else { + res.setHeader('Content-Type', req.headers['x-setcontenttype']); + } } - }); - }).listen(8000); + + fs.exists(filename, (exists) => { + if (exists) { + const fileStream = fs.createReadStream(filename); + res.setHeader('Access-Control-Allow-Origin', '*'); + res.writeHead(200, contentType); + fileStream.pipe(res); + } else { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.write('404 Not Found\n'); + res.end(); + } + }); + }) + .listen(8000); }); afterAll(() => { server.close(); }); - afterEach(() => { - }); + afterEach(() => {}); test('should get the JSON petstore api and build it', (done) => { - Swagger('http://localhost:8000/petstore.json') + Swagger('http://localhost:8000/petstore.json').then((client) => { + expect(client).toBeTruthy(); + + // we have 3 tags + expect(Object.keys(client.apis).length).toBe(3); + + // the pet tag exists + expect(client.apis.pet).toBeTruthy(); + + // the get pet operation + expect(client.apis.pet.getPetById).toBeTruthy(); + + done(); + }); + }); + + test('should get the YAML petstore api and build it', (done) => { + Swagger('http://localhost:8000/petstore.json').then((client) => { + expect(client).toBeTruthy(); + + // we have 3 tags + expect(Object.keys(client.apis).length).toBe(3); + + // the pet tag exists + expect(client.apis.pet).toBeTruthy(); + + // the get pet operation + expect(client.apis.pet.getPetById).toBeTruthy(); + + done(); + }); + }); + + test('should get the JSON petstore api and build it when response lacks a `Content-Type`', (done) => { + Swagger('http://localhost:8000/petstore.json', { + requestInterceptor: (req) => { + req.headers['X-SetContentType'] = 'none'; + return req; + }, + }) .then((client) => { expect(client).toBeTruthy(); @@ -82,11 +122,17 @@ describe('http', () => { expect(client.apis.pet.getPetById).toBeTruthy(); done(); - }); + }) + .catch((err) => done(err)); }); - test('should get the YAML petstore api and build it', (done) => { - Swagger('http://localhost:8000/petstore.json') + test('should get the YAML petstore api and build it when response lacks a `Content-Type`', (done) => { + Swagger('http://localhost:8000/petstore.yaml', { + requestInterceptor: (req) => { + req.headers['X-SetContentType'] = 'none'; + return req; + }, + }) .then((client) => { expect(client).toBeTruthy(); @@ -100,77 +146,24 @@ describe('http', () => { expect(client.apis.pet.getPetById).toBeTruthy(); done(); - }); - }); - - test( - 'should get the JSON petstore api and build it when response lacks a `Content-Type`', - (done) => { - Swagger('http://localhost:8000/petstore.json', { - requestInterceptor: (req) => { - req.headers['X-SetContentType'] = 'none'; - return req; - }, - }) - .then((client) => { - expect(client).toBeTruthy(); - - // we have 3 tags - expect(Object.keys(client.apis).length).toBe(3); - - // the pet tag exists - expect(client.apis.pet).toBeTruthy(); - - // the get pet operation - expect(client.apis.pet.getPetById).toBeTruthy(); - - done(); - }) - .catch((err) => done(err)); - }, - ); - - test( - 'should get the YAML petstore api and build it when response lacks a `Content-Type`', - (done) => { - Swagger('http://localhost:8000/petstore.yaml', { - requestInterceptor: (req) => { - req.headers['X-SetContentType'] = 'none'; - return req; - }, }) - .then((client) => { - expect(client).toBeTruthy(); - - // we have 3 tags - expect(Object.keys(client.apis).length).toBe(3); - - // the pet tag exists - expect(client.apis.pet).toBeTruthy(); - - // the get pet operation - expect(client.apis.pet.getPetById).toBeTruthy(); - - done(); - }) - .catch((err) => done(err)); - }, - ); + .catch((err) => done(err)); + }); /** * See https://github.com/swagger-api/swagger-js/issues/1005 */ test.skip('should get a pet from the petstore', (done) => { - Swagger('http://localhost:8000/petstore.json') - .then((client) => { - client.apis.pet.getPetById({ petId: -1 }) - .then(() => { - done('shoulda thrown an error!'); - }) - .catch((error) => { - done(error); - }); - }); + Swagger('http://localhost:8000/petstore.json').then((client) => { + client.apis.pet + .getPetById({ petId: -1 }) + .then(() => { + done('shoulda thrown an error!'); + }) + .catch((error) => { + done(error); + }); + }); }); /** @@ -182,7 +175,9 @@ describe('http', () => { throw new Error('Expected an error.'); }) .catch((error) => { - expect(error.message).toEqual('request to http://localhost:1/untouchable.yaml failed, reason: connect ECONNREFUSED 127.0.0.1:1'); + expect(error.message).toEqual( + 'request to http://localhost:1/untouchable.yaml failed, reason: connect ECONNREFUSED 127.0.0.1:1' + ); expect(error.name).toEqual('FetchError'); }); }); @@ -204,12 +199,11 @@ describe('http', () => { * See https://github.com/swagger-api/swagger-js/issues/1004 */ test.skip('fail with invalid verbs', (done) => { - Swagger('http://localhost:8000/invalid-operation.yaml') - .then((client) => { - expect(client.apis.default).toBeTruthy(); - expect(typeof client.apis.default['not-a-valid-verb']).toBe('undefined'); - done(); - }); + Swagger('http://localhost:8000/invalid-operation.yaml').then((client) => { + expect(client.apis.default).toBeTruthy(); + expect(typeof client.apis.default['not-a-valid-verb']).toBe('undefined'); + done(); + }); }); /** @@ -229,41 +223,35 @@ describe('http', () => { }); }); - test( - 'use the host from whence the spec was fetched when constructing swagger2 URLs from a basePath', - async () => { - const client = await Swagger('http://localhost:8000/relative-host.swagger.yaml'); - try { - const res = await client.apis.default.myOp(); - expect(res.status).toBe(404); - } catch (e) { - expect(e).toMatchObject({ - status: 404, - response: { - url: 'http://localhost:8000/v1/endpoint', - }, - }); - } - }, - ); - - test( - 'use the host from whence the spec was fetched when constructing OAS3 URLs from relative servers entries', - async () => { - const client = await Swagger('http://localhost:8000/relative-server.openapi.yaml'); - try { - const res = await client.apis.default.myOp(); - expect(res.status).toBe(404); - } catch (e) { - expect(e).toMatchObject({ - status: 404, - response: { - url: 'http://localhost:8000/v1/endpoint', - }, - }); - } - }, - ); + test('use the host from whence the spec was fetched when constructing swagger2 URLs from a basePath', async () => { + const client = await Swagger('http://localhost:8000/relative-host.swagger.yaml'); + try { + const res = await client.apis.default.myOp(); + expect(res.status).toBe(404); + } catch (e) { + expect(e).toMatchObject({ + status: 404, + response: { + url: 'http://localhost:8000/v1/endpoint', + }, + }); + } + }); + + test('use the host from whence the spec was fetched when constructing OAS3 URLs from relative servers entries', async () => { + const client = await Swagger('http://localhost:8000/relative-server.openapi.yaml'); + try { + const res = await client.apis.default.myOp(); + expect(res.status).toBe(404); + } catch (e) { + expect(e).toMatchObject({ + status: 404, + response: { + url: 'http://localhost:8000/v1/endpoint', + }, + }); + } + }); test('should err gracefully when requesting https from an http server', () => { return Swagger({ @@ -275,7 +263,9 @@ describe('http', () => { return req; }, }).catch((err) => { - expect(err.message).toMatch(/^request to https:\/\/localhost:8000\/petstore\.json failed, reason: (socket hang up|write EPROTO)/); + expect(err.message).toMatch( + /^request to https:\/\/localhost:8000\/petstore\.json failed, reason: (socket hang up|write EPROTO)/ + ); }); }); @@ -286,9 +276,15 @@ describe('http', () => { requestInterceptor, }).then((client) => { expect(requestInterceptor.mock.calls.length).toEqual(3); - expect(requestInterceptor.mock.calls[0][0].url).toEqual('http://localhost:8000/nested/one.yaml'); - expect(requestInterceptor.mock.calls[1][0].url).toEqual('http://localhost:8000/nested/two.yaml'); - expect(requestInterceptor.mock.calls[2][0].url).toEqual('http://localhost:8000/nested/three.yaml'); + expect(requestInterceptor.mock.calls[0][0].url).toEqual( + 'http://localhost:8000/nested/one.yaml' + ); + expect(requestInterceptor.mock.calls[1][0].url).toEqual( + 'http://localhost:8000/nested/two.yaml' + ); + expect(requestInterceptor.mock.calls[2][0].url).toEqual( + 'http://localhost:8000/nested/three.yaml' + ); expect(client.spec).toEqual({ data: { diff --git a/test/data/sample-multipart-oas2.js b/test/data/sample-multipart-oas2.js index 955f620cf..b837fef7d 100644 --- a/test/data/sample-multipart-oas2.js +++ b/test/data/sample-multipart-oas2.js @@ -17,18 +17,12 @@ export default { }, host: '', basePath: '/api/v1', - schemes: [ - 'http', - ], + schemes: ['http'], paths: { '/land/content/ViewOfAuthOwner': { post: { - consumes: [ - 'multipart/form-data', - ], - produces: [ - 'application/json', - ], + consumes: ['multipart/form-data'], + produces: ['application/json'], summary: '', parameters: [ { @@ -37,10 +31,7 @@ export default { description: '', default: 'id', type: 'string', - enum: [ - 'id', - 'title', - ], + enum: ['id', 'title'], }, { in: 'formData', @@ -48,10 +39,7 @@ export default { description: '', default: 'desc', type: 'string', - enum: [ - 'asc', - 'desc', - ], + enum: ['asc', 'desc'], }, { in: 'formData', @@ -126,12 +114,8 @@ export default { }, '/land/content/uploadImage': { post: { - consumes: [ - 'multipart/form-data', - ], - produces: [ - 'application/json', - ], + consumes: ['multipart/form-data'], + produces: ['application/json'], summary: 'upload image(s)', parameters: [ { diff --git a/test/data/sample-multipart-oas3.js b/test/data/sample-multipart-oas3.js index 03c3d4f47..60c6dc58b 100644 --- a/test/data/sample-multipart-oas3.js +++ b/test/data/sample-multipart-oas3.js @@ -24,19 +24,13 @@ export default { description: '', default: 'id', type: 'string', - enum: [ - 'id', - 'title', - ], + enum: ['id', 'title'], }, 'hhlContent:order': { description: '', default: 'desc', type: 'string', - enum: [ - 'asc', - 'desc', - ], + enum: ['asc', 'desc'], }, 'email[]': { description: 'The list of emails.', diff --git a/test/execute/baseurl.js b/test/execute/baseurl.js index 95bd7221a..3e70031f8 100644 --- a/test/execute/baseurl.js +++ b/test/execute/baseurl.js @@ -4,21 +4,18 @@ import { baseUrl } from '../../src/execute'; // One can use operationId or pathItem + method describe('baseUrl', () => { - test( - 'should calculate a valid baseUrl given host, basePath, context, schemes', - () => { - const res = baseUrl({ - spec: { - schemes: ['https'], - host: 'foo.com:8080', - basePath: '/bar', - }, - contextUrl: 'http://example.com:9090/hello/swagger.json', - }); - - expect(res).toEqual('https://foo.com:8080/bar'); - }, - ); + test('should calculate a valid baseUrl given host, basePath, context, schemes', () => { + const res = baseUrl({ + spec: { + schemes: ['https'], + host: 'foo.com:8080', + basePath: '/bar', + }, + contextUrl: 'http://example.com:9090/hello/swagger.json', + }); + + expect(res).toEqual('https://foo.com:8080/bar'); + }); test('should calculate a valid baseUrl given host, basePath, context', () => { const res = baseUrl({ diff --git a/test/execute/main.js b/test/execute/main.js index 38a4959d2..edca9705f 100644 --- a/test/execute/main.js +++ b/test/execute/main.js @@ -1,7 +1,5 @@ import FormData from '../../src/internal/form-data-monkey-patch'; -import { - execute, buildRequest, self as stubs, -} from '../../src/execute'; +import { execute, buildRequest, self as stubs } from '../../src/execute'; import { normalizeSwagger } from '../../src/helpers'; // Supported shape... { spec, operationId, parameters, securities, fetch } @@ -61,7 +59,7 @@ describe('execute', () => { url: 'http://foo.com:8081/v1/', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -87,7 +85,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/one', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -118,7 +116,7 @@ describe('execute', () => { method: 'GET', url: 'https://swagger.io/one', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -153,7 +151,7 @@ describe('execute', () => { method: 'GET', url: 'https://swagger.io/one', credentials: 'same-origin', - headers: { }, + headers: {}, userFetch: spy, }); }); @@ -181,7 +179,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/one?petId=123', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -194,25 +192,31 @@ describe('execute', () => { '/one': { get: { operationId: 'getMe', - parameters: [{ - name: 'fields', - in: 'query', - type: 'string', - }], + parameters: [ + { + name: 'fields', + in: 'query', + type: 'string', + }, + ], }, }, }, }; // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { fields: '[articles]=title' } }); + const req = buildRequest({ + spec, + operationId: 'getMe', + parameters: { fields: '[articles]=title' }, + }); // Then expect(req).toEqual({ url: 'http://swagger.io/v1/one?fields=%5Barticles%5D%3Dtitle', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -269,7 +273,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/one?zero=0&false=false&zeroDefault=0&falseDefault=false', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -282,11 +286,13 @@ describe('execute', () => { '/one': { get: { operationId: 'getMe', - parameters: [{ - name: 'petId', - in: 'query', - type: 'boolean', - }], + parameters: [ + { + name: 'petId', + in: 'query', + type: 'boolean', + }, + ], }, }, }, @@ -300,7 +306,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/one?petId=true', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -312,12 +318,14 @@ describe('execute', () => { '/one': { get: { operationId: 'getMe', - parameters: [{ - name: 'petId', - in: 'query', - type: 'integer', - default: 3, - }], + parameters: [ + { + name: 'petId', + in: 'query', + type: 'integer', + default: 3, + }, + ], }, }, }, @@ -329,35 +337,36 @@ describe('execute', () => { url: 'http://swagger.io/v1/one?petId=3', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); - test( - 'should throw error if required parameter value is not provided', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test('should throw error if required parameter value is not provided', () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'petId', in: 'query', required: true, type: 'string', - }], - }, + }, + ], }, }, - }; + }, + }; - expect(() => buildRequest({ spec, operationId: 'getMe' })).toThrow('Required parameter petId is not provided'); - }, - ); + expect(() => buildRequest({ spec, operationId: 'getMe' })).toThrow( + 'Required parameter petId is not provided' + ); + }); test('should throw error if operation was not found', () => { // Given @@ -373,38 +382,39 @@ describe('execute', () => { }, }; - expect(() => buildRequest({ spec, operationId: 'nonExistingOperationId' })).toThrow('Operation nonExistingOperationId not found'); + expect(() => buildRequest({ spec, operationId: 'nonExistingOperationId' })).toThrow( + 'Operation nonExistingOperationId not found' + ); }); describe('formData', () => { - test( - 'should add an empty query param if the value is empty and allowEmptyValue: true', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - delete: { - operationId: 'deleteMe', - parameters: [{ + test('should add an empty query param if the value is empty and allowEmptyValue: true', () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + delete: { + operationId: 'deleteMe', + parameters: [ + { name: 'petId', in: 'formData', allowEmptyValue: true, - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'deleteMe', parameters: {} }); + // When + const req = buildRequest({ spec, operationId: 'deleteMe', parameters: {} }); - // Then - expect(req.body).toEqual('petId='); - }, - ); + // Then + expect(req.body).toEqual('petId='); + }); test('should support collectionFormat', () => { const spec = { @@ -414,15 +424,17 @@ describe('execute', () => { '/one': { get: { operationId: 'getMe', - parameters: [{ - name: 'petId', - in: 'formData', - collectionFormat: 'csv', - type: 'array', - items: { - type: 'integer', + parameters: [ + { + name: 'petId', + in: 'formData', + collectionFormat: 'csv', + type: 'array', + items: { + type: 'integer', + }, }, - }], + ], }, }, }, @@ -446,12 +458,14 @@ describe('execute', () => { '/pets/findByStatus': { get: { operationId: 'getMe', - parameters: [{ - in: 'query', - name: 'status', - type: 'boolean', - required: false, - }], + parameters: [ + { + in: 'query', + name: 'status', + type: 'boolean', + required: false, + }, + ], }, }, }, @@ -465,7 +479,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/pets/findByStatus?status=false', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -479,12 +493,14 @@ describe('execute', () => { '/pets/findByStatus': { get: { operationId: 'getMe', - parameters: [{ - in: 'query', - name: 'status', - type: 'string', - required: true, - }], + parameters: [ + { + in: 'query', + name: 'status', + type: 'string', + required: true, + }, + ], }, }, }, @@ -502,7 +518,11 @@ describe('execute', () => { }; // When - const req = buildRequest({ spec, operationId: 'getMe', responseContentType: 'application/josh' }); + const req = buildRequest({ + spec, + operationId: 'getMe', + responseContentType: 'application/josh', + }); // Then expect(req).toEqual({ @@ -523,286 +543,275 @@ describe('execute', () => { '/one': { get: { operationId: 'loginUser', - parameters: [{ - in: 'query', - name: 'username', - type: 'string', - }, - { - in: 'query', - name: 'password', - type: 'string', - }], + parameters: [ + { + in: 'query', + name: 'username', + type: 'string', + }, + { + in: 'query', + name: 'password', + type: 'string', + }, + ], }, }, }, }; - const req = buildRequest({ spec, operationId: 'loginUser', parameters: { username: 'fred', password: 'meyer' } }); + const req = buildRequest({ + spec, + operationId: 'loginUser', + parameters: { username: 'fred', password: 'meyer' }, + }); expect(req).toEqual({ url: 'http://swagger.io/v1/one?username=fred&password=meyer', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); - test( - 'should add Content-Type if a body param definition is present but there is no payload', - () => { - // Given - const spec = { - host: 'swagger.io', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [ - { - name: 'body', - in: 'body', - schema: { - type: 'string', - }, + test('should add Content-Type if a body param definition is present but there is no payload', () => { + // Given + const spec = { + host: 'swagger.io', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { + name: 'body', + in: 'body', + schema: { + type: 'string', }, - ], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ - spec, - operationId: 'getMe', - requestContentType: 'application/josh', - }); + // When + const req = buildRequest({ + spec, + operationId: 'getMe', + requestContentType: 'application/josh', + }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/one', - body: undefined, - headers: { - 'Content-Type': 'application/josh', - }, - credentials: 'same-origin', - method: 'GET', - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/one', + body: undefined, + headers: { + 'Content-Type': 'application/josh', + }, + credentials: 'same-origin', + method: 'GET', + }); + }); - test( - 'should add Content-Type if a formData param definition is present but there is no payload', - () => { - // Given - const spec = { - host: 'swagger.io', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [ - { - name: 'data', - in: 'formData', - schema: { - type: 'string', - }, + test('should add Content-Type if a formData param definition is present but there is no payload', () => { + // Given + const spec = { + host: 'swagger.io', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { + name: 'data', + in: 'formData', + schema: { + type: 'string', }, - ], - }, + }, + ], }, }, - }; - - // When - const req = buildRequest({ - spec, - operationId: 'getMe', - requestContentType: 'application/x-www-form-encoded', - }); + }, + }; - // Then - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: { - 'Content-Type': 'application/x-www-form-encoded', - }, - credentials: 'same-origin', - method: 'GET', - }); - }, - ); + // When + const req = buildRequest({ + spec, + operationId: 'getMe', + requestContentType: 'application/x-www-form-encoded', + }); - test( - 'should not add Content-Type if no form-data or body param definition is present', - () => { - // Given - const spec = { - host: 'swagger.io', - paths: { '/one': { get: { operationId: 'getMe' } } }, - }; + // Then + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: { + 'Content-Type': 'application/x-www-form-encoded', + }, + credentials: 'same-origin', + method: 'GET', + }); + }); - // When - const req = buildRequest({ spec, operationId: 'getMe', requestContentType: 'application/josh' }); + test('should not add Content-Type if no form-data or body param definition is present', () => { + // Given + const spec = { + host: 'swagger.io', + paths: { '/one': { get: { operationId: 'getMe' } } }, + }; - // Then - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: {}, - credentials: 'same-origin', - method: 'GET', - }); - }, - ); + // When + const req = buildRequest({ + spec, + operationId: 'getMe', + requestContentType: 'application/josh', + }); - test( - 'should add Content-Type multipart/form-data when param type is file and no other sources of consumes', - () => { - // Given - const spec = { - host: 'swagger.io', - paths: { - '/one': { - post: { - operationId: 'postMe', - parameters: [{ name: 'foo', type: 'file', in: 'formData' }], - }, + // Then + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: {}, + credentials: 'same-origin', + method: 'GET', + }); + }); + + test('should add Content-Type multipart/form-data when param type is file and no other sources of consumes', () => { + // Given + const spec = { + host: 'swagger.io', + paths: { + '/one': { + post: { + operationId: 'postMe', + parameters: [{ name: 'foo', type: 'file', in: 'formData' }], }, }, - }; + }, + }; - // When - const req = buildRequest({ - spec, - operationId: 'postMe', - parameters: { foo: 'test' }, - }); + // When + const req = buildRequest({ + spec, + operationId: 'postMe', + parameters: { foo: 'test' }, + }); - // Then - expect(req.headers).toEqual({ - 'Content-Type': 'multipart/form-data', - }); + // Then + expect(req.headers).toEqual({ + 'Content-Type': 'multipart/form-data', + }); - // Would like to do a more thourough test ( ie: ensure the value `foo` exists.. - // but I don't feel like attacking the interals of the node pollyfill - // for FormData, as it seems to be missing `.get()`) - expect(req.url).toEqual('http://swagger.io/one'); - expect(req.body).toBeInstanceOf(FormData); - }, - ); + // Would like to do a more thourough test ( ie: ensure the value `foo` exists.. + // but I don't feel like attacking the interals of the node pollyfill + // for FormData, as it seems to be missing `.get()`) + expect(req.url).toEqual('http://swagger.io/one'); + expect(req.body).toBeInstanceOf(FormData); + }); - test( - 'should add Content-Type application/x-www-form-urlencoded when in: formData ', - () => { - // Given - const spec = { - host: 'swagger.io', - paths: { - '/one': { - post: { - operationId: 'postMe', - parameters: [{ name: 'file', in: 'formData' }], - }, + test('should add Content-Type application/x-www-form-urlencoded when in: formData ', () => { + // Given + const spec = { + host: 'swagger.io', + paths: { + '/one': { + post: { + operationId: 'postMe', + parameters: [{ name: 'file', in: 'formData' }], }, }, - }; + }, + }; - // When - const req = buildRequest({ - spec, - operationId: 'postMe', - parameters: { file: 'test' }, - }); + // When + const req = buildRequest({ + spec, + operationId: 'postMe', + parameters: { file: 'test' }, + }); - // Then - expect(req).toEqual({ - body: 'file=test', - method: 'POST', - url: 'http://swagger.io/one', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - credentials: 'same-origin', - }); - }, - ); + // Then + expect(req).toEqual({ + body: 'file=test', + method: 'POST', + url: 'http://swagger.io/one', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + credentials: 'same-origin', + }); + }); - test( - 'should add Content-Type from spec when no consumes in operation and no requestContentType passed', - () => { - // Given - const spec = { - host: 'swagger.io', - consumes: ['test'], - paths: { - '/one': { - post: { - operationId: 'postMe', - parameters: [{ name: 'file', in: 'formData' }], - }, + test('should add Content-Type from spec when no consumes in operation and no requestContentType passed', () => { + // Given + const spec = { + host: 'swagger.io', + consumes: ['test'], + paths: { + '/one': { + post: { + operationId: 'postMe', + parameters: [{ name: 'file', in: 'formData' }], }, }, - }; + }, + }; - // When - const req = buildRequest({ - spec, - operationId: 'postMe', - parameters: { file: 'test' }, - }); + // When + const req = buildRequest({ + spec, + operationId: 'postMe', + parameters: { file: 'test' }, + }); - // Then - expect(req).toEqual({ - body: 'file=test', - method: 'POST', - url: 'http://swagger.io/one', - headers: { - 'Content-Type': 'test', - }, - credentials: 'same-origin', - }); - }, - ); + // Then + expect(req).toEqual({ + body: 'file=test', + method: 'POST', + url: 'http://swagger.io/one', + headers: { + 'Content-Type': 'test', + }, + credentials: 'same-origin', + }); + }); - test( - 'should add Content-Type from operation when no requestContentType passed', - () => { - // Given - const spec = { - host: 'swagger.io', - consumes: ['no'], - paths: { - '/one': { - post: { - operationId: 'postMe', - consumes: ['test'], - parameters: [{ name: 'file', in: 'formData' }], - }, + test('should add Content-Type from operation when no requestContentType passed', () => { + // Given + const spec = { + host: 'swagger.io', + consumes: ['no'], + paths: { + '/one': { + post: { + operationId: 'postMe', + consumes: ['test'], + parameters: [{ name: 'file', in: 'formData' }], }, }, - }; + }, + }; - // When - const req = buildRequest({ - spec, - operationId: 'postMe', - parameters: { file: 'test' }, - }); + // When + const req = buildRequest({ + spec, + operationId: 'postMe', + parameters: { file: 'test' }, + }); - // Then - expect(req).toEqual({ - body: 'file=test', - method: 'POST', - url: 'http://swagger.io/one', - headers: { - 'Content-Type': 'test', - }, - credentials: 'same-origin', - }); - }, - ); + // Then + expect(req).toEqual({ + body: 'file=test', + method: 'POST', + url: 'http://swagger.io/one', + headers: { + 'Content-Type': 'test', + }, + credentials: 'same-origin', + }); + }); test('should build a request for all given fields', () => { // Given @@ -879,211 +888,195 @@ describe('execute', () => { }); }); - test( - 'should NOT stringify the body, if provided with a javascript object', - () => { - // execute alone should do that, allowing us to modify the object in a clean way) + test('should NOT stringify the body, if provided with a javascript object', () => { + // execute alone should do that, allowing us to modify the object in a clean way) - // Given - const spec = { - host: 'swagger.io', - paths: { '/me': { post: { parameters: [{ name: 'body', in: 'body' }], operationId: 'makeMe' } } }, - }; + // Given + const spec = { + host: 'swagger.io', + paths: { + '/me': { post: { parameters: [{ name: 'body', in: 'body' }], operationId: 'makeMe' } }, + }, + }; - const req = buildRequest({ - spec, - operationId: 'makeMe', - parameters: { - body: { - one: 1, - }, + const req = buildRequest({ + spec, + operationId: 'makeMe', + parameters: { + body: { + one: 1, }, - }); + }, + }); - expect(req.body).toEqual({ - one: 1, - }); - }, - ); + expect(req.body).toEqual({ + one: 1, + }); + }); describe('attachContentTypeForEmptyPayload', () => { - test( - 'should attach a Content-Type to a Swagger 2 operation with a body parameter defined but no body provided', - () => { - const spec = { - swagger: '2.0', - host: 'swagger.io', - consumes: ['application/json'], - paths: { - '/one': { - post: { - operationId: 'myOp', - parameters: [ - { - name: 'body', - in: 'body', - }, - ], - }, + test('should attach a Content-Type to a Swagger 2 operation with a body parameter defined but no body provided', () => { + const spec = { + swagger: '2.0', + host: 'swagger.io', + consumes: ['application/json'], + paths: { + '/one': { + post: { + operationId: 'myOp', + parameters: [ + { + name: 'body', + in: 'body', + }, + ], }, }, - }; + }, + }; - const req = buildRequest({ - spec, - operationId: 'myOp', - attachContentTypeForEmptyPayload: true, - }); + const req = buildRequest({ + spec, + operationId: 'myOp', + attachContentTypeForEmptyPayload: true, + }); - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'same-origin', - method: 'POST', - body: undefined, - }); - }, - ); - test( - 'should attach a Content-Type to a Swagger 2 operation with a formData parameter defined but no body provided', - () => { - const spec = { - swagger: '2.0', - host: 'swagger.io', - paths: { - '/one': { - post: { - operationId: 'myOp', - parameters: [ - { - name: 'data', - in: 'formData', - type: 'string', - }, - ], - }, + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'same-origin', + method: 'POST', + body: undefined, + }); + }); + test('should attach a Content-Type to a Swagger 2 operation with a formData parameter defined but no body provided', () => { + const spec = { + swagger: '2.0', + host: 'swagger.io', + paths: { + '/one': { + post: { + operationId: 'myOp', + parameters: [ + { + name: 'data', + in: 'formData', + type: 'string', + }, + ], }, }, - }; + }, + }; - const req = buildRequest({ - spec, - operationId: 'myOp', - attachContentTypeForEmptyPayload: true, - }); + const req = buildRequest({ + spec, + operationId: 'myOp', + attachContentTypeForEmptyPayload: true, + }); - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - credentials: 'same-origin', - method: 'POST', - }); - }, - ); - test( - 'should not attach a Content-Type to a Swagger 2 operation with no body or formData parameter definition present', - () => { - const spec = { - swagger: '2.0', - host: 'swagger.io', - paths: { - '/one': { - post: { - operationId: 'myOp', - }, + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + credentials: 'same-origin', + method: 'POST', + }); + }); + test('should not attach a Content-Type to a Swagger 2 operation with no body or formData parameter definition present', () => { + const spec = { + swagger: '2.0', + host: 'swagger.io', + paths: { + '/one': { + post: { + operationId: 'myOp', }, }, - }; + }, + }; - const req = buildRequest({ - spec, - operationId: 'myOp', - attachContentTypeForEmptyPayload: true, - }); + const req = buildRequest({ + spec, + operationId: 'myOp', + attachContentTypeForEmptyPayload: true, + }); - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: {}, - credentials: 'same-origin', - method: 'POST', - }); - }, - ); - test( - 'should not attach a Content-Type to a Swagger 2 operation with a body parameter defined but no body provided if the option is not enabled', - () => { - const spec = { - swagger: '2.0', - host: 'swagger.io', - consumes: ['application/json'], - paths: { - '/one': { - post: { - operationId: 'myOp', - parameters: [ - { - name: 'body', - in: 'body', - }, - ], - }, + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: {}, + credentials: 'same-origin', + method: 'POST', + }); + }); + test('should not attach a Content-Type to a Swagger 2 operation with a body parameter defined but no body provided if the option is not enabled', () => { + const spec = { + swagger: '2.0', + host: 'swagger.io', + consumes: ['application/json'], + paths: { + '/one': { + post: { + operationId: 'myOp', + parameters: [ + { + name: 'body', + in: 'body', + }, + ], }, }, - }; + }, + }; - const req = buildRequest({ - spec, - operationId: 'myOp', - }); + const req = buildRequest({ + spec, + operationId: 'myOp', + }); - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: {}, - credentials: 'same-origin', - method: 'POST', - body: undefined, - }); - }, - ); - test( - 'should not attach a Content-Type to a Swagger 2 operation with a formData parameter defined but no body provided if the option is not enabled', - () => { - const spec = { - swagger: '2.0', - host: 'swagger.io', - paths: { - '/one': { - post: { - operationId: 'myOp', - parameters: [ - { - name: 'data', - in: 'formData', - type: 'string', - }, - ], - }, + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: {}, + credentials: 'same-origin', + method: 'POST', + body: undefined, + }); + }); + test('should not attach a Content-Type to a Swagger 2 operation with a formData parameter defined but no body provided if the option is not enabled', () => { + const spec = { + swagger: '2.0', + host: 'swagger.io', + paths: { + '/one': { + post: { + operationId: 'myOp', + parameters: [ + { + name: 'data', + in: 'formData', + type: 'string', + }, + ], }, }, - }; + }, + }; - const req = buildRequest({ - spec, - operationId: 'myOp', - }); + const req = buildRequest({ + spec, + operationId: 'myOp', + }); - expect(req).toEqual({ - url: 'http://swagger.io/one', - headers: {}, - credentials: 'same-origin', - method: 'POST', - }); - }, - ); + expect(req).toEqual({ + url: 'http://swagger.io/one', + headers: {}, + credentials: 'same-origin', + method: 'POST', + }); + }); }); }); @@ -1100,7 +1093,7 @@ describe('execute', () => { execute({ fetch: jest.fn().mockImplementation(() => ({ - then() { }, + then() {}, })), spec, operationId: 'getMe', @@ -1119,11 +1112,13 @@ describe('execute', () => { // Given const spec = { host: 'swagger.io', - paths: { '/me': { post: { parameters: [{ name: 'body', in: 'body' }], operationId: 'makeMe' } } }, + paths: { + '/me': { post: { parameters: [{ name: 'body', in: 'body' }], operationId: 'makeMe' } }, + }, }; const fetchSpy = jest.fn().mockImplementation(() => ({ - then() { }, + then() {}, })); execute({ @@ -1148,11 +1143,13 @@ describe('execute', () => { // Given const spec = { host: 'swagger.io', - paths: { '/me': { post: { parameters: [{ name: 'body', in: 'body' }], operationId: 'makeMe' } } }, + paths: { + '/me': { post: { parameters: [{ name: 'body', in: 'body' }], operationId: 'makeMe' } }, + }, }; const fetchSpy = jest.fn().mockImplementation(() => ({ - then() { }, + then() {}, })); execute({ @@ -1172,11 +1169,13 @@ describe('execute', () => { // Given const spec = { host: 'swagger.io', - paths: { '/me': { post: { parameters: [{ name: 'one', in: 'formData' }], operationId: 'makeMe' } } }, + paths: { + '/me': { post: { parameters: [{ name: 'one', in: 'formData' }], operationId: 'makeMe' } }, + }, }; const fetchSpy = jest.fn().mockImplementation(() => ({ - then() { }, + then() {}, })); execute({ @@ -1204,14 +1203,16 @@ describe('execute', () => { '/one': { get: { operationId: 'getMe', - parameters: [{ - name: 'petId', - in: 'query', - type: 'array', - items: { - type: 'string', + parameters: [ + { + name: 'petId', + in: 'query', + type: 'array', + items: { + type: 'string', + }, }, - }], + ], }, }, }, @@ -1225,7 +1226,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/one?petId=a%2Cb', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -1264,29 +1265,32 @@ describe('execute', () => { }; // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { ids: [1, 2, 3], 'the names': ['a,b', 'mary'] } }); + const req = buildRequest({ + spec, + operationId: 'getMe', + parameters: { ids: [1, 2, 3], 'the names': ['a,b', 'mary'] }, + }); // Then expect(req).toEqual({ url: 'http://swagger.io/v1/one?ids=1,2,3&the%20names=a%2Cb|mary', method: 'GET', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); - test( - 'should include values for array of query parameters \'csv\' collectionFormat', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test("should include values for array of query parameters 'csv' collectionFormat", () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'petId', in: 'query', collectionFormat: 'csv', @@ -1294,37 +1298,36 @@ describe('execute', () => { items: { type: 'integer', }, - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); + // When + const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?petId=1,2,3', - method: 'GET', - credentials: 'same-origin', - headers: { }, - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?petId=1,2,3', + method: 'GET', + credentials: 'same-origin', + headers: {}, + }); + }); - test( - 'should include values for array of query parameters \'ssv\' collectionFormat', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test("should include values for array of query parameters 'ssv' collectionFormat", () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'petId', in: 'query', collectionFormat: 'ssv', @@ -1332,37 +1335,36 @@ describe('execute', () => { items: { type: 'integer', }, - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); + // When + const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?petId=1%202%203', - method: 'GET', - credentials: 'same-origin', - headers: { }, - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?petId=1%202%203', + method: 'GET', + credentials: 'same-origin', + headers: {}, + }); + }); - test( - 'should include values for array of query parameters \'multi\' collectionFormat', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test("should include values for array of query parameters 'multi' collectionFormat", () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'petId', in: 'query', collectionFormat: 'multi', @@ -1370,37 +1372,36 @@ describe('execute', () => { items: { type: 'integer', }, - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); + // When + const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?petId=1&petId=2&petId=3', - method: 'GET', - credentials: 'same-origin', - headers: { }, - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?petId=1&petId=2&petId=3', + method: 'GET', + credentials: 'same-origin', + headers: {}, + }); + }); - test( - 'should include values for array of query parameters \'tsv\' collectionFormat', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test("should include values for array of query parameters 'tsv' collectionFormat", () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'petId', in: 'query', collectionFormat: 'tsv', @@ -1408,37 +1409,36 @@ describe('execute', () => { items: { type: 'integer', }, - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); + // When + const req = buildRequest({ spec, operationId: 'getMe', parameters: { petId: [1, 2, 3] } }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?petId=1%092%093', - method: 'GET', - credentials: 'same-origin', - headers: { }, - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?petId=1%092%093', + method: 'GET', + credentials: 'same-origin', + headers: {}, + }); + }); - test( - 'should include values for array of query parameters \'pipes\' collectionFormat', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test("should include values for array of query parameters 'pipes' collectionFormat", () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'name', in: 'query', collectionFormat: 'pipes', @@ -1446,106 +1446,113 @@ describe('execute', () => { items: { type: 'string', }, - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { name: ['john', 'smith'] } }); + // When + const req = buildRequest({ + spec, + operationId: 'getMe', + parameters: { name: ['john', 'smith'] }, + }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?name=john|smith', - method: 'GET', - credentials: 'same-origin', - headers: { }, - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?name=john|smith', + method: 'GET', + credentials: 'same-origin', + headers: {}, + }); + }); - test( - 'should fall back to `name-in` format when a parameter cannot be found', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test('should fall back to `name-in` format when a parameter cannot be found', () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'name', in: 'query', type: 'string', - }], - }, + }, + ], }, }, - }; + }, + }; - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { 'query.name': 'john' } }); + // When + const req = buildRequest({ + spec, + operationId: 'getMe', + parameters: { 'query.name': 'john' }, + }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?name=john', - method: 'GET', - credentials: 'same-origin', - headers: { }, - }); - }, - ); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?name=john', + method: 'GET', + credentials: 'same-origin', + headers: {}, + }); + }); - test( - 'should set all parameter options when given an ambiguous parameter value', - () => { - // Given - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - get: { - operationId: 'getMe', - parameters: [{ + test('should set all parameter options when given an ambiguous parameter value', () => { + // Given + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + get: { + operationId: 'getMe', + parameters: [ + { name: 'name', in: 'query', type: 'string', - }, { + }, + { name: 'name', in: 'formData', type: 'string', - }], - }, + }, + ], }, }, - }; + }, + }; - const oriWarn = global.console.warn; - global.console.warn = jest.fn(); + const oriWarn = global.console.warn; + global.console.warn = jest.fn(); - // When - const req = buildRequest({ spec, operationId: 'getMe', parameters: { name: 'john' } }); + // When + const req = buildRequest({ spec, operationId: 'getMe', parameters: { name: 'john' } }); - // Then - expect(req).toEqual({ - url: 'http://swagger.io/v1/one?name=john', - method: 'GET', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: 'name=john', - }); + // Then + expect(req).toEqual({ + url: 'http://swagger.io/v1/one?name=john', + method: 'GET', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: 'name=john', + }); - // eslint-disable-next-line no-console - expect(console.warn.mock.calls.length).toEqual(2); - global.console.warn = oriWarn; - }, - ); + // eslint-disable-next-line no-console + expect(console.warn.mock.calls.length).toEqual(2); + global.console.warn = oriWarn; + }); }); describe('body', () => { @@ -1557,13 +1564,15 @@ describe('execute', () => { '/one': { post: { operationId: 'postMe', - parameters: [{ - name: 'petId', - in: 'body', - schema: { - type: 'integer', + parameters: [ + { + name: 'petId', + in: 'body', + schema: { + type: 'integer', + }, }, - }], + ], }, }, }, @@ -1620,7 +1629,7 @@ describe('execute', () => { name: 'johny', id: '123', }, - headers: { }, + headers: {}, }); }); @@ -1632,7 +1641,7 @@ describe('execute', () => { method: 'POST', body: 123, credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -1644,7 +1653,7 @@ describe('execute', () => { method: 'POST', body: undefined, credentials: 'same-origin', - headers: { }, + headers: {}, }); }); }); @@ -1657,10 +1666,12 @@ describe('execute', () => { '/one': { delete: { operationId: 'deleteMe', - parameters: [{ - name: 'petId', - in: 'body', - }], + parameters: [ + { + name: 'petId', + in: 'body', + }, + ], }, }, }, @@ -1674,7 +1685,7 @@ describe('execute', () => { method: 'DELETE', body: undefined, credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -1686,7 +1697,7 @@ describe('execute', () => { method: 'DELETE', body: 123, credentials: 'same-origin', - headers: { }, + headers: {}, }); }); }); @@ -1701,90 +1712,94 @@ describe('execute', () => { '/one': { delete: { operationId: 'deleteMe', - parameters: [{ - in: 'header', - name: 'api_key', - type: 'integer', - }], + parameters: [ + { + in: 'header', + name: 'api_key', + type: 'integer', + }, + ], + }, + }, + }, + }; + + const req = buildRequest({ spec, operationId: 'deleteMe', parameters: { api_key: 123 } }); + + expect(req).toEqual({ + url: 'http://swagger.io/v1/one', + method: 'DELETE', + credentials: 'same-origin', + headers: { + api_key: 123, + }, + }); + }); + + test('should process a delete request without headers of value undefined', () => { + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + delete: { + operationId: 'deleteMe', + parameters: [ + { + in: 'header', + name: 'api_key', + type: 'integer', + }, + ], + }, + }, + }, + }; + + const req = buildRequest({ + spec, + operationId: 'deleteMe', + parameters: { api_key: undefined }, + }); + + expect(req).toEqual({ + url: 'http://swagger.io/v1/one', + method: 'DELETE', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should process a delete request without headers wich are not provided', () => { + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/one': { + delete: { + operationId: 'deleteMe', + parameters: [ + { + in: 'header', + name: 'api_key', + type: 'integer', + }, + ], }, }, }, }; - const req = buildRequest({ spec, operationId: 'deleteMe', parameters: { api_key: 123 } }); + const req = buildRequest({ spec, operationId: 'deleteMe', parameters: {} }); expect(req).toEqual({ url: 'http://swagger.io/v1/one', method: 'DELETE', credentials: 'same-origin', - headers: { - api_key: 123, - }, + headers: {}, }); }); - test( - 'should process a delete request without headers of value undefined', - () => { - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - delete: { - operationId: 'deleteMe', - parameters: [{ - in: 'header', - name: 'api_key', - type: 'integer', - }], - }, - }, - }, - }; - - const req = buildRequest({ spec, operationId: 'deleteMe', parameters: { api_key: undefined } }); - - expect(req).toEqual({ - url: 'http://swagger.io/v1/one', - method: 'DELETE', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should process a delete request without headers wich are not provided', - () => { - const spec = { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/one': { - delete: { - operationId: 'deleteMe', - parameters: [{ - in: 'header', - name: 'api_key', - type: 'integer', - }], - }, - }, - }, - }; - - const req = buildRequest({ spec, operationId: 'deleteMe', parameters: {} }); - - expect(req).toEqual({ - url: 'http://swagger.io/v1/one', - method: 'DELETE', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - test('should accept the format', () => { const spec = { host: 'swagger.io', @@ -1794,19 +1809,24 @@ describe('execute', () => { get: { operationId: 'getMe', consumes: ['application/json'], - parameters: [{ - in: 'query', - name: 'petId', - type: 'string', - required: false, - }], + parameters: [ + { + in: 'query', + name: 'petId', + type: 'string', + required: false, + }, + ], }, }, }, }; const req = buildRequest({ - spec, operationId: 'getMe', responseContentType: 'application/json', parameters: {}, + spec, + operationId: 'getMe', + responseContentType: 'application/json', + parameters: {}, }); expect(req).toEqual({ @@ -1829,12 +1849,14 @@ describe('execute', () => { '/{id}': { get: { operationId: 'getMe', - parameters: [{ - in: 'path', - name: 'id', - type: 'number', - required: true, - }], + parameters: [ + { + in: 'path', + name: 'id', + type: 'number', + required: true, + }, + ], }, }, }, @@ -1846,8 +1868,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/123', method: 'GET', credentials: 'same-origin', - headers: { - }, + headers: {}, }); }); @@ -1879,7 +1900,53 @@ describe('execute', () => { }, }; - const req = buildRequest({ spec, operationId: 'getPetsById', parameters: { id: 123, test: 567 } }); + const req = buildRequest({ + spec, + operationId: 'getPetsById', + parameters: { id: 123, test: 567 }, + }); + + expect(req).toEqual({ + url: 'http://swagger.io/v1/pet/123?test=567', + headers: {}, + credentials: 'same-origin', + method: 'GET', + }); + }); + + test('should merge Path and Operation parameters when parameter is the first item in paths', () => { + const spec = { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/pet/{id}': { + parameters: [ + { + name: 'id', + in: 'path', + type: 'number', + required: true, + }, + ], + get: { + operationId: 'getPetsById', + parameters: [ + { + name: 'test', + in: 'query', + type: 'number', + }, + ], + }, + }, + }, + }; + + const req = buildRequest({ + spec, + operationId: 'getPetsById', + parameters: { id: 123, test: 567 }, + }); expect(req).toEqual({ url: 'http://swagger.io/v1/pet/123?test=567', @@ -1889,10 +1956,9 @@ describe('execute', () => { }); }); - test( - 'should merge Path and Operation parameters when parameter is the first item in paths', - () => { - const spec = { + test('should handle duplicate parameter inheritance from normalized swagger specifications', () => { + const spec = { + spec: { host: 'swagger.io', basePath: '/v1', paths: { @@ -1917,117 +1983,79 @@ describe('execute', () => { }, }, }, - }; - - const req = buildRequest({ spec, operationId: 'getPetsById', parameters: { id: 123, test: 567 } }); + }, + }; - expect(req).toEqual({ - url: 'http://swagger.io/v1/pet/123?test=567', - headers: {}, - credentials: 'same-origin', - method: 'GET', - }); - }, - ); + const resultSpec = normalizeSwagger(spec); + const warnSpy = jest.spyOn(console, 'warn'); + const req = buildRequest({ + spec: resultSpec.spec, + operationId: 'getPetsById', + parameters: { id: 123, test: 567 }, + }); + expect(req).toEqual({ + url: 'http://swagger.io/v1/pet/123?test=567', + headers: {}, + credentials: 'same-origin', + method: 'GET', + }); + expect(warnSpy.mock.calls.length).toEqual(0); + }); - test( - 'should handle duplicate parameter inheritance from normalized swagger specifications', - () => { - const spec = { - spec: { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/pet/{id}': { + test('should warn for ambiguous parameters in normalized swagger specifications', () => { + const spec = { + spec: { + host: 'swagger.io', + basePath: '/v1', + paths: { + '/pet/{id}': { + parameters: [ + { + name: 'id', + in: 'path', + type: 'number', + required: true, + }, + ], + get: { + operationId: 'getPetsById', parameters: [ { - name: 'id', - in: 'path', + name: 'test', + in: 'query', type: 'number', - required: true, }, - ], - get: { - operationId: 'getPetsById', - parameters: [ - { - name: 'test', - in: 'query', - type: 'number', - }, - ], - }, - }, - }, - }, - }; - - const resultSpec = normalizeSwagger(spec); - const warnSpy = jest.spyOn(console, 'warn'); - const req = buildRequest({ spec: resultSpec.spec, operationId: 'getPetsById', parameters: { id: 123, test: 567 } }); - expect(req).toEqual({ - url: 'http://swagger.io/v1/pet/123?test=567', - headers: {}, - credentials: 'same-origin', - method: 'GET', - }); - expect(warnSpy.mock.calls.length).toEqual(0); - }, - ); - - test( - 'should warn for ambiguous parameters in normalized swagger specifications', - () => { - const spec = { - spec: { - host: 'swagger.io', - basePath: '/v1', - paths: { - '/pet/{id}': { - parameters: [ { name: 'id', - in: 'path', + in: 'query', type: 'number', - required: true, }, ], - get: { - operationId: 'getPetsById', - parameters: [ - { - name: 'test', - in: 'query', - type: 'number', - }, - { - name: 'id', - in: 'query', - type: 'number', - }, - ], - }, }, }, }, - }; + }, + }; - const oriWarn = global.console.warn; - global.console.warn = jest.fn(); + const oriWarn = global.console.warn; + global.console.warn = jest.fn(); - const resultSpec = normalizeSwagger(spec); - const req = buildRequest({ spec: resultSpec.spec, operationId: 'getPetsById', parameters: { id: 123, test: 567 } }); - expect(req).toEqual({ - url: 'http://swagger.io/v1/pet/123?test=567&id=123', - headers: {}, - credentials: 'same-origin', - method: 'GET', - }); - // eslint-disable-next-line no-console - expect(console.warn.mock.calls.length).toEqual(2); - global.console.warn = oriWarn; - }, - ); + const resultSpec = normalizeSwagger(spec); + const req = buildRequest({ + spec: resultSpec.spec, + operationId: 'getPetsById', + parameters: { id: 123, test: 567 }, + }); + expect(req).toEqual({ + url: 'http://swagger.io/v1/pet/123?test=567&id=123', + headers: {}, + credentials: 'same-origin', + method: 'GET', + }); + // eslint-disable-next-line no-console + expect(console.warn.mock.calls.length).toEqual(2); + global.console.warn = oriWarn; + }); test('should encode path parameter', () => { const spec = { @@ -2037,12 +2065,14 @@ describe('execute', () => { '/{id}': { delete: { operationId: 'deleteMe', - parameters: [{ - in: 'path', - name: 'id', - type: 'string', - required: true, - }], + parameters: [ + { + in: 'path', + name: 'id', + type: 'string', + required: true, + }, + ], }, }, }, @@ -2054,7 +2084,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/foo%2Fbar', method: 'DELETE', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); @@ -2066,12 +2096,14 @@ describe('execute', () => { '/{id}/{id}': { delete: { operationId: 'deleteMe', - parameters: [{ - in: 'path', - name: 'id', - type: 'string', - required: true, - }], + parameters: [ + { + in: 'path', + name: 'id', + type: 'string', + required: true, + }, + ], }, }, }, @@ -2083,7 +2115,7 @@ describe('execute', () => { url: 'http://swagger.io/v1/foo%2Fbar/foo%2Fbar', method: 'DELETE', credentials: 'same-origin', - headers: { }, + headers: {}, }); }); }); @@ -2097,36 +2129,35 @@ describe('execute', () => { '/one': { post: { operationId: 'postMe', - parameters: [{ - name: 'petId', - in: 'formData', - type: 'string', - }], + parameters: [ + { + name: 'petId', + in: 'formData', + type: 'string', + }, + ], }, }, }, }; - test( - 'should generate a request with application/x-www-form-urlencoded', - () => { - const req = buildRequest({ - spec, - requestContentType: 'application/x-www-form-urlencoded', - operationId: 'postMe', - parameters: { petId: 'id' }, - }); + test('should generate a request with application/x-www-form-urlencoded', () => { + const req = buildRequest({ + spec, + requestContentType: 'application/x-www-form-urlencoded', + operationId: 'postMe', + parameters: { petId: 'id' }, + }); - expect(req).toEqual({ - url: 'http://swagger.io/v1/one', - method: 'POST', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: 'petId=id', - }); - }, - ); + expect(req).toEqual({ + url: 'http://swagger.io/v1/one', + method: 'POST', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: 'petId=id', + }); + }); }); }); diff --git a/test/helpers.js b/test/helpers.js index 14dbc00be..f755860df 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -1,6 +1,4 @@ -import { - normalizeSwagger, getOperationRaw, idFromPathMethod, -} from '../src/helpers'; +import { normalizeSwagger, getOperationRaw, idFromPathMethod } from '../src/helpers'; describe('helpers', () => { describe('idFromPathMethod', () => { @@ -18,677 +16,610 @@ describe('helpers', () => { // Then expect(id).toEqual('get_one'); }); - test( - 'should handle strange paths/methods correctly when in v2 mode', - () => { - const fn = (path, method) => { - return idFromPathMethod(path, method, { - v2OperationIdCompatibilityMode: true, - }); - }; - // https://github.com/swagger-api/swagger-js/issues/1269#issue-309070070 - expect(fn('/foo/{bar}/baz', 'get')).toEqual('get_foo_bar_baz'); + test('should handle strange paths/methods correctly when in v2 mode', () => { + const fn = (path, method) => { + return idFromPathMethod(path, method, { + v2OperationIdCompatibilityMode: true, + }); + }; + // https://github.com/swagger-api/swagger-js/issues/1269#issue-309070070 + expect(fn('/foo/{bar}/baz', 'get')).toEqual('get_foo_bar_baz'); - expect(fn('/one/{foo}/{bar}', 'get')).toEqual('get_one_foo_bar'); - expect(fn('/one/{bar}/-----{baz}', 'get')).toEqual('get_one_bar_baz'); - }, - ); + expect(fn('/one/{foo}/{bar}', 'get')).toEqual('get_one_foo_bar'); + expect(fn('/one/{bar}/-----{baz}', 'get')).toEqual('get_one_bar_baz'); + }); }); describe('getOperationRaw', () => { - test( - 'should return the operation object, given an explicit operationId', - () => { - // Given - const spec = { - paths: { - '/one': { - get: { operationId: 'op1' }, - }, + test('should return the operation object, given an explicit operationId', () => { + // Given + const spec = { + paths: { + '/one': { + get: { operationId: 'op1' }, }, - }; + }, + }; - // When - const op = getOperationRaw(spec, 'op1'); + // When + const op = getOperationRaw(spec, 'op1'); - // Then - expect(op).toMatchObject({ - operation: spec.paths['/one'].get, - pathName: '/one', - method: 'GET', - }); - }, - ); + // Then + expect(op).toMatchObject({ + operation: spec.paths['/one'].get, + pathName: '/one', + method: 'GET', + }); + }); - test( - 'should return the operation object, given an explicit operationId with special characters', - () => { - // Given - const spec = { - paths: { - '/one': { - get: { operationId: 'A.Very_Special-operationID!' }, - }, + test('should return the operation object, given an explicit operationId with special characters', () => { + // Given + const spec = { + paths: { + '/one': { + get: { operationId: 'A.Very_Special-operationID!' }, }, - }; + }, + }; - // When - const op = getOperationRaw(spec, 'A.Very_Special-operationID!'); + // When + const op = getOperationRaw(spec, 'A.Very_Special-operationID!'); - // Then - expect(op).toMatchObject({ - operation: spec.paths['/one'].get, - pathName: '/one', - method: 'GET', - }); - }, - ); + // Then + expect(op).toMatchObject({ + operation: spec.paths['/one'].get, + pathName: '/one', + method: 'GET', + }); + }); - test( - 'should return null, given an explicit operationId that does not exist', - () => { - // Given - const spec = { - paths: { - '/one': { - get: { operationId: 'getOne' }, - }, + test('should return null, given an explicit operationId that does not exist', () => { + // Given + const spec = { + paths: { + '/one': { + get: { operationId: 'getOne' }, }, - }; + }, + }; - // When - const op = getOperationRaw(spec, 'ThisOperationIdDoesNotExist'); + // When + const op = getOperationRaw(spec, 'ThisOperationIdDoesNotExist'); - // Then - expect(op).toEqual(null); - }, - ); - - test( - 'should return the operationObj, given a generated operationId', - () => { - // Given` - const spec = { - paths: { - '/two': { - get: { - description: 'an operation', - }, + // Then + expect(op).toEqual(null); + }); + + test('should return the operationObj, given a generated operationId', () => { + // Given` + const spec = { + paths: { + '/two': { + get: { + description: 'an operation', }, }, - }; + }, + }; - // When - const op = getOperationRaw(spec, 'get_two'); + // When + const op = getOperationRaw(spec, 'get_two'); - // Then - expect(op).toMatchObject({ - operation: spec.paths['/two'].get, - pathName: '/two', - method: 'GET', - }); - }, - ); + // Then + expect(op).toMatchObject({ + operation: spec.paths['/two'].get, + pathName: '/two', + method: 'GET', + }); + }); - test( - 'should return the operationObj, given a generated legacy operationId', - () => { - // Given` - const spec = { - paths: { - '/two': { - get: { - description: 'an operation', - }, + test('should return the operationObj, given a generated legacy operationId', () => { + // Given` + const spec = { + paths: { + '/two': { + get: { + description: 'an operation', }, }, - }; + }, + }; - // When - const op = getOperationRaw(spec, 'get-/two'); + // When + const op = getOperationRaw(spec, 'get-/two'); - // Then - expect(op).toMatchObject({ - operation: spec.paths['/two'].get, - pathName: '/two', - method: 'GET', - }); - }, - ); + // Then + expect(op).toMatchObject({ + operation: spec.paths['/two'].get, + pathName: '/two', + method: 'GET', + }); + }); }); describe('normalizeSwagger', () => { describe('operationId', () => { - test( - 'should create unique operationIds when explicit operationIds are duplicates, and preserve originals', - () => { - const input = { - spec: { - paths: { - '/foo': { - get: { - operationId: 'test', - }, + test('should create unique operationIds when explicit operationIds are duplicates, and preserve originals', () => { + const input = { + spec: { + paths: { + '/foo': { + get: { + operationId: 'test', }, - '/bar': { - get: { - operationId: 'test', - }, + }, + '/bar': { + get: { + operationId: 'test', }, - '/baz': { - get: { - operationId: 'test', - }, + }, + '/baz': { + get: { + operationId: 'test', }, }, }, - }; - - const res = normalizeSwagger(input); - const fooRes = res.spec.paths['/foo'].get; - const barRes = res.spec.paths['/bar'].get; - const bazRes = res.spec.paths['/baz'].get; - - // Then - expect(fooRes.operationId).toEqual('test1'); - expect(barRes.operationId).toEqual('test2'); - expect(bazRes.operationId).toEqual('test3'); - expect(fooRes.__originalOperationId).toEqual('test'); - expect(barRes.__originalOperationId).toEqual('test'); - expect(bazRes.__originalOperationId).toEqual('test'); - }, - ); - - test( - 'should add the normalized operation id to the spec, if a non-normalized id exists', - () => { - // Given - const spec = { - spec: { - paths: { - '/foo': { - get: { - operationId: 'something with spaces', - }, + }, + }; + + const res = normalizeSwagger(input); + const fooRes = res.spec.paths['/foo'].get; + const barRes = res.spec.paths['/bar'].get; + const bazRes = res.spec.paths['/baz'].get; + + // Then + expect(fooRes.operationId).toEqual('test1'); + expect(barRes.operationId).toEqual('test2'); + expect(bazRes.operationId).toEqual('test3'); + expect(fooRes.__originalOperationId).toEqual('test'); + expect(barRes.__originalOperationId).toEqual('test'); + expect(bazRes.__originalOperationId).toEqual('test'); + }); + + test('should add the normalized operation id to the spec, if a non-normalized id exists', () => { + // Given + const spec = { + spec: { + paths: { + '/foo': { + get: { + operationId: 'something with spaces', }, }, }, - }; + }, + }; + + // When + const normalizedSpec = normalizeSwagger(spec); + const id = normalizedSpec.spec.paths['/foo'].get.operationId; - // When - const normalizedSpec = normalizeSwagger(spec); - const id = normalizedSpec.spec.paths['/foo'].get.operationId; + // Then + expect(id).toEqual('something_with_spaces'); + }); - // Then - expect(id).toEqual('something_with_spaces'); - }, - ); - - test( - 'should add __originalOperationId for non-duplicate, normal operationIds', - () => { - // Given - const input = { - spec: { - paths: { - '/foo': { - get: { - operationId: 'fooOperation', - }, + test('should add __originalOperationId for non-duplicate, normal operationIds', () => { + // Given + const input = { + spec: { + paths: { + '/foo': { + get: { + operationId: 'fooOperation', }, - '/bar': { - get: { - operationId: 'barOperation', - }, + }, + '/bar': { + get: { + operationId: 'barOperation', }, - '/baz': { - get: { - operationId: 'bazOperation', - }, + }, + '/baz': { + get: { + operationId: 'bazOperation', }, }, }, - }; + }, + }; + + // When + normalizeSwagger(input); + const fooOperation = input.spec.paths['/foo'].get; + const barOperation = input.spec.paths['/bar'].get; + const bazOperation = input.spec.paths['/baz'].get; - // When - normalizeSwagger(input); - const fooOperation = input.spec.paths['/foo'].get; - const barOperation = input.spec.paths['/bar'].get; - const bazOperation = input.spec.paths['/baz'].get; + // Then + expect(fooOperation.operationId).toEqual('fooOperation'); + expect(fooOperation.__originalOperationId).toEqual('fooOperation'); - // Then - expect(fooOperation.operationId).toEqual('fooOperation'); - expect(fooOperation.__originalOperationId).toEqual('fooOperation'); + expect(barOperation.operationId).toEqual('barOperation'); + expect(barOperation.__originalOperationId).toEqual('barOperation'); - expect(barOperation.operationId).toEqual('barOperation'); - expect(barOperation.__originalOperationId).toEqual('barOperation'); + expect(bazOperation.operationId).toEqual('bazOperation'); + expect(bazOperation.__originalOperationId).toEqual('bazOperation'); + }); - expect(bazOperation.operationId).toEqual('bazOperation'); - expect(bazOperation.__originalOperationId).toEqual('bazOperation'); - }, - ); - - test( - 'should add __originalOperationId for non-duplicate, abnormal operationIds', - () => { - // Given - const input = { - spec: { - paths: { - '/foo': { - get: { - operationId: 'foo!Operation', - }, + test('should add __originalOperationId for non-duplicate, abnormal operationIds', () => { + // Given + const input = { + spec: { + paths: { + '/foo': { + get: { + operationId: 'foo!Operation', }, - '/bar': { - get: { - operationId: 'bar!Operation', - }, + }, + '/bar': { + get: { + operationId: 'bar!Operation', }, - '/baz': { - get: { - operationId: 'baz!Operation', - }, + }, + '/baz': { + get: { + operationId: 'baz!Operation', }, }, }, - }; + }, + }; - // When - normalizeSwagger(input); - const fooOperation = input.spec.paths['/foo'].get; - const barOperation = input.spec.paths['/bar'].get; - const bazOperation = input.spec.paths['/baz'].get; + // When + normalizeSwagger(input); + const fooOperation = input.spec.paths['/foo'].get; + const barOperation = input.spec.paths['/bar'].get; + const bazOperation = input.spec.paths['/baz'].get; - // Then - expect(fooOperation.operationId).toEqual('foo_Operation'); - expect(fooOperation.__originalOperationId).toEqual('foo!Operation'); + // Then + expect(fooOperation.operationId).toEqual('foo_Operation'); + expect(fooOperation.__originalOperationId).toEqual('foo!Operation'); - expect(barOperation.operationId).toEqual('bar_Operation'); - expect(barOperation.__originalOperationId).toEqual('bar!Operation'); + expect(barOperation.operationId).toEqual('bar_Operation'); + expect(barOperation.__originalOperationId).toEqual('bar!Operation'); - expect(bazOperation.operationId).toEqual('baz_Operation'); - expect(bazOperation.__originalOperationId).toEqual('baz!Operation'); - }, - ); - - test( - 'should add the original operation id to the spec, if a non-normalized id exists', - () => { - // Given - const spec = { - spec: { - paths: { - '/foo': { - get: { - operationId: 'something with spaces', - }, + expect(bazOperation.operationId).toEqual('baz_Operation'); + expect(bazOperation.__originalOperationId).toEqual('baz!Operation'); + }); + + test('should add the original operation id to the spec, if a non-normalized id exists', () => { + // Given + const spec = { + spec: { + paths: { + '/foo': { + get: { + operationId: 'something with spaces', }, }, }, - }; + }, + }; + + // When + const normalizedSpec = normalizeSwagger(spec); + const originalId = normalizedSpec.spec.paths['/foo'].get.__originalOperationId; - // When - const normalizedSpec = normalizeSwagger(spec); - const originalId = normalizedSpec.spec.paths['/foo'].get.__originalOperationId; + // Then + expect(originalId).toEqual('something with spaces'); + }); - // Then - expect(originalId).toEqual('something with spaces'); - }, - ); - - test( - 'should not set __originalOperationId when operationId is not defined', - () => { - // Given - const spec = { - spec: { - paths: { - '/foo': { - get: { - }, - post: { - operationId: 'myId2', - }, + test('should not set __originalOperationId when operationId is not defined', () => { + // Given + const spec = { + spec: { + paths: { + '/foo': { + get: {}, + post: { + operationId: 'myId2', }, }, }, - }; + }, + }; - // When - const normalizedSpec = normalizeSwagger(spec); - const fooGet = normalizedSpec.spec.paths['/foo'].get; - const fooPost = normalizedSpec.spec.paths['/foo'].post; + // When + const normalizedSpec = normalizeSwagger(spec); + const fooGet = normalizedSpec.spec.paths['/foo'].get; + const fooPost = normalizedSpec.spec.paths['/foo'].post; - // Then - expect(fooPost.__originalOperationId).toEqual('myId2'); - expect(fooGet.__originalOperationId).toEqual(undefined); - }, - ); - - test( - 'should create unique operationIds when explicit operationIds are effectively the same due to whitespace', - () => { - const spec = { - spec: { - paths: { - '/foo': { - get: { - operationId: 'test', - }, + // Then + expect(fooPost.__originalOperationId).toEqual('myId2'); + expect(fooGet.__originalOperationId).toEqual(undefined); + }); + + test('should create unique operationIds when explicit operationIds are effectively the same due to whitespace', () => { + const spec = { + spec: { + paths: { + '/foo': { + get: { + operationId: 'test', }, - '/bar': { - get: { - operationId: 'te st', - }, + }, + '/bar': { + get: { + operationId: 'te st', }, - '/bat': { - get: { - operationId: 'te/st', - }, + }, + '/bat': { + get: { + operationId: 'te/st', }, }, }, - }; + }, + }; - const id = normalizeSwagger(spec); - const id1 = id.spec.paths['/foo'].get.operationId; - const id2 = id.spec.paths['/bar'].get.operationId; - const id3 = id.spec.paths['/bat'].get.operationId; + const id = normalizeSwagger(spec); + const id1 = id.spec.paths['/foo'].get.operationId; + const id2 = id.spec.paths['/bar'].get.operationId; + const id3 = id.spec.paths['/bat'].get.operationId; - // Then - expect(id1).toEqual('test'); - expect(id2).toEqual('te_st1'); - expect(id3).toEqual('te_st2'); - }, - ); + // Then + expect(id1).toEqual('test'); + expect(id2).toEqual('te_st1'); + expect(id3).toEqual('te_st2'); + }); }); describe('consumes', () => { - test( - 'should not overwrite consumes values from the global-level when exists in operation', - () => { - const spec = { - spec: { - consumes: ['application/json'], - paths: { - '/two': { - get: { - consumes: ['application/moar-test'], - }, + test('should not overwrite consumes values from the global-level when exists in operation', () => { + const spec = { + spec: { + consumes: ['application/json'], + paths: { + '/two': { + get: { + consumes: ['application/moar-test'], }, }, }, - }; - - const resultSpec = normalizeSwagger(spec); - - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - consumes: ['application/json'], - paths: { - '/two': { - get: { - consumes: ['application/moar-test'], - }, + }, + }; + + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + consumes: ['application/json'], + paths: { + '/two': { + get: { + consumes: ['application/moar-test'], }, }, }, - }); - }, - ); - - test( - 'should add consumes values from the global-level when no consumes in operation', - () => { - const spec = { - spec: { - consumes: ['application/json'], - paths: { - '/two': { - get: { - }, - }, + }, + }); + }); + + test('should add consumes values from the global-level when no consumes in operation', () => { + const spec = { + spec: { + consumes: ['application/json'], + paths: { + '/two': { + get: {}, }, }, - }; - - const resultSpec = normalizeSwagger(spec); - - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - consumes: ['application/json'], - paths: { - '/two': { - get: { - consumes: ['application/json'], - }, + }, + }; + + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + consumes: ['application/json'], + paths: { + '/two': { + get: { + consumes: ['application/json'], }, }, }, - }); - }, - ); + }, + }); + }); }); describe('produces', () => { - test( - 'should not overwrite produces values from the global-level when exists in operation', - () => { - const spec = { - spec: { - produces: ['application/json'], - paths: { - '/two': { - get: { - produces: ['application/moar-test'], - }, + test('should not overwrite produces values from the global-level when exists in operation', () => { + const spec = { + spec: { + produces: ['application/json'], + paths: { + '/two': { + get: { + produces: ['application/moar-test'], }, }, }, - }; - - const resultSpec = normalizeSwagger(spec); - - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - produces: ['application/json'], - paths: { - '/two': { - get: { - produces: ['application/moar-test'], - }, + }, + }; + + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + produces: ['application/json'], + paths: { + '/two': { + get: { + produces: ['application/moar-test'], }, }, }, - }); - }, - ); - - test( - 'should add produces values from the global-level when no produces in operation', - () => { - const spec = { - spec: { - produces: ['application/json'], - paths: { - '/two': { - get: { - }, - }, + }, + }); + }); + + test('should add produces values from the global-level when no produces in operation', () => { + const spec = { + spec: { + produces: ['application/json'], + paths: { + '/two': { + get: {}, }, }, - }; - - const resultSpec = normalizeSwagger(spec); - - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - produces: ['application/json'], - paths: { - '/two': { - get: { - produces: ['application/json'], - }, + }, + }; + + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + produces: ['application/json'], + paths: { + '/two': { + get: { + produces: ['application/json'], }, }, }, - }); - }, - ); + }, + }); + }); }); describe('security', () => { - test( - 'should not overwrite security values from the global-level when exists in operation', - () => { - const spec = { - spec: { - security: ['test'], - paths: { - '/two': { - get: { - security: ['test1'], - }, + test('should not overwrite security values from the global-level when exists in operation', () => { + const spec = { + spec: { + security: ['test'], + paths: { + '/two': { + get: { + security: ['test1'], }, }, }, - }; - - const resultSpec = normalizeSwagger(spec); - - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - security: ['test'], - paths: { - '/two': { - get: { - security: ['test1'], - }, + }, + }; + + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + security: ['test'], + paths: { + '/two': { + get: { + security: ['test1'], }, }, }, - }); - }, - ); - - test( - 'should add security values from the global-level when no security in operation', - () => { - const spec = { - spec: { - security: ['test1'], - paths: { - '/two': { - get: { - }, - }, + }, + }); + }); + + test('should add security values from the global-level when no security in operation', () => { + const spec = { + spec: { + security: ['test1'], + paths: { + '/two': { + get: {}, }, }, - }; - - const resultSpec = normalizeSwagger(spec); - - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - security: ['test1'], - paths: { - '/two': { - get: { - security: ['test1'], - }, + }, + }; + + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + security: ['test1'], + paths: { + '/two': { + get: { + security: ['test1'], }, }, }, - }); - }, - ); + }, + }); + }); }); describe('parameters', () => { - test( - 'should add parameters from path when no parameters in operation', - () => { - const spec = { - spec: { - paths: { - '/two': { - parameters: [{ name: 'a', in: 'path' }], - get: {}, - }, + test('should add parameters from path when no parameters in operation', () => { + const spec = { + spec: { + paths: { + '/two': { + parameters: [{ name: 'a', in: 'path' }], + get: {}, }, }, - }; + }, + }; - const resultSpec = normalizeSwagger(spec); + const resultSpec = normalizeSwagger(spec); - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - paths: { - '/two': { + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + paths: { + '/two': { + parameters: [{ name: 'a', in: 'path' }], + get: { parameters: [{ name: 'a', in: 'path' }], - get: { - parameters: [{ name: 'a', in: 'path' }], - }, }, }, }, - }); - }, - ); - - test( - 'should add parameters from path but not override parameters in operation', - () => { - const spec = { - spec: { - paths: { - '/two': { + }, + }); + }); + + test('should add parameters from path but not override parameters in operation', () => { + const spec = { + spec: { + paths: { + '/two': { + parameters: [ + { name: 'a', in: 'path' }, + { name: 'b', in: 'path' }, + ], + get: { parameters: [ - { name: 'a', in: 'path' }, - { name: 'b', in: 'path' }, + { name: 'a', in: 'query' }, + { name: 'c', in: 'query' }, ], - get: { - parameters: [ - { name: 'a', in: 'query' }, - { name: 'c', in: 'query' }, - ], - }, }, }, }, - }; - - const resultSpec = normalizeSwagger(spec); + }, + }; - expect(resultSpec).toEqual({ - spec: { - $$normalized: true, - paths: { - '/two': { + const resultSpec = normalizeSwagger(spec); + + expect(resultSpec).toEqual({ + spec: { + $$normalized: true, + paths: { + '/two': { + parameters: [ + { name: 'a', in: 'path' }, + { name: 'b', in: 'path' }, + ], + get: { parameters: [ - { name: 'a', in: 'path' }, + { name: 'a', in: 'query' }, + { name: 'c', in: 'query' }, { name: 'b', in: 'path' }, ], - get: { - parameters: [ - { name: 'a', in: 'query' }, - { name: 'c', in: 'query' }, - { name: 'b', in: 'path' }, - ], - }, }, }, }, - }); - }, - ); + }, + }); + }); }); }); }); diff --git a/test/http-multipart.js b/test/http-multipart.js index 08e0633ce..88993886a 100644 --- a/test/http-multipart.js +++ b/test/http-multipart.js @@ -1,4 +1,5 @@ import fetchMock from 'fetch-mock'; + import FormData from '../src/internal/form-data-monkey-patch'; import { buildRequest } from '../src/execute'; import sampleMultipartOpenApi2 from './data/sample-multipart-oas2'; @@ -23,7 +24,7 @@ describe('buildRequest - openapi 2.0', () => { parameters: { 'formData.hhlContent:sort': 'id', 'formData.hhlContent:order': 'desc', - 'formData.email[]': ["person1", "person2"], // eslint-disable-line quotes + 'formData.email[]': ['person1', 'person2'], // eslint-disable-line quotes 'formData.none[]': ['foo', 'bar'], 'formData.csv[]': ['foo', 'bar'], 'formData.tsv[]': ['foo', 'bar'], @@ -91,7 +92,7 @@ describe('buildRequest - openapi 2.0', () => { * where returnData = req.body/req.files/req.file */ test.skip('should (Live) POST multipart-formdata with entry item entries', () => { - return fetch('http://localhost:3300/api/v1/formdata', { // eslint-disable-line no-undef + return fetch('http://localhost:3300/api/v1/formdata', { method: 'POST', body: req.body, }) @@ -107,22 +108,25 @@ describe('buildRequest - openapi 2.0', () => { test('should Mock POST multipart-formdata with entry item entries', () => { // Given - fetchMock.post('http://localhost:3300/api/v1/formdata', { - status: 200, - body: JSON.stringify({ - message: 'post received', - data: { - 'hhlContent:sort': 'id', - 'hhlContent:order': 'desc', - email: ['person1', 'person2'], - }, - }), - }, - { - sendAsJson: false, - }); + fetchMock.post( + 'http://localhost:3300/api/v1/formdata', + { + status: 200, + body: JSON.stringify({ + message: 'post received', + data: { + 'hhlContent:sort': 'id', + 'hhlContent:order': 'desc', + email: ['person1', 'person2'], + }, + }), + }, + { + sendAsJson: false, + } + ); - return fetch('http://localhost:3300/api/v1/formdata', { // eslint-disable-line no-undef + return fetch('http://localhost:3300/api/v1/formdata', { method: 'POST', body: req.body, }) @@ -150,7 +154,7 @@ describe('buildRequest - openapi 3.0', () => { requestBody: { 'hhlContent:sort': 'id', 'hhlContent:order': 'desc', - 'email[]': ["person1", "person2"], // eslint-disable-line quotes + 'email[]': ['person1', 'person2'], // eslint-disable-line quotes }, }); @@ -183,7 +187,7 @@ describe('buildRequest - openapi 3.0', () => { * where returnData = req.body/req.files/req.file */ test.skip('should (Live) POST multipart-formdata with entry item entries', () => { - return fetch('http://localhost:3300/api/v1/formdata', { // eslint-disable-line no-undef + return fetch('http://localhost:3300/api/v1/formdata', { method: 'POST', body: req.body, }) @@ -199,22 +203,25 @@ describe('buildRequest - openapi 3.0', () => { test('should Mock POST multipart-formdata with entry item entries', () => { // Given - fetchMock.post('http://localhost:3300/api/v1/formdata', { - status: 200, - body: JSON.stringify({ - message: 'post received', - data: { - 'hhlContent:sort': 'id', - 'hhlContent:order': 'desc', - email: ['person1', 'person2'], - }, - }), - }, - { - sendAsJson: false, - }); + fetchMock.post( + 'http://localhost:3300/api/v1/formdata', + { + status: 200, + body: JSON.stringify({ + message: 'post received', + data: { + 'hhlContent:sort': 'id', + 'hhlContent:order': 'desc', + email: ['person1', 'person2'], + }, + }), + }, + { + sendAsJson: false, + } + ); - return fetch('http://localhost:3300/api/v1/formdata', { // eslint-disable-line no-undef + return fetch('http://localhost:3300/api/v1/formdata', { method: 'POST', body: req.body, }) @@ -321,7 +328,11 @@ describe('buildRequest - openapi 3.0', () => { }, }); - expect(Array.from(req.body.entryList)).toEqual([{ name: 'color[R]', value: '100' }, { name: 'color[G]', value: '200' }, { name: 'color[B]', value: '150' }]); + expect(Array.from(req.body.entryList)).toEqual([ + { name: 'color[R]', value: '100' }, + { name: 'color[G]', value: '200' }, + { name: 'color[B]', value: '150' }, + ]); }); }); }); diff --git a/test/http.js b/test/http.js index 094e6dd2f..a5ecef476 100644 --- a/test/http.js +++ b/test/http.js @@ -1,8 +1,13 @@ import xmock from 'xmock'; import fetchMock from 'fetch-mock'; + import http, { - serializeHeaders, mergeInQueryOrForm, encodeFormOrQuery, serializeRes, - shouldDownloadAsText, isFile, + serializeHeaders, + mergeInQueryOrForm, + encodeFormOrQuery, + serializeRes, + shouldDownloadAsText, + isFile, } from '../src/http'; describe('http', () => { @@ -20,11 +25,10 @@ describe('http', () => { return http({ url: 'http://swagger.io', - }) - .then((res) => { - expect(res.status).toEqual(200); - expect(res.text).toEqual('hi'); - }); + }).then((res) => { + expect(res.status).toEqual(200); + expect(res.text).toEqual('hi'); + }); }); test('should always load a spec as text', () => { @@ -46,17 +50,16 @@ describe('http', () => { return http({ url: 'http://swagger.io', - }) - .then( - () => { - throw new Error('Expected rejection for HTTP status 400'); - }, - (err) => { - expect(err.status).toEqual(400); - expect(err.statusCode).toEqual(400); - expect(err.response.text).toEqual('hi'); - }, - ); + }).then( + () => { + throw new Error('Expected rejection for HTTP status 400'); + }, + (err) => { + expect(err.status).toEqual(400); + expect(err.statusCode).toEqual(400); + expect(err.response.text).toEqual('hi'); + } + ); }); test('should call request interceptor', () => { @@ -69,12 +72,9 @@ describe('http', () => { req.headers.mystatus = 200; return req; }, - }) - .then( - (res) => { - expect(res.status).toEqual(200); - }, - ); + }).then((res) => { + expect(res.status).toEqual(200); + }); }); test('should allow the requestInterceptor to return a promise', () => { @@ -91,12 +91,9 @@ describe('http', () => { }, 20); }); }, - }) - .then( - (res) => { - expect(res.status).toEqual(200); - }, - ); + }).then((res) => { + expect(res.status).toEqual(200); + }); }); test('should apply responseInterceptor to error responses', () => { @@ -108,38 +105,33 @@ describe('http', () => { responseInterceptor: (res) => { res.testValue = 5; }, - }) - .then( - () => { - throw new Error('Expected rejection for HTTP status 400'); - }, - (err) => { - expect(err.response.testValue).toEqual(5); - }, - ); + }).then( + () => { + throw new Error('Expected rejection for HTTP status 400'); + }, + (err) => { + expect(err.response.testValue).toEqual(5); + } + ); }); - test( - 'should allow the responseInterceptor to return a promise for a final response', - () => { - xapp = xmock(); - xapp.get('http://swagger.io', (req, res) => res.status(400).send('doit')); - xapp.get('http://example.com', (req, res) => res.send('hi')); - - return http({ - url: 'http://swagger.io', - responseInterceptor: () => { - return http({ - url: 'http://example.com', - }); - }, - }) - .then((res) => { - expect(res.status).toEqual(200); - expect(res.text).toEqual('hi'); + test('should allow the responseInterceptor to return a promise for a final response', () => { + xapp = xmock(); + xapp.get('http://swagger.io', (req, res) => res.status(400).send('doit')); + xapp.get('http://example.com', (req, res) => res.send('hi')); + + return http({ + url: 'http://swagger.io', + responseInterceptor: () => { + return http({ + url: 'http://example.com', }); - }, - ); + }, + }).then((res) => { + expect(res.status).toEqual(200); + expect(res.text).toEqual('hi'); + }); + }); test('should set responseError on responseInterceptor Error', () => { xapp = xmock(); @@ -151,16 +143,15 @@ describe('http', () => { responseInterceptor: () => { throw testError; }, - }) - .then( - () => { - throw new Error('Expected rejection for HTTP status 400'); - }, - (err) => { - expect(err.response).toBeFalsy(); - expect(err.responseError).toBe(testError); - }, - ); + }).then( + () => { + throw new Error('Expected rejection for HTTP status 400'); + }, + (err) => { + expect(err.response).toBeFalsy(); + expect(err.responseError).toBe(testError); + } + ); }); describe('serializeHeaders', () => { @@ -306,17 +297,22 @@ describe('http', () => { query: { anotherOne: ['one', 'two'], // No collection format evenMore: 'hi', // string, not an array - bar: { // has a collectionFormat, so we need a way of indicating it + bar: { + // has a collectionFormat, so we need a way of indicating it collectionFormat: 'ssv', value: [1, 2, 3], }, }, }; - return http('http://example.com', req).then((response) => { - expect(response.url).toEqual('http://example.com/?anotherOne=one,two&evenMore=hi&bar=1%202%203'); - expect(response.status).toEqual(200); - }).then(fetchMock.restore); + return http('http://example.com', req) + .then((response) => { + expect(response.url).toEqual( + 'http://example.com/?anotherOne=one,two&evenMore=hi&bar=1%202%203' + ); + expect(response.status).toEqual(200); + }) + .then(fetchMock.restore); }); test('should remove newlines from header values', () => { @@ -337,58 +333,56 @@ describe('http', () => { }, }; - return http('http://example.com', req).then((response) => { - expect(response.url).toEqual('http://example.com/'); - expect(response.data.toString()).toEqual( - 'so much depends upon a red wheel barrow', - ); - }).then(fetchMock.restore); + return http('http://example.com', req) + .then((response) => { + expect(response.url).toEqual('http://example.com/'); + expect(response.data.toString()).toEqual('so much depends upon a red wheel barrow'); + }) + .then(fetchMock.restore); }); }); describe('serializeRes', () => { - test( - 'should serialize fetch-like response and call serializeHeaders', - () => { - // cross-fetch exposes FetchAPI methods onto global - require('cross-fetch/polyfill'); - const response = new Response('data', { // eslint-disable-line no-undef - status: 200, - headers: { - Authorization: 'Basic hoop-la, Advanced hoop-la', - 'Content-Type': 'text/plain', - }, - }); + test('should serialize fetch-like response and call serializeHeaders', () => { + // cross-fetch exposes FetchAPI methods onto global + require('cross-fetch/polyfill'); + const response = new Response('data', { + // eslint-disable-line no-undef + status: 200, + headers: { + Authorization: 'Basic hoop-la, Advanced hoop-la', + 'Content-Type': 'text/plain', + }, + }); - return serializeRes(response, 'https://swagger.io') - .then((serializedResponse) => { - expect(serializedResponse.headers).toEqual({ - authorization: ['Basic hoop-la', 'Advanced hoop-la'], - 'content-type': 'text/plain', - }); - }); - }, - ); + return serializeRes(response, 'https://swagger.io').then((serializedResponse) => { + expect(serializedResponse.headers).toEqual({ + authorization: ['Basic hoop-la', 'Advanced hoop-la'], + 'content-type': 'text/plain', + }); + }); + }); - test( - 'should set .text and .data to body Blob or Buffer for binary response', - () => { - // cross-fetch exposes FetchAPI methods onto global - require('cross-fetch/polyfill'); + test('should set .text and .data to body Blob or Buffer for binary response', () => { + // cross-fetch exposes FetchAPI methods onto global + require('cross-fetch/polyfill'); - const headers = { - 'Content-Type': 'application/octet-stream', - }; + const headers = { + 'Content-Type': 'application/octet-stream', + }; - const body = 'body data'; - fetchMock.mock('http://swagger.io', { body, headers }); + const body = 'body data'; + fetchMock.mock('http://swagger.io', { body, headers }); - let originalRes; + let originalRes; - return fetch('http://swagger.io').then((_res) => { // eslint-disable-line no-undef + return fetch('http://swagger.io') + .then((_res) => { + // eslint-disable-line no-undef originalRes = _res; return serializeRes(_res, 'https://swagger.io'); - }).then((resSerialize) => { + }) + .then((resSerialize) => { expect(resSerialize.data).toBe(resSerialize.text); if (originalRes.blob) { expect(Object.prototype.toString.call(resSerialize.data)).toBe('[object Blob]'); @@ -396,34 +390,38 @@ describe('http', () => { expect(resSerialize.data).toBeInstanceOf(Buffer); expect(resSerialize.data).toEqual(Buffer.from(body)); } - }).then(fetchMock.restore); - }, - ); + }) + .then(fetchMock.restore); + }); - test( - 'should set .text and .data to body string for text response', - () => { - const headers = { - 'Content-Type': 'application/json', - }; + test('should set .text and .data to body string for text response', () => { + const headers = { + 'Content-Type': 'application/json', + }; - const body = '{}'; - fetchMock.mock('http://swagger.io', { body, headers }); + const body = '{}'; + fetchMock.mock('http://swagger.io', { body, headers }); - return fetch('http://swagger.io').then((_res) => { // eslint-disable-line no-undef + return fetch('http://swagger.io') + .then((_res) => { + // eslint-disable-line no-undef return serializeRes(_res, 'https://swagger.io'); - }).then((resSerialize) => { + }) + .then((resSerialize) => { expect(resSerialize.data).toBe(resSerialize.text); expect(resSerialize.data).toBe(body); - }).then(fetchMock.restore); - }, - ); + }) + .then(fetchMock.restore); + }); }); describe('shouldDownloadAsText', () => { test('should return true for json, xml, yaml, and text types', () => { const types = [ - 'text/x-yaml', 'application/xml', 'text/xml', 'application/json', + 'text/x-yaml', + 'application/xml', + 'text/xml', + 'application/json', 'text/plain', ]; @@ -433,9 +431,7 @@ describe('http', () => { }); test('should return false for other common types', () => { - const types = [ - 'application/octet-stream', 'application/x-binary', - ]; + const types = ['application/octet-stream', 'application/x-binary']; types.forEach((v) => { expect(`${v} ${shouldDownloadAsText(v)}`).toEqual(`${v} false`); diff --git a/test/index-authorizations.js b/test/index-authorizations.js index 9568dace8..02c441f1b 100644 --- a/test/index-authorizations.js +++ b/test/index-authorizations.js @@ -127,7 +127,7 @@ describe('(instance) #execute', () => { expect(http.mock.calls.length).toEqual(1); expect(http.mock.calls[0][0]).toEqual({ credentials: 'same-origin', - headers: { }, + headers: {}, method: 'GET', url: '/pet?petKey=barFoo', }); diff --git a/test/index.js b/test/index.js index e261081b3..545440c3e 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,5 @@ import xmock from 'xmock'; + import Swagger from '../src/index'; describe('constructor', () => { @@ -122,36 +123,33 @@ describe('constructor', () => { }); }); - test( - 'should honor `v2OperationIdCompatibilityMode` when building `apis`', - () => { - // Given - const spec = { - swagger: '2.0', - paths: { - '/foo/{bar}/baz': { - get: { - description: '', - tags: ['myTag'], - }, + test('should honor `v2OperationIdCompatibilityMode` when building `apis`', () => { + // Given + const spec = { + swagger: '2.0', + paths: { + '/foo/{bar}/baz': { + get: { + description: '', + tags: ['myTag'], }, }, - }; + }, + }; - // When - return Swagger({ - spec, - v2OperationIdCompatibilityMode: true, - }).then((swag) => { - const { apis } = swag; + // When + return Swagger({ + spec, + v2OperationIdCompatibilityMode: true, + }).then((swag) => { + const { apis } = swag; - // Then - expect(typeof apis).toBe('object'); - expect(typeof apis.myTag).toBe('object'); - expect(apis.myTag.get_foo_bar_baz).toBeInstanceOf(Function); - }); - }, - ); + // Then + expect(typeof apis).toBe('object'); + expect(typeof apis.myTag).toBe('object'); + expect(apis.myTag.get_foo_bar_baz).toBeInstanceOf(Function); + }); + }); test('should handle circular $refs when a baseDoc is provided', () => { // Given @@ -199,12 +197,11 @@ describe('constructor', () => { res.send('not found'); }); - new Swagger({ url: 'http://petstore.swagger.io/404' }) - .catch((err) => { - expect(err.status).toBe(404); - expect(err.message).toBe('Not Found'); - cb(); - }); + new Swagger({ url: 'http://petstore.swagger.io/404' }).catch((err) => { + expect(err.status).toBe(404); + expect(err.message).toBe('Not Found'); + cb(); + }); }); test('should serialize the response', () => { @@ -219,29 +216,28 @@ describe('constructor', () => { url: 'https://swagger.io/one', }; - return Swagger.http(req) - .then((res) => { - expect(res).toMatchObject({ - url: req.url, - ok: true, - status: 200, - headers: { - connection: 'close', - 'content-type': 'application/json', - - hi: 'ho', - }, - statusText: 'OK', - data: '{"me":true}', - text: '{"me":true}', - body: { - me: true, - }, - obj: { - me: true, - }, - }); + return Swagger.http(req).then((res) => { + expect(res).toMatchObject({ + url: req.url, + ok: true, + status: 200, + headers: { + connection: 'close', + 'content-type': 'application/json', + + hi: 'ho', + }, + statusText: 'OK', + data: '{"me":true}', + text: '{"me":true}', + body: { + me: true, + }, + obj: { + me: true, + }, }); + }); }); test('should handle invalid JSON bodies', () => { @@ -254,13 +250,12 @@ describe('constructor', () => { url: 'https://swagger.io/one', }; - return Swagger.http(req) - .then((res) => { - const { body, text, status } = res; - expect(status).toEqual(200); - expect(text).toEqual('['); - expect(body).toEqual(); - }); + return Swagger.http(req).then((res) => { + const { body, text, status } = res; + expect(status).toEqual(200); + expect(text).toEqual('['); + expect(body).toEqual(); + }); }); }); @@ -288,32 +283,29 @@ describe('constructor', () => { }); }); - test( - 'should respect the `withCredentials` flag on the http agent', - () => { - const spec = { - paths: { - '/pet': { - get: { - operationId: 'getPets', - }, + test('should respect the `withCredentials` flag on the http agent', () => { + const spec = { + paths: { + '/pet': { + get: { + operationId: 'getPets', }, }, - }; - return Swagger({ spec }).then((client) => { - const http = jest.fn(); - http.withCredentials = true; - client.execute({ http, operationId: 'getPets' }); - expect(http.mock.calls.length).toEqual(1); - expect(http.mock.calls[0][0]).toEqual({ - headers: {}, - method: 'GET', - credentials: 'include', - url: '/pet', - }); + }, + }; + return Swagger({ spec }).then((client) => { + const http = jest.fn(); + http.withCredentials = true; + client.execute({ http, operationId: 'getPets' }); + expect(http.mock.calls.length).toEqual(1); + expect(http.mock.calls[0][0]).toEqual({ + headers: {}, + method: 'GET', + credentials: 'include', + url: '/pet', }); - }, - ); + }); + }); test('should add basic auth to a request', () => { const spec = { @@ -420,7 +412,7 @@ describe('constructor', () => { client.execute({ http, operationId: 'getPets' }); expect(http.mock.calls.length).toEqual(1); expect(http.mock.calls[0][0]).toEqual({ - headers: { }, + headers: {}, method: 'GET', credentials: 'same-origin', url: '/pet?petKey=barFoo', @@ -468,49 +460,46 @@ describe('constructor', () => { }); }); - test( - 'should not add an empty oAuth2 Bearer token header to a request', - () => { - const spec = { - securityDefinitions: { - bearer: { - description: 'Bearer authorization token', - type: 'oauth2', - name: 'Authorization', - in: 'header', - }, + test('should not add an empty oAuth2 Bearer token header to a request', () => { + const spec = { + securityDefinitions: { + bearer: { + description: 'Bearer authorization token', + type: 'oauth2', + name: 'Authorization', + in: 'header', }, - security: [{ bearer: [] }], - paths: { - '/pet': { - get: { - operationId: 'getPets', - }, + }, + security: [{ bearer: [] }], + paths: { + '/pet': { + get: { + operationId: 'getPets', }, }, - }; + }, + }; - const authorizations = { - bearer: { - token: { - access_token: '', - }, + const authorizations = { + bearer: { + token: { + access_token: '', }, - }; - - return Swagger({ spec, authorizations }).then((client) => { - const http = jest.fn(); - client.execute({ http, operationId: 'getPets' }); - expect(http.mock.calls.length).toEqual(1); - expect(http.mock.calls[0][0]).toEqual({ - headers: {}, - credentials: 'same-origin', - method: 'GET', - url: '/pet', - }); + }, + }; + + return Swagger({ spec, authorizations }).then((client) => { + const http = jest.fn(); + client.execute({ http, operationId: 'getPets' }); + expect(http.mock.calls.length).toEqual(1); + expect(http.mock.calls[0][0]).toEqual({ + headers: {}, + credentials: 'same-origin', + method: 'GET', + url: '/pet', }); - }, - ); + }); + }); test('should add global securites', () => { const spec = { @@ -644,11 +633,9 @@ describe('constructor', () => { .get('http://petstore.swagger.io/v2/pet/3', () => ({ id: 3 })) .get('http://petstore.swagger.io/v2/pet/4', () => ({ id: 4 })) .get('http://petstore.swagger.io/v2/ref.json', () => ({ b: 2 })) - .get('http://petstore.swagger.io/v2/base.json', () => ( - { - $ref: 'http://petstore.swagger.io/v2/ref.json#b', - } - )); + .get('http://petstore.swagger.io/v2/base.json', () => ({ + $ref: 'http://petstore.swagger.io/v2/ref.json#b', + })); }); test('should support request interceptor', (cb) => { @@ -683,52 +670,49 @@ describe('constructor', () => { }, cb); }); - test( - 'should support request interceptor when fetching a spec and remote ref', - (cb) => { - const spy = jest.fn().mockImplementation((a) => a); - new Swagger({ - url: 'http://petstore.swagger.io/v2/base.json', - requestInterceptor: spy, - }).then(() => { + test('should support request interceptor when fetching a spec and remote ref', (cb) => { + const spy = jest.fn().mockImplementation((a) => a); + new Swagger({ + url: 'http://petstore.swagger.io/v2/base.json', + requestInterceptor: spy, + }) + .then(() => { expect(spy.mock.calls.length).toEqual(2); cb(); - }).catch(cb); - }, - ); - - test( - 'should support response interceptor when fetching a spec and remote ref', - (cb) => { - const spy = jest.fn().mockImplementation((a) => { - return a; - }); + }) + .catch(cb); + }); + + test('should support response interceptor when fetching a spec and remote ref', (cb) => { + const spy = jest.fn().mockImplementation((a) => { + return a; + }); - new Swagger({ - url: 'http://petstore.swagger.io/v2/base.json', - responseInterceptor: spy, - }).then(() => { + new Swagger({ + url: 'http://petstore.swagger.io/v2/base.json', + responseInterceptor: spy, + }) + .then(() => { expect(spy.mock.calls.length).toEqual(2); cb(); - }).catch(cb); - }, - ); - - test( - 'should support request and response interceptor when fetching a spec and remote ref', - (cb) => { - const reqSpy = jest.fn().mockImplementation((a) => a); - const resSpy = jest.fn().mockImplementation((a) => a); - new Swagger({ - url: 'http://petstore.swagger.io/v2/base.json', - responseInterceptor: reqSpy, - requestInterceptor: resSpy, - }).then(() => { + }) + .catch(cb); + }); + + test('should support request and response interceptor when fetching a spec and remote ref', (cb) => { + const reqSpy = jest.fn().mockImplementation((a) => a); + const resSpy = jest.fn().mockImplementation((a) => a); + new Swagger({ + url: 'http://petstore.swagger.io/v2/base.json', + responseInterceptor: reqSpy, + requestInterceptor: resSpy, + }) + .then(() => { expect(reqSpy.mock.calls.length).toEqual(2); expect(resSpy.mock.calls.length).toEqual(2); cb(); - }).catch(cb); - }, - ); + }) + .catch(cb); + }); }); }); diff --git a/test/interfaces.js b/test/interfaces.js index 0d29eb031..76ba3cc85 100644 --- a/test/interfaces.js +++ b/test/interfaces.js @@ -14,7 +14,7 @@ describe('intefaces', () => { test('should call mapTagOperations with { spec, cb:Function }', () => { // Given const spyMapTagOperations = jest.spyOn(stubs, 'mapTagOperations'); - const spec = { }; + const spec = {}; // When makeApisTagOperation({ spec }); @@ -73,7 +73,7 @@ describe('intefaces', () => { test('should call mapTagOperations with { spec, cb:Function }', () => { // Given const spyMapTagOperations = jest.spyOn(stubs, 'mapTagOperations'); - const spec = { }; + const spec = {}; // When makeApisTagOperationsOperationExecute({ spec }); @@ -125,7 +125,7 @@ describe('intefaces', () => { expect(interfaceValue).toMatchObject({ apis: { - default: { operations: { } }, + default: { operations: {} }, me: { operations: {} }, }, }); @@ -182,64 +182,58 @@ describe('intefaces', () => { }); }); - test( - 'should put the result of the `cb` prop into the operation method', - () => { - // Given - const spec = { - paths: { - one: { - get: { - tags: ['alpha'], - operationId: 'getOne', - }, + test('should put the result of the `cb` prop into the operation method', () => { + // Given + const spec = { + paths: { + one: { + get: { + tags: ['alpha'], + operationId: 'getOne', }, }, - }; - const spy = jest.fn().mockImplementation(() => 'hug'); + }, + }; + const spy = jest.fn().mockImplementation(() => 'hug'); - // With - const tags = mapTagOperations({ spec, cb: spy }); + // With + const tags = mapTagOperations({ spec, cb: spy }); - // Then - expect(tags).toEqual({ - alpha: { - getOne: 'hug', - }, - }); - }, - ); - - test( - 'should call the `cb` prop with the operation object, the spec and the path and the method ', - () => { - // Given - const spec = { - paths: { - one: { - get: { - tags: ['alpha'], - operationId: 'getOne', - }, + // Then + expect(tags).toEqual({ + alpha: { + getOne: 'hug', + }, + }); + }); + + test('should call the `cb` prop with the operation object, the spec and the path and the method ', () => { + // Given + const spec = { + paths: { + one: { + get: { + tags: ['alpha'], + operationId: 'getOne', }, }, - }; - const spy = jest.fn(); - - // With - mapTagOperations({ spec, cb: spy }); - - // Then - expect(spy.mock.calls.length).toEqual(1); - expect(spy.mock.calls[0][0]).toEqual({ - operation: spec.paths.one.get, - pathName: 'one', - method: 'GET', - operationId: 'getOne', - spec, - }); - }, - ); + }, + }; + const spy = jest.fn(); + + // With + mapTagOperations({ spec, cb: spy }); + + // Then + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0][0]).toEqual({ + operation: spec.paths.one.get, + pathName: 'one', + method: 'GET', + operationId: 'getOne', + spec, + }); + }); test('should group multiple operations with the same tag', () => { // Given @@ -348,40 +342,37 @@ describe('intefaces', () => { }); }); - test( - 'should remap duplicate operationId as {operationId}{count} starting at 1', - () => { - // Given - const spec = { - paths: { - one: { - get: { - operationId: 'getOne', - }, - put: { - operationId: 'getOne', - }, - post: { - operationId: 'getOne', - }, + test('should remap duplicate operationId as {operationId}{count} starting at 1', () => { + // Given + const spec = { + paths: { + one: { + get: { + operationId: 'getOne', + }, + put: { + operationId: 'getOne', + }, + post: { + operationId: 'getOne', }, }, - }; - - // With - let count = 1; - // eslint-disable-next-line no-return-assign, no-plusplus - const tags = mapTagOperations({ spec, defaultTag: 'hug', cb: () => count++ }); - - // Then - expect(tags).toEqual({ - hug: { - getOne1: 1, - getOne2: 2, - getOne3: 3, - }, - }); - }, - ); + }, + }; + + // With + let count = 1; + // eslint-disable-next-line no-return-assign, no-plusplus + const tags = mapTagOperations({ spec, defaultTag: 'hug', cb: () => count++ }); + + // Then + expect(tags).toEqual({ + hug: { + getOne1: 1, + getOne2: 2, + getOne3: 3, + }, + }); + }); }); }); diff --git a/test/oas3/client.js b/test/oas3/client.js index a15663787..ed8c407e5 100644 --- a/test/oas3/client.js +++ b/test/oas3/client.js @@ -8,55 +8,56 @@ import Swagger from '../../src/index'; describe('http - OpenAPI Specification 3.0', () => { let server; beforeAll(() => { - server = http.createServer((req, res) => { - const { accept } = req.headers; - let contentType; - const uri = url.parse(req.url).pathname; - const filename = path.join('test', 'oas3', 'data', uri); + server = http + .createServer((req, res) => { + const { accept } = req.headers; + let contentType; + const uri = url.parse(req.url).pathname; + const filename = path.join('test', 'oas3', 'data', uri); - if (filename.indexOf('.yaml') > 0) { - contentType = 'application/yaml'; - } else { - contentType = 'application/json'; - } - - if (typeof accept !== 'undefined') { - if (accept === 'invalid') { - res.writeHead(500); - res.end(); - return; - } - - if (accept.indexOf('application/json') >= 0) { - contentType = accept; - res.setHeader('Content-Type', contentType); - } if (filename.indexOf('.yaml') > 0) { - res.setHeader('Content-Type', 'application/yaml'); + contentType = 'application/yaml'; + } else { + contentType = 'application/json'; } - } - fs.exists(filename, (exists) => { - if (exists) { - const fileStream = fs.createReadStream(filename); - res.setHeader('Access-Control-Allow-Origin', '*'); - res.writeHead(200, contentType); - fileStream.pipe(res); - } else { - res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.write('404 Not Found\n'); - res.end(); + if (typeof accept !== 'undefined') { + if (accept === 'invalid') { + res.writeHead(500); + res.end(); + return; + } + + if (accept.indexOf('application/json') >= 0) { + contentType = accept; + res.setHeader('Content-Type', contentType); + } + if (filename.indexOf('.yaml') > 0) { + res.setHeader('Content-Type', 'application/yaml'); + } } - }); - }).listen(8000); + + fs.exists(filename, (exists) => { + if (exists) { + const fileStream = fs.createReadStream(filename); + res.setHeader('Access-Control-Allow-Origin', '*'); + res.writeHead(200, contentType); + fileStream.pipe(res); + } else { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.write('404 Not Found\n'); + res.end(); + } + }); + }) + .listen(8000); }); afterAll(() => { server.close(); }); - afterEach(() => { - }); + afterEach(() => {}); test('should get the petstore api and build it', (done) => { Swagger('http://localhost:8000/petstore-oas3.yaml') diff --git a/test/oas3/execute/authorization.js b/test/oas3/execute/authorization.js index e6f5cbbe3..08e97df81 100644 --- a/test/oas3/execute/authorization.js +++ b/test/oas3/execute/authorization.js @@ -58,9 +58,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myBasicAuth: [], - }], + security: [ + { + myBasicAuth: [], + }, + ], }, }, }, @@ -105,9 +107,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myBasicAuth: [], - }], + security: [ + { + myBasicAuth: [], + }, + ], }, }, }, @@ -136,99 +140,95 @@ describe('Authorization - OpenAPI Specification 3.0', () => { }); }); - test( - 'should not add credentials to operations without the security requirement', - () => { - const spec = { - openapi: '3.0.0', - components: { - securitySchemes: { - myBasicAuth: { - type: 'http', - scheme: 'basic', - }, + test('should not add credentials to operations without the security requirement', () => { + const spec = { + openapi: '3.0.0', + components: { + securitySchemes: { + myBasicAuth: { + type: 'http', + scheme: 'basic', }, }, - paths: { - '/': { - get: { - operationId: 'myOperation', - }, + }, + paths: { + '/': { + get: { + operationId: 'myOperation', }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - securities: { - authorized: { - myBasicAuth: { - username: 'somebody', - password: 'goodpass', - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + securities: { + authorized: { + myBasicAuth: { + username: 'somebody', + password: 'goodpass', }, }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - test( - 'should allow empty password without casting undefined to string', - () => { - const spec = { - openapi: '3.0.0', - components: { - securitySchemes: { - myBasicAuth: { - type: 'http', - scheme: 'basic', - }, + expect(req).toEqual({ + method: 'GET', + url: '/', + credentials: 'same-origin', + headers: {}, + }); + }); + test('should allow empty password without casting undefined to string', () => { + const spec = { + openapi: '3.0.0', + components: { + securitySchemes: { + myBasicAuth: { + type: 'http', + scheme: 'basic', }, }, - paths: { - '/': { - get: { - operationId: 'myOperation', - security: [{ + }, + paths: { + '/': { + get: { + operationId: 'myOperation', + security: [ + { myBasicAuth: [], - }], - }, + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - securities: { - authorized: { - myBasicAuth: { - username: 'somebody', - password: undefined, - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + securities: { + authorized: { + myBasicAuth: { + username: 'somebody', + password: undefined, }, }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/', - credentials: 'same-origin', - headers: { - Authorization: `Basic ${btoa('somebody:')}`, - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/', + credentials: 'same-origin', + headers: { + Authorization: `Basic ${btoa('somebody:')}`, + }, + }); + }); }); describe('Bearer', () => { test('should add token to the Authorization header', () => { @@ -246,9 +246,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myBearerAuth: [], - }], + security: [ + { + myBearerAuth: [], + }, + ], }, }, }, @@ -292,9 +294,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myBearerAuth: [], - }], + security: [ + { + myBearerAuth: [], + }, + ], }, }, }, @@ -323,49 +327,46 @@ describe('Authorization - OpenAPI Specification 3.0', () => { }); }); - test( - 'should not add credentials to operations without the security requirement', - () => { - const spec = { - openapi: '3.0.0', - components: { - securitySchemes: { - myBearerAuth: { - type: 'http', - scheme: 'bearer', - }, + test('should not add credentials to operations without the security requirement', () => { + const spec = { + openapi: '3.0.0', + components: { + securitySchemes: { + myBearerAuth: { + type: 'http', + scheme: 'bearer', }, }, - paths: { - '/': { - get: { - operationId: 'myOperation', - }, + }, + paths: { + '/': { + get: { + operationId: 'myOperation', }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - securities: { - authorized: { - myBearerAuth: { - value: 'Asdf1234', - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + securities: { + authorized: { + myBearerAuth: { + value: 'Asdf1234', }, }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/', + credentials: 'same-origin', + headers: {}, + }); + }); }); }); @@ -386,9 +387,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myApiKey: [], - }], + security: [ + { + myApiKey: [], + }, + ], }, }, }, @@ -432,9 +435,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myApiKey: [], - }], + security: [ + { + myApiKey: [], + }, + ], }, }, }, @@ -476,9 +481,11 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [{ - myApiKey: [], - }], + security: [ + { + myApiKey: [], + }, + ], }, }, }, @@ -506,66 +513,63 @@ describe('Authorization - OpenAPI Specification 3.0', () => { }, }); }); - test( - 'should not add credentials if operation does not call for security', - () => { - const spec = { - openapi: '3.0.0', - components: { - securitySchemes: { - myApiKeyCookie: { - type: 'apiKey', - name: 'MyApiKeyCookie', - in: 'cookie', - }, - MyApiKeyHeader: { - type: 'apiKey', - name: 'MyApiKeyHeader', - in: 'header', - }, - myApiKeyQuery: { - type: 'apiKey', - name: 'myApiKeyQuery', - in: 'query', - }, + test('should not add credentials if operation does not call for security', () => { + const spec = { + openapi: '3.0.0', + components: { + securitySchemes: { + myApiKeyCookie: { + type: 'apiKey', + name: 'MyApiKeyCookie', + in: 'cookie', + }, + MyApiKeyHeader: { + type: 'apiKey', + name: 'MyApiKeyHeader', + in: 'header', + }, + myApiKeyQuery: { + type: 'apiKey', + name: 'myApiKeyQuery', + in: 'query', }, }, - paths: { - '/': { - get: { - operationId: 'myOperation', - }, + }, + paths: { + '/': { + get: { + operationId: 'myOperation', }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - securities: { - authorized: { - myApiKeyQuery: { - value: 'test', - }, - MyApiKeyHeader: { - value: 'test', - }, - myApiKeyCookie: { - value: 'test', - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + securities: { + authorized: { + myApiKeyQuery: { + value: 'test', + }, + MyApiKeyHeader: { + value: 'test', + }, + myApiKeyCookie: { + value: 'test', }, }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/', + credentials: 'same-origin', + headers: {}, + }); + }); }); describe('OAuth2', () => { @@ -591,9 +595,7 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [ - { myOAuth2Implicit: [] }, - ], + security: [{ myOAuth2Implicit: [] }], }, }, }, @@ -626,9 +628,7 @@ describe('Authorization - OpenAPI Specification 3.0', () => { test('should build a request with a global security', () => { const spec = { openapi: '3.0.0', - security: [ - { myOAuth2Implicit: [] }, - ], + security: [{ myOAuth2Implicit: [] }], components: { securitySchemes: { myOAuth2Implicit: { @@ -677,58 +677,55 @@ describe('Authorization - OpenAPI Specification 3.0', () => { }, }); }); - test( - 'should build a request without authorization when spec does not require it', - () => { - const spec = { - openapi: '3.0.0', - components: { - securitySchemes: { - myOAuth2Implicit: { - type: 'oauth2', - flows: { - implicit: { - authorizationUrl: 'http://google.com/', - scopes: { - myScope: 'blah blah blah', - }, + test('should build a request without authorization when spec does not require it', () => { + const spec = { + openapi: '3.0.0', + components: { + securitySchemes: { + myOAuth2Implicit: { + type: 'oauth2', + flows: { + implicit: { + authorizationUrl: 'http://google.com/', + scopes: { + myScope: 'blah blah blah', }, }, }, }, }, - paths: { - '/': { - get: { - operationId: 'myOperation', - }, + }, + paths: { + '/': { + get: { + operationId: 'myOperation', }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - securities: { - authorized: { - myOAuth2Implicit: { - token: { - access_token: 'myTokenValue', - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + securities: { + authorized: { + myOAuth2Implicit: { + token: { + access_token: 'myTokenValue', }, }, }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/', + credentials: 'same-origin', + headers: {}, + }); + }); }); test('should use a custom oAuth token name if defined', () => { const spec = { @@ -745,9 +742,7 @@ describe('Authorization - OpenAPI Specification 3.0', () => { '/': { get: { operationId: 'myOperation', - security: [ - { myOAuth2Implicit: [] }, - ], + security: [{ myOAuth2Implicit: [] }], }, }, }, diff --git a/test/oas3/execute/main.js b/test/oas3/execute/main.js index 9829d0aaa..af97045c9 100644 --- a/test/oas3/execute/main.js +++ b/test/oas3/execute/main.js @@ -5,7 +5,9 @@ import { escape } from 'querystring'; import { buildRequest, baseUrl } from '../../../src/execute'; -const petstoreSpec = jsYaml.safeLoad(fs.readFileSync(path.join('test', 'oas3', 'data', 'petstore-oas3.yaml'), 'utf8')); +const petstoreSpec = jsYaml.safeLoad( + fs.readFileSync(path.join('test', 'oas3', 'data', 'petstore-oas3.yaml'), 'utf8') +); // Supported shape... { spec, operationId, parameters, securities, fetch } // One can use operationId or pathItem + method @@ -508,7 +510,11 @@ describe('buildRequest - OpenAPI Specification 3.0', () => { }; // When - const req = buildRequest({ spec, operationId: 'getMe', requestContentType: 'application/josh' }); + const req = buildRequest({ + spec, + operationId: 'getMe', + requestContentType: 'application/josh', + }); // Then expect(req).toEqual({ @@ -653,7 +659,8 @@ describe('buildRequest - OpenAPI Specification 3.0', () => { const res = baseUrl({ spec, - contextUrl: 'https://gist.githubusercontent.com/hkosova/d223eb45c5198db09d08f2603cc0e10a/raw/ae22e290b4f21e19bbfc02b97498289792579fec/relative-server.yaml', + contextUrl: + 'https://gist.githubusercontent.com/hkosova/d223eb45c5198db09d08f2603cc0e10a/raw/ae22e290b4f21e19bbfc02b97498289792579fec/relative-server.yaml', }); expect(res).toEqual('https://gist.githubusercontent.com'); diff --git a/test/oas3/execute/style-explode/cookie.js b/test/oas3/execute/style-explode/cookie.js index c1dbd695a..6ba707630 100644 --- a/test/oas3/execute/style-explode/cookie.js +++ b/test/oas3/execute/style-explode/cookie.js @@ -4,46 +4,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - cookie parameters', () describe('primitive values', () => { const VALUE = 5; - test( - 'default: should build a cookie parameter in form/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'cookie', - }, - ], - }, + test('default: should build a cookie parameter in form/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'cookie', + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - Cookie: 'id=5', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + Cookie: 'id=5', + }, + }); + }); test('should build a cookie parameter in form/no-explode format', () => { // Given @@ -128,46 +125,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - cookie parameters', () describe('array values', () => { const VALUE = [3, 4, 5]; - test( - 'default: should build a cookie parameter in form/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'cookie', - }, - ], - }, + test('default: should build a cookie parameter in form/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'cookie', + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - Cookie: 'id=3,4,5', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + Cookie: 'id=3,4,5', + }, + }); + }); test('should build a cookie parameter in form/no-explode format', () => { // Given @@ -255,46 +249,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - cookie parameters', () firstName: 'Alex', }; - test( - 'default: should build a cookie parameter in form/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'cookie', - }, - ], - }, + test('default: should build a cookie parameter in form/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'cookie', + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - Cookie: 'id=role,admin,firstName,Alex', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + Cookie: 'id=role,admin,firstName,Alex', + }, + }); + }); test('should build a cookie parameter in form/no-explode format', () => { // Given diff --git a/test/oas3/execute/style-explode/header.js b/test/oas3/execute/style-explode/header.js index 9686a4e76..4d7679e8a 100644 --- a/test/oas3/execute/style-explode/header.js +++ b/test/oas3/execute/style-explode/header.js @@ -4,132 +4,123 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - header parameters', () describe('primitive values', () => { const VALUE = 5; - test( - 'default: should build a header parameter in simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - }, - ], - }, + test('default: should build a header parameter in simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': '5', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': '5', + }, + }); + }); - test( - 'should build a header parameter in simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - style: 'simple', - explode: false, - }, - ], - }, + test('should build a header parameter in simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + style: 'simple', + explode: false, + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': '5', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': '5', + }, + }); + }); - test( - 'should build a header parameter in simple/no-explode format with special characters', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - style: 'simple', - explode: false, - }, - ], - }, + test('should build a header parameter in simple/no-explode format with special characters', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + style: 'simple', + explode: false, + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': ' <>"%{}|\\^', - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': ' <>"%{}|\\^', + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': ' <>"%{}|\\^', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': ' <>"%{}|\\^', + }, + }); + }); test('should build a header parameter in simple/explode format', () => { // Given @@ -174,89 +165,83 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - header parameters', () describe('array values', () => { const VALUE = [3, 4, 5]; - test( - 'default: should build a header parameter in simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - }, - ], - }, + test('default: should build a header parameter in simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': '3,4,5', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': '3,4,5', + }, + }); + }); - test( - 'should build a header parameter in simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - style: 'simple', - explode: false, - }, - ], - }, + test('should build a header parameter in simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + style: 'simple', + explode: false, + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': '3,4,5', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': '3,4,5', + }, + }); + }); test('should build a header parameter in simple/explode format', () => { // Given @@ -304,89 +289,83 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - header parameters', () firstName: 'Alex', }; - test( - 'default: should build a header parameter in simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - }, - ], - }, + test('default: should build a header parameter in simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': 'role,admin,firstName,Alex', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': 'role,admin,firstName,Alex', + }, + }); + }); - test( - 'should build a header parameter in simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'X-MyHeader', - in: 'header', - style: 'simple', - explode: false, - }, - ], - }, + test('should build a header parameter in simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'X-MyHeader', + in: 'header', + style: 'simple', + explode: false, + }, + ], }, }, - }; + }, + }; - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'X-MyHeader': VALUE, - }, - }); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'X-MyHeader': VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users', - credentials: 'same-origin', - headers: { - 'X-MyHeader': 'role,admin,firstName,Alex', - }, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/users', + credentials: 'same-origin', + headers: { + 'X-MyHeader': 'role,admin,firstName,Alex', + }, + }); + }); test('should build a header parameter in simple/explode format', () => { // Given diff --git a/test/oas3/execute/style-explode/path.js b/test/oas3/execute/style-explode/path.js index f415c812f..7879b88a1 100644 --- a/test/oas3/execute/style-explode/path.js +++ b/test/oas3/execute/style-explode/path.js @@ -2,85 +2,79 @@ import { buildRequest } from '../../../../src/execute'; describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () => { describe('primitive values', () => { - test( - 'default: should build a path parameter in a simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - }, - ], - }, + test('default: should build a path parameter in a simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: 'wow!', - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: '/path/wow%21', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a path parameter in a simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'simple', - explode: false, - }, - ], - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: 'wow!', + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/wow%21', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a path parameter in a simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'simple', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: 'wow!', - }, - }); + }, + }; - expect(req).toEqual({ - method: 'GET', - url: '/path/wow%21', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: 'wow!', + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/wow%21', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a simple/explode format', () => { // Given @@ -120,46 +114,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); - test( - 'should build a path parameter in a label/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'label', - explode: false, - }, - ], - }, + test('should build a path parameter in a label/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'label', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: 'wow!', - }, - }); + }, + }; - expect(req).toEqual({ - method: 'GET', - url: '/path/.wow%21', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: 'wow!', + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/.wow%21', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a label/explode format', () => { // Given @@ -199,46 +190,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); - test( - 'should build a path parameter in a matrix/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'matrix', - explode: false, - }, - ], - }, + test('should build a path parameter in a matrix/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'matrix', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: 'wow!', - }, - }); + }, + }; - expect(req).toEqual({ - method: 'GET', - url: '/path/;id=wow%21', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: 'wow!', + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/;id=wow%21', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a matrix/explode format', () => { // Given @@ -279,85 +267,79 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); describe('array values', () => { - test( - 'default: should build a path parameter in a simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - }, - ], - }, + test('default: should build a path parameter in a simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: [3, 4, 5], - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: '/path/3,4,5', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a path parameter in a simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'simple', - explode: false, - }, - ], - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: [3, 4, 5], + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/3,4,5', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a path parameter in a simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'simple', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: [3, 4, 5], - }, - }); + }, + }; - expect(req).toEqual({ - method: 'GET', - url: '/path/3,4,5', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: [3, 4, 5], + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/3,4,5', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a simple/explode format', () => { // Given @@ -397,46 +379,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); - test( - 'should build a path parameter in a label/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'label', - explode: false, - }, - ], - }, + test('should build a path parameter in a label/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'label', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: [3, 4, 5], - }, - }); + }, + }; - expect(req).toEqual({ - method: 'GET', - url: '/path/.3.4.5', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: [3, 4, 5], + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/.3.4.5', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a label/explode format', () => { // Given @@ -476,46 +455,43 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); - test( - 'should build a path parameter in a matrix/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'matrix', - explode: false, - }, - ], - }, + test('should build a path parameter in a matrix/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'matrix', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: [3, 4, 5], - }, - }); + }, + }; - expect(req).toEqual({ - method: 'GET', - url: '/path/;id=3,4,5', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: [3, 4, 5], + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/;id=3,4,5', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a matrix/explode format', () => { // Given @@ -556,91 +532,85 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); describe('object values', () => { - test( - 'default: should build a path parameter in a simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - }, - ], - }, + test('default: should build a path parameter in a simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: 'Alex', - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: 'Alex', }, - }); - - expect(req).toEqual({ - method: 'GET', - url: '/path/role,admin,firstName,Alex', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a path parameter in a simple/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'simple', - explode: false, - }, - ], - }, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/role,admin,firstName,Alex', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a path parameter in a simple/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'simple', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: 'Alex', - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: 'Alex', }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/path/role,admin,firstName,Alex', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/path/role,admin,firstName,Alex', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a simple/explode format', () => { // Given @@ -683,49 +653,46 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); - test( - 'should build a path parameter in a label/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'label', - explode: false, - }, - ], - }, + test('should build a path parameter in a label/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'label', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: 'Alex', - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: 'Alex', }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/path/.role.admin.firstName.Alex', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: '/path/.role.admin.firstName.Alex', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a label/explode format', () => { // Given @@ -768,49 +735,46 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - path parameters', () = }); }); - test( - 'should build a path parameter in a matrix/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/path/{id}': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'path', - style: 'matrix', - explode: false, - }, - ], - }, + test('should build a path parameter in a matrix/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/path/{id}': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'path', + style: 'matrix', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: 'Alex', - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: 'Alex', }, - }); - - expect(req).toEqual({ - method: 'GET', - url: '/path/;id=role,admin,firstName,Alex', - credentials: 'same-origin', - headers: {}, - }); - }, - ); + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/path/;id=role,admin,firstName,Alex', + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a path parameter in a matrix/explode format', () => { // Given diff --git a/test/oas3/execute/style-explode/query.js b/test/oas3/execute/style-explode/query.js index 1a6c811b4..dee70d889 100644 --- a/test/oas3/execute/style-explode/query.js +++ b/test/oas3/execute/style-explode/query.js @@ -5,7 +5,7 @@ import { buildRequest } from '../../../../src/execute'; const UNSAFE_INPUT = ' <>"%{}|\\^'; const UNSAFE_INPUT_RESULT = '%20%3C%3E%22%25%7B%7D%7C%5C%5E'; -const RESERVED_INPUT = ':/?#[]@!$&\'()*+,;='; +const RESERVED_INPUT = ":/?#[]@!$&'()*+,;="; // !allowReserved const RESERVED_INPUT_ENCODED_RESULT = '%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D'; // !!allowReserved @@ -18,203 +18,841 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () describe('primitive values', () => { const VALUE = SAFE_INPUT; - test( - 'default: should build a query parameter in form/explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - }, - ], - }, + test('default: should build a query parameter in form/explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${VALUE}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: UNSAFE_INPUT, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${UNSAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + allowReserved: true, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + // these characters taken from RFC1738 Section 2.2 + // https://tools.ietf.org/html/rfc1738#section-2.2, "Unsafe" + id: UNSAFE_INPUT, + }, + }); + + expect(req).toEqual({ + method: 'GET', + // FIXME: ~ should be encoded as well + url: `/users?id=${UNSAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters in parameter name', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id[role]', + in: 'query', + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'id[role]': 'admin', + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/users?id%5Brole%5D=admin', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build an empty query parameter with escaped non-RFC3986 characters in parameter name', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id[role]', + in: 'query', + allowEmptyValue: true, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + 'id[role]': '', + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/users?id%5Brole%5D=', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: true, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${VALUE}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${VALUE}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/no-explode format with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + allowReserved: true, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: RESERVED_INPUT, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${RESERVED_INPUT_UNENCODED_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/no-explode format with percent-encoding if allowReserved is not set', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: RESERVED_INPUT, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${RESERVED_INPUT_ENCODED_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + }); + describe('array values', () => { + const VALUE = [3, 4, 5, SAFE_INPUT]; + + test('default: should build a query parameter in form/explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE.concat([UNSAFE_INPUT]), + }, + }); + + expect(req).toEqual({ + method: 'GET', + // FIXME: ~ should be encoded as well + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}&id=${UNSAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + allowReserved: true, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE.concat([UNSAFE_INPUT]), + }, + }); + + expect(req).toEqual({ + method: 'GET', + // FIXME: ~ should be encoded as well + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}&id=${UNSAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: true, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + }, + ], + }, + }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3,4,5,${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/no-explode format with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + allowReserved: true, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=${VALUE}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter with escaped non-RFC3986 characters', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - }, - ], - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: RESERVED_INPUT.split(''), + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=${RESERVED_INPUT_UNENCODED_RESULT.split('').join(',')}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in form/no-explode format without allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: UNSAFE_INPUT, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=${UNSAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter with escaped non-RFC3986 characters with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - allowReserved: true, - }, - ], - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: RESERVED_INPUT.split(''), + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: '/users?id=%3A,%2F,%3F,%23,%5B,%5D,%40,%21,%24,%26,%27,%28,%29,%2A,%2B,%2C,%3B,%3D', + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in space-delimited/explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'spaceDelimited', + explode: true, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - // these characters taken from RFC1738 Section 2.2 - // https://tools.ietf.org/html/rfc1738#section-2.2, "Unsafe" - id: UNSAFE_INPUT, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in space-delimited/explode format with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'spaceDelimited', + explode: true, + }, + ], + }, }, - }); - - expect(req).toEqual({ - method: 'GET', - // FIXME: ~ should be encoded as well - url: `/users?id=${UNSAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test('should build a query parameter with escaped non-RFC3986 characters in parameter name', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id[role]', - in: 'query', - }, - ], - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in space-delimited/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'spaceDelimited', + explode: false, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'id[role]': 'admin', + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3%204%205%20${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in pipe-delimited/explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'pipeDelimited', + explode: true, + }, + ], + }, }, - }); - - expect(req).toEqual({ - method: 'GET', - url: '/users?id%5Brole%5D=admin', - credentials: 'same-origin', - headers: {}, - }); - }); - - test('should build an empty query parameter with escaped non-RFC3986 characters in parameter name', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id[role]', - in: 'query', - allowEmptyValue: true, - }, - ], - }, + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in pipe-delimited/explode format with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'pipeDelimited', + explode: true, + allowReserved: true, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - 'id[role]': '', + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE.concat([RESERVED_INPUT]), + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}&id=${RESERVED_INPUT_UNENCODED_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter in pipe-delimited/no-explode format', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'pipeDelimited', + explode: false, + }, + ], + }, }, - }); + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: VALUE, + }, + }); - expect(req).toEqual({ - method: 'GET', - url: '/users?id%5Brole%5D=', - credentials: 'same-origin', - headers: {}, - }); + expect(req).toEqual({ + method: 'GET', + url: `/users?id=3|4|5|${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, }); + }); - test('should build a query parameter in form/explode format', () => { + test('should build a query parameter in pipe-delimited/no-explode format with allowReserved', () => { // Given const spec = { openapi: '3.0.0', @@ -226,8 +864,9 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () { name: 'id', in: 'query', - style: 'form', - explode: true, + style: 'pipeDelimited', + explode: false, + allowReserved: true, }, ], }, @@ -240,19 +879,26 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () spec, operationId: 'myOperation', parameters: { - id: VALUE, + id: VALUE.concat([RESERVED_INPUT]), }, }); expect(req).toEqual({ method: 'GET', - url: `/users?id=${VALUE}`, + url: `/users?id=3|4|5|${SAFE_INPUT_RESULT}|${RESERVED_INPUT_UNENCODED_RESULT}`, credentials: 'same-origin', headers: {}, }); }); + }); + describe('object values', () => { + const VALUE = { + role: 'admin', + firstName: 'Alex', + greeting: SAFE_INPUT, + }; - test('should build a query parameter in form/no-explode format', () => { + test('default: should build a query parameter in form/explode format', () => { // Given const spec = { openapi: '3.0.0', @@ -264,8 +910,6 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () { name: 'id', in: 'query', - style: 'form', - explode: false, }, ], }, @@ -284,217 +928,130 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () expect(req).toEqual({ method: 'GET', - url: `/users?id=${VALUE}`, + url: `/users?role=admin&firstName=Alex&greeting=${SAFE_INPUT_RESULT}`, credentials: 'same-origin', headers: {}, }); }); - test( - 'should build a query parameter in form/no-explode format with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'form', - explode: false, - allowReserved: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: RESERVED_INPUT, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=${RESERVED_INPUT_UNENCODED_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in form/no-explode format with percent-encoding if allowReserved is not set', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'form', - explode: false, + test('should handle building a query parameter in form/explode format, with a stringified object provided, if schema type is indicated', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + schema: { + type: 'object', }, - ], - }, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: RESERVED_INPUT, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=${RESERVED_INPUT_ENCODED_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - }); - describe('array values', () => { - const VALUE = [3, 4, 5, SAFE_INPUT]; + }, + }; - test( - 'default: should build a query parameter in form/explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter with escaped non-RFC3986 characters', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - }, - ], - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: JSON.stringify(VALUE), + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?role=admin&firstName=Alex&greeting=${SAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE.concat([UNSAFE_INPUT]), + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: UNSAFE_INPUT, }, - }); - - expect(req).toEqual({ - method: 'GET', - // FIXME: ~ should be encoded as well - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}&id=${UNSAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter with escaped non-RFC3986 characters with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - allowReserved: true, - }, - ], - }, + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?role=admin&firstName=${UNSAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); + + test('should build a query parameter with escaped non-RFC3986 characters with allowReserved', () => { + // Given + + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + allowReserved: true, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE.concat([UNSAFE_INPUT]), + }, + }; + + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: UNSAFE_INPUT, }, - }); - - expect(req).toEqual({ - method: 'GET', - // FIXME: ~ should be encoded as well - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}&id=${UNSAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); + }, + }); + + expect(req).toEqual({ + method: 'GET', + url: `/users?role=admin&firstName=${UNSAFE_INPUT_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); test('should build a query parameter in form/explode format', () => { // Given @@ -528,7 +1085,7 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () expect(req).toEqual({ method: 'GET', - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, + url: `/users?role=admin&firstName=Alex&greeting=${SAFE_INPUT_RESULT}`, credentials: 'same-origin', headers: {}, }); @@ -566,559 +1123,55 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () expect(req).toEqual({ method: 'GET', - url: `/users?id=3,4,5,${SAFE_INPUT_RESULT}`, + url: `/users?id=role,admin,firstName,Alex,greeting,${SAFE_INPUT_RESULT}`, credentials: 'same-origin', headers: {}, }); }); - test( - 'should build a query parameter in form/no-explode format with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'form', - explode: false, - allowReserved: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: RESERVED_INPUT.split(''), - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=${RESERVED_INPUT_UNENCODED_RESULT.split('').join(',')}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in form/no-explode format without allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'form', - explode: false, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: RESERVED_INPUT.split(''), - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: '/users?id=%3A,%2F,%3F,%23,%5B,%5D,%40,%21,%24,%26,%27,%28,%29,%2A,%2B,%2C,%3B,%3D', - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in space-delimited/explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'spaceDelimited', - explode: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in space-delimited/explode format with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'spaceDelimited', - explode: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in space-delimited/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'spaceDelimited', - explode: false, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3%204%205%20${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in pipe-delimited/explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'pipeDelimited', - explode: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in pipe-delimited/explode format with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'pipeDelimited', - explode: true, - allowReserved: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE.concat([RESERVED_INPUT]), - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3&id=4&id=5&id=${SAFE_INPUT_RESULT}&id=${RESERVED_INPUT_UNENCODED_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in pipe-delimited/no-explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'pipeDelimited', - explode: false, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3|4|5|${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in pipe-delimited/no-explode format with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'pipeDelimited', - explode: false, - allowReserved: true, - }, - ], - }, + test('should build a query parameter in form/no-explode format with allowReserved', () => { + // Given + const spec = { + openapi: '3.0.0', + paths: { + '/users': { + get: { + operationId: 'myOperation', + parameters: [ + { + name: 'id', + in: 'query', + style: 'form', + explode: false, + allowReserved: true, + }, + ], }, }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE.concat([RESERVED_INPUT]), - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=3|4|5|${SAFE_INPUT_RESULT}|${RESERVED_INPUT_UNENCODED_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - }); - describe('object values', () => { - const VALUE = { - role: 'admin', - firstName: 'Alex', - greeting: SAFE_INPUT, - }; + }, + }; - test( - 'default: should build a query parameter in form/explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?role=admin&firstName=Alex&greeting=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should handle building a query parameter in form/explode format, with a stringified object provided, if schema type is indicated', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - schema: { - type: 'object', - }, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: JSON.stringify(VALUE), - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?role=admin&firstName=Alex&greeting=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter with escaped non-RFC3986 characters', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: UNSAFE_INPUT, - }, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?role=admin&firstName=${UNSAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter with escaped non-RFC3986 characters with allowReserved', - () => { - // Given - - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - allowReserved: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: UNSAFE_INPUT, - }, + // when + const req = buildRequest({ + spec, + operationId: 'myOperation', + parameters: { + id: { + role: 'admin', + firstName: RESERVED_INPUT, }, - }); + }, + }); - expect(req).toEqual({ - method: 'GET', - url: `/users?role=admin&firstName=${UNSAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); + expect(req).toEqual({ + method: 'GET', + url: `/users?id=role,admin,firstName,${RESERVED_INPUT_UNENCODED_RESULT}`, + credentials: 'same-origin', + headers: {}, + }); + }); - test('should build a query parameter in form/explode format', () => { + test('should build a query parameter in form/no-explode format without allowReserved', () => { // Given const spec = { openapi: '3.0.0', @@ -1131,7 +1184,7 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () name: 'id', in: 'query', style: 'form', - explode: true, + explode: false, }, ], }, @@ -1144,19 +1197,22 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () spec, operationId: 'myOperation', parameters: { - id: VALUE, + id: { + role: 'admin', + firstName: RESERVED_INPUT, + }, }, }); expect(req).toEqual({ method: 'GET', - url: `/users?role=admin&firstName=Alex&greeting=${SAFE_INPUT_RESULT}`, + url: `/users?id=role,admin,firstName,${RESERVED_INPUT_ENCODED_RESULT}`, credentials: 'same-origin', headers: {}, }); }); - test('should build a query parameter in form/no-explode format', () => { + test('should build a query parameter in deepObject/explode format', () => { // Given const spec = { openapi: '3.0.0', @@ -1168,8 +1224,8 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () { name: 'id', in: 'query', - style: 'form', - explode: false, + style: 'deepObject', + explode: true, }, ], }, @@ -1188,140 +1244,10 @@ describe('OAS 3.0 - buildRequest w/ `style` & `explode` - query parameters', () expect(req).toEqual({ method: 'GET', - url: `/users?id=role,admin,firstName,Alex,greeting,${SAFE_INPUT_RESULT}`, + url: `/users?id%5Brole%5D=admin&id%5BfirstName%5D=Alex&id%5Bgreeting%5D=${SAFE_INPUT_RESULT}`, credentials: 'same-origin', headers: {}, }); }); - - test( - 'should build a query parameter in form/no-explode format with allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'form', - explode: false, - allowReserved: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: RESERVED_INPUT, - }, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=role,admin,firstName,${RESERVED_INPUT_UNENCODED_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in form/no-explode format without allowReserved', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'form', - explode: false, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: { - role: 'admin', - firstName: RESERVED_INPUT, - }, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id=role,admin,firstName,${RESERVED_INPUT_ENCODED_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); - - test( - 'should build a query parameter in deepObject/explode format', - () => { - // Given - const spec = { - openapi: '3.0.0', - paths: { - '/users': { - get: { - operationId: 'myOperation', - parameters: [ - { - name: 'id', - in: 'query', - style: 'deepObject', - explode: true, - }, - ], - }, - }, - }, - }; - - // when - const req = buildRequest({ - spec, - operationId: 'myOperation', - parameters: { - id: VALUE, - }, - }); - - expect(req).toEqual({ - method: 'GET', - url: `/users?id%5Brole%5D=admin&id%5BfirstName%5D=Alex&id%5Bgreeting%5D=${SAFE_INPUT_RESULT}`, - credentials: 'same-origin', - headers: {}, - }); - }, - ); }); }); diff --git a/test/oas3/execute/style-serializer.js b/test/oas3/execute/style-serializer.js index 316a798f4..55401fb7c 100644 --- a/test/oas3/execute/style-serializer.js +++ b/test/oas3/execute/style-serializer.js @@ -1,6 +1,4 @@ -import { - encodeDisallowedCharacters, -} from '../../../src/execute/oas3/style-serializer'; +import { encodeDisallowedCharacters } from '../../../src/execute/oas3/style-serializer'; describe('OAS3 style serializer', () => { describe('encodeDisallowedCharacters', () => { @@ -11,7 +9,7 @@ describe('OAS3 style serializer', () => { expect(tested('#')).toEqual('%23'); expect(tested('$')).toEqual('%24'); expect(tested('&')).toEqual('%26'); - expect(tested('\'')).toEqual('%27'); + expect(tested("'")).toEqual('%27'); expect(tested('(')).toEqual('%28'); expect(tested(')')).toEqual('%29'); expect(tested('*')).toEqual('%2A'); @@ -35,7 +33,9 @@ describe('OAS3 style serializer', () => { expect(tested('テスト')).toEqual('%E3%83%86%E3%82%B9%E3%83%88'); expect(tested('𩸽')).toEqual('%F0%A9%B8%BD'); expect(tested('🍣')).toEqual('%F0%9F%8D%A3'); - expect(tested('👩‍👩‍👧‍👧')).toEqual('%F0%9F%91%A9%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A7'); + expect(tested('👩‍👩‍👧‍👧')).toEqual( + '%F0%9F%91%A9%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A7' + ); }); test('should skip encoding if `escape` is not set to true', () => { @@ -45,7 +45,7 @@ describe('OAS3 style serializer', () => { expect(tested('#')).toEqual('#'); expect(tested('$')).toEqual('$'); expect(tested('&')).toEqual('&'); - expect(tested('\'')).toEqual('\''); + expect(tested("'")).toEqual("'"); expect(tested('(')).toEqual('('); expect(tested(')')).toEqual(')'); expect(tested('*')).toEqual('*'); diff --git a/test/oas3/helpers.js b/test/oas3/helpers.js index 7dbbcd26e..5ccb4c222 100644 --- a/test/oas3/helpers.js +++ b/test/oas3/helpers.js @@ -1,7 +1,4 @@ -import { - isOAS3, - isSwagger2, -} from '../../src/helpers'; +import { isOAS3, isSwagger2 } from '../../src/helpers'; describe('helpers - OpenAPI Specification 3.0', () => { describe('isOAS3', () => { diff --git a/test/resolver.js b/test/resolver.js index 8333a7f73..56b724158 100644 --- a/test/resolver.js +++ b/test/resolver.js @@ -30,8 +30,7 @@ describe('resolver', () => { }; // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -60,8 +59,7 @@ describe('resolver', () => { }; // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -77,93 +75,89 @@ describe('resolver', () => { } }); - test( - 'should tolerate $refs with raw values that should be percent-encoded', - () => { - // NOTE: this is for compatibility and can be removed in the next major - // REVIEW for v4 + test('should tolerate $refs with raw values that should be percent-encoded', () => { + // NOTE: this is for compatibility and can be removed in the next major + // REVIEW for v4 - // Given - const spec = { + // Given + const spec = { + one: { + uno: 1, + $ref: '#/value two', + }, + 'value two': { + duos: 2, + }, + }; + + // When + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); + + // Then + function handleResponse(obj) { + expect(obj.errors).toEqual([]); + expect(obj.spec).toEqual({ one: { - uno: 1, - $ref: '#/value two', + duos: 2, }, 'value two': { duos: 2, }, - }; + }); + } + }); - // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + test('should be able to resolve circular $refs when a baseDoc is provided', () => { + // Given + const spec = { + one: { + $ref: '#/two', + }, + two: { + a: { + $ref: '#/three', + }, + }, + three: { + b: { + $ref: '#/two', + }, + }, + }; - // Then - function handleResponse(obj) { - expect(obj.errors).toEqual([]); - expect(obj.spec).toEqual({ - one: { - duos: 2, - }, - 'value two': { - duos: 2, - }, - }); - } - }, - ); + // When + return Swagger.resolve({ + spec, + baseDoc: 'http://example.com/swagger.json', + allowMetaPatches: false, + }).then(handleResponse); - test( - 'should be able to resolve circular $refs when a baseDoc is provided', - () => { - // Given - const spec = { + // Then + function handleResponse(obj) { + expect(obj.errors).toEqual([]); + expect(obj.spec).toEqual({ one: { - $ref: '#/two', - }, - two: { a: { - $ref: '#/three', + b: { + $ref: 'http://example.com/swagger.json#/two', + }, }, }, three: { b: { - $ref: '#/two', + $ref: 'http://example.com/swagger.json#/two', }, }, - }; - - // When - return Swagger.resolve({ spec, baseDoc: 'http://example.com/swagger.json', allowMetaPatches: false }) - .then(handleResponse); - - // Then - function handleResponse(obj) { - expect(obj.errors).toEqual([]); - expect(obj.spec).toEqual({ - one: { - a: { - b: { - $ref: 'http://example.com/swagger.json#/two', - }, - }, - }, - three: { + two: { + a: { b: { $ref: 'http://example.com/swagger.json#/two', }, }, - two: { - a: { - b: { - $ref: 'http://example.com/swagger.json#/two', - }, - }, - }, - }); - } - }, - ); + }, + }); + } + }); test('should resolve this edge case of allOf + items + deep $refs', () => { // Given @@ -197,8 +191,7 @@ describe('resolver', () => { }; // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -212,8 +205,7 @@ describe('resolver', () => { xmock().get(url, (req, res) => res.send({ one: 1 })); // When - return Swagger.resolve({ baseDoc: url, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ baseDoc: url, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -227,15 +219,11 @@ describe('resolver', () => { test('should be able to resolve simple allOf', () => { // Given const spec = { - allOf: [ - { uno: 1 }, - { duos: 2 }, - ], + allOf: [{ uno: 1 }, { duos: 2 }], }; // When - return Swagger.resolve({ spec }) - .then(handleResponse); + return Swagger.resolve({ spec }).then(handleResponse); // Then function handleResponse(obj) { @@ -250,15 +238,11 @@ describe('resolver', () => { test('should be able to resolve simple allOf', () => { // Given const spec = { - allOf: [ - { uno: 1 }, - { duos: 2 }, - ], + allOf: [{ uno: 1 }, { duos: 2 }], }; // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -306,8 +290,7 @@ describe('resolver', () => { }; // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -405,8 +388,7 @@ describe('resolver', () => { }; // When - return Swagger.resolve({ spec, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: false }).then(handleResponse); // Then function handleResponse(obj) { @@ -428,7 +410,6 @@ describe('resolver', () => { message: { type: 'string', example: 'Unauthorized', - }, code: { example: 401, @@ -506,8 +487,7 @@ describe('resolver', () => { }; // When - return Swagger.resolve({ spec, allowMetaPatches: true }) - .then(handleResponse); + return Swagger.resolve({ spec, allowMetaPatches: true }).then(handleResponse); // Then function handleResponse(obj) { @@ -529,7 +509,6 @@ describe('resolver', () => { message: { type: 'string', example: 'Unauthorized', - }, code: { example: 401, @@ -562,11 +541,10 @@ describe('resolver', () => { swagger: '2.0', info: { version: '0.2.1', - title: 'Resolver Issue, undefind of \'0\'', + title: "Resolver Issue, undefind of '0'", description: 'Resolver issue', }, - paths: { - }, + paths: {}, definitions: { First: { allOf: [ @@ -609,11 +587,10 @@ describe('resolver', () => { swagger: '2.0', info: { version: '0.2.1', - title: 'Resolver Issue, undefind of \'0\'', + title: "Resolver Issue, undefind of '0'", description: 'Resolver issue', }, - paths: { - }, + paths: {}, definitions: { First: { properties: { @@ -654,11 +631,10 @@ describe('resolver', () => { swagger: '2.0', info: { version: '0.2.1', - title: 'Resolver Issue, undefind of \'0\'', + title: "Resolver Issue, undefind of '0'", description: 'Resolver issue', }, - paths: { - }, + paths: {}, definitions: { First: { allOf: [ @@ -702,11 +678,10 @@ describe('resolver', () => { swagger: '2.0', info: { version: '0.2.1', - title: 'Resolver Issue, undefind of \'0\'', + title: "Resolver Issue, undefind of '0'", description: 'Resolver issue', }, - paths: { - }, + paths: {}, definitions: { First: { properties: { @@ -743,35 +718,33 @@ describe('resolver', () => { }); }); - test( - 'should not throw errors on resvered-keywords in freely-named-fields', - () => { - // Given - const ReservedKeywordSpec = jsYaml.safeLoad(fs.readFileSync(path.resolve(__dirname, './data/reserved-keywords.yaml'), 'utf8')); + test('should not throw errors on resvered-keywords in freely-named-fields', () => { + // Given + const ReservedKeywordSpec = jsYaml.safeLoad( + fs.readFileSync(path.resolve(__dirname, './data/reserved-keywords.yaml'), 'utf8') + ); - // When - return Swagger.resolve({ spec: ReservedKeywordSpec, allowMetaPatches: false }) - .then(handleResponse); + // When + return Swagger.resolve({ spec: ReservedKeywordSpec, allowMetaPatches: false }).then( + handleResponse + ); - // Then - function handleResponse(obj) { - // Sanity ( to make sure we're testing the right spec ) - expect(obj.spec.definitions).toMatchObject({ $ref: {} }); + // Then + function handleResponse(obj) { + // Sanity ( to make sure we're testing the right spec ) + expect(obj.spec.definitions).toMatchObject({ $ref: {} }); - // The main assertion - expect(obj.errors).toEqual([]); - } - }, - ); + // The main assertion + expect(obj.errors).toEqual([]); + } + }); const DOCUMENT_ORIGINAL = { swagger: '2.0', paths: { '/pet': { post: { - tags: [ - 'pet', - ], + tags: ['pet'], summary: 'Add a new pet to the store', operationId: 'addPet', parameters: [ @@ -808,9 +781,7 @@ describe('resolver', () => { }, Pet: { type: 'object', - required: [ - 'category', - ], + required: ['category'], properties: { category: { $ref: '#/definitions/Category', @@ -823,8 +794,9 @@ describe('resolver', () => { describe('Swagger usage', () => { test.skip('should be able to resolve a Swagger document with $refs', () => { // When - return Swagger.resolve({ spec: DOCUMENT_ORIGINAL, allowMetaPatches: false }) - .then(handleResponse); + return Swagger.resolve({ spec: DOCUMENT_ORIGINAL, allowMetaPatches: false }).then( + handleResponse + ); // Then function handleResponse(obj) { @@ -834,9 +806,7 @@ describe('resolver', () => { paths: { '/pet': { post: { - tags: [ - 'pet', - ], + tags: ['pet'], summary: 'Add a new pet to the store', operationId: 'addPet', __originalOperationId: 'addPet', @@ -848,9 +818,7 @@ describe('resolver', () => { required: true, schema: { type: 'object', - required: [ - 'category', - ], + required: ['category'], properties: { category: { type: 'object', @@ -891,9 +859,7 @@ describe('resolver', () => { }, Pet: { type: 'object', - required: [ - 'category', - ], + required: ['category'], properties: { category: { type: 'object', @@ -914,104 +880,96 @@ describe('resolver', () => { } }); - test( - 'should be able to resolve a Swagger document with $refs when allowMetaPatches is enabled', - () => { - // When - return Swagger.resolve({ spec: DOCUMENT_ORIGINAL, allowMetaPatches: true }) - .then(handleResponse); - - // Then - function handleResponse(obj) { - expect(obj.errors).toEqual([]); - expect(obj.spec).toEqual({ - swagger: '2.0', - $$normalized: true, - paths: { - '/pet': { - post: { - tags: [ - 'pet', - ], - summary: 'Add a new pet to the store', - operationId: 'addPet', - __originalOperationId: 'addPet', - parameters: [ - { - in: 'body', - name: 'body', - description: 'Pet object that needs to be added to the store', - required: true, - schema: { - $$ref: '#/definitions/Pet', - type: 'object', - required: [ - 'category', - ], - properties: { - category: { - $$ref: '#/definitions/Category', - type: 'object', - properties: { - id: { - type: 'integer', - format: 'int64', - }, - name: { - type: 'string', - }, + test('should be able to resolve a Swagger document with $refs when allowMetaPatches is enabled', () => { + // When + return Swagger.resolve({ spec: DOCUMENT_ORIGINAL, allowMetaPatches: true }).then( + handleResponse + ); + + // Then + function handleResponse(obj) { + expect(obj.errors).toEqual([]); + expect(obj.spec).toEqual({ + swagger: '2.0', + $$normalized: true, + paths: { + '/pet': { + post: { + tags: ['pet'], + summary: 'Add a new pet to the store', + operationId: 'addPet', + __originalOperationId: 'addPet', + parameters: [ + { + in: 'body', + name: 'body', + description: 'Pet object that needs to be added to the store', + required: true, + schema: { + $$ref: '#/definitions/Pet', + type: 'object', + required: ['category'], + properties: { + category: { + $$ref: '#/definitions/Category', + type: 'object', + properties: { + id: { + type: 'integer', + format: 'int64', + }, + name: { + type: 'string', }, }, }, }, }, - ], - responses: { - 405: { - description: 'Invalid input', - }, + }, + ], + responses: { + 405: { + description: 'Invalid input', }, }, }, }, - definitions: { - Category: { - type: 'object', - properties: { - id: { - type: 'integer', - format: 'int64', - }, - name: { - type: 'string', - }, + }, + definitions: { + Category: { + type: 'object', + properties: { + id: { + type: 'integer', + format: 'int64', + }, + name: { + type: 'string', }, }, - Pet: { - type: 'object', - required: [ - 'category', - ], - properties: { - category: { - $$ref: '#/definitions/Category', - type: 'object', - properties: { - id: { - type: 'integer', - format: 'int64', - }, - name: { - type: 'string', - }, + }, + Pet: { + type: 'object', + required: ['category'], + properties: { + category: { + $$ref: '#/definitions/Category', + type: 'object', + properties: { + id: { + type: 'integer', + format: 'int64', + }, + name: { + type: 'string', }, }, }, }, }, - }); - } - }, - ); + }, + }); + } + }); }); }); diff --git a/test/resolver/index.js b/test/resolver/index.js index 7e1a35311..721cc231e 100644 --- a/test/resolver/index.js +++ b/test/resolver/index.js @@ -49,21 +49,16 @@ testDocuments.forEach((doc) => { if (currentCase.remoteDocuments) { Object.keys(currentCase.remoteDocuments).forEach((key) => { const docContent = currentCase.remoteDocuments[key]; - nockScope - .get(`/${key}`) - .reply(200, docContent, { - 'Content-Type': 'application/yaml', - }); + nockScope.get(`/${key}`).reply(200, docContent, { + 'Content-Type': 'application/yaml', + }); }); } }); afterAll(nock.restore); - assertCaseExpectations( - currentCase, - async () => getValueForAction(currentCase.action), - ); + assertCaseExpectations(currentCase, async () => getValueForAction(currentCase.action)); }); }); } diff --git a/test/specmap/all-of.js b/test/specmap/all-of.js index c3889dd79..7ffb66832 100644 --- a/test/specmap/all-of.js +++ b/test/specmap/all-of.js @@ -1,4 +1,5 @@ import xmock from 'xmock'; + import mapSpec, { plugins } from '../../src/specmap'; describe('allOf', () => { @@ -9,10 +10,7 @@ describe('allOf', () => { test('should resolve simple allOf', () => { return mapSpec({ spec: { - allOf: [ - { one: 1 }, - { two: 2 }, - ], + allOf: [{ one: 1 }, { two: 2 }], }, plugins: [plugins.allOf], }).then((res) => { @@ -26,29 +24,23 @@ describe('allOf', () => { }); }); - test( - 'should return empty object when you pass nothing to allOf', - (done) => { - return mapSpec({ - spec: { allOf: [] }, - plugins: [plugins.allOf], - }).then((res) => { - expect(res).toEqual({ - errors: [], - spec: {}, - }); - done(); + test('should return empty object when you pass nothing to allOf', (done) => { + return mapSpec({ + spec: { allOf: [] }, + plugins: [plugins.allOf], + }).then((res) => { + expect(res).toEqual({ + errors: [], + spec: {}, }); - }, - ); + done(); + }); + }); test('should resolve local $refs in allOf', () => { return mapSpec({ spec: { - allOf: [ - { one: { $ref: '#/bar' } }, - { two: 2 }, - ], + allOf: [{ one: { $ref: '#/bar' } }, { two: 2 }], bar: { baz: 4 }, }, plugins: [plugins.refs, plugins.allOf], @@ -192,54 +184,48 @@ describe('allOf', () => { }); }); - test( - 'should ignore "allOf" in freely named Swagger key positions', - () => { - const spec = { - parameters: { - allOf: { - a: 123, - }, + test('should ignore "allOf" in freely named Swagger key positions', () => { + const spec = { + parameters: { + allOf: { + a: 123, }, - responses: { - allOf: { - a: 123, - }, + }, + responses: { + allOf: { + a: 123, }, - definitions: { - allOf: { - a: 123, - }, + }, + definitions: { + allOf: { + a: 123, }, - securityDefinitions: { - allOf: { - a: 123, - }, + }, + securityDefinitions: { + allOf: { + a: 123, }, - properties: { - allOf: { - a: 123, - }, + }, + properties: { + allOf: { + a: 123, }, - }; + }, + }; - return mapSpec({ - spec, - plugins: [plugins.allOf], - }).then((res) => { - expect(res.errors).toEqual([]); - expect(res.spec).toEqual(spec); - }); - }, - ); + return mapSpec({ + spec, + plugins: [plugins.allOf], + }).then((res) => { + expect(res.errors).toEqual([]); + expect(res.spec).toEqual(spec); + }); + }); test('should throw error if allOf has a non-object item', () => { return mapSpec({ spec: { - allOf: [ - { one: 1 }, - 2, - ], + allOf: [{ one: 1 }, 2], }, plugins: [plugins.allOf], }).then((res) => { @@ -253,8 +239,8 @@ describe('allOf', () => { return mapSpec({ spec: { allOf: [ - { one: { two: { half: true }}}, // eslint-disable-line object-curly-spacing - { one: { two: { otherHalf: true }}}, // eslint-disable-line object-curly-spacing + { one: { two: { half: true } } }, // eslint-disable-line object-curly-spacing + { one: { two: { otherHalf: true } } }, // eslint-disable-line object-curly-spacing ], }, plugins: [plugins.allOf], @@ -278,19 +264,14 @@ describe('allOf', () => { spec: { allOf: [ { - allOf: [ - { two: 2 }, - ], + allOf: [{ two: 2 }], }, { one: 1 }, { allOf: [ { three: 3 }, { - allOf: [ - { four: 4 }, - { five: 5 }, - ], + allOf: [{ four: 4 }, { five: 5 }], }, ], }, @@ -319,10 +300,7 @@ describe('allOf', () => { return mapSpec({ plugins: [plugins.refs, plugins.allOf], spec: { - allOf: [ - { $ref: 'http://example.com/' }, - { fromLocal: true }, - ], + allOf: [{ $ref: 'http://example.com/' }, { fromLocal: true }], }, }).then((res) => { expect(res.errors).toEqual([]); @@ -350,14 +328,16 @@ describe('allOf', () => { }, }, Bravo: { - allOf: [{ - type: 'object', - properties: { - three: { - type: 'string', + allOf: [ + { + type: 'object', + properties: { + three: { + type: 'string', + }, }, }, - }], + ], }, }, }, @@ -439,46 +419,43 @@ describe('allOf', () => { }); }); - test( - 'should handle case, with an `allOf` referencing an `allOf` ', - () => { - return mapSpec({ - plugins: [plugins.refs, plugins.allOf], - showDebug: true, - spec: { - definitions: { - one: { - allOf: [ - { - $ref: '#/definitions/two', - }, - { - type: 'object', - }, - ], - }, - two: { - allOf: [ - { - type: 'object', - }, - ], - }, + test('should handle case, with an `allOf` referencing an `allOf` ', () => { + return mapSpec({ + plugins: [plugins.refs, plugins.allOf], + showDebug: true, + spec: { + definitions: { + one: { + allOf: [ + { + $ref: '#/definitions/two', + }, + { + type: 'object', + }, + ], + }, + two: { + allOf: [ + { + type: 'object', + }, + ], }, }, - }).then((res) => { - expect(res.errors).toEqual([]); - expect(res.spec).toEqual({ - definitions: { - one: { - type: 'object', - }, - two: { - type: 'object', - }, + }, + }).then((res) => { + expect(res.errors).toEqual([]); + expect(res.spec).toEqual({ + definitions: { + one: { + type: 'object', }, - }); + two: { + type: 'object', + }, + }, }); - }, - ); + }); + }); }); diff --git a/test/specmap/complex.js b/test/specmap/complex.js index 7534d406f..276d7ff81 100644 --- a/test/specmap/complex.js +++ b/test/specmap/complex.js @@ -1,6 +1,7 @@ import path from 'path'; import glob from 'glob'; import xmock from 'xmock'; + import mapSpec, { plugins } from '../../src/specmap'; const { refs } = plugins; diff --git a/test/specmap/context-tree.js b/test/specmap/context-tree.js index d5cacfbb9..64ab0e3bb 100644 --- a/test/specmap/context-tree.js +++ b/test/specmap/context-tree.js @@ -43,14 +43,11 @@ describe('ContextTree', () => { expect(tree.get(['one', 'three', 'four']).baseDoc).toEqual('rooty'); }); - test( - 'should allow setting the root from contructor and get without arg, returns root', - () => { - const tree = new ContextTree({ two: 2 }); - const res = tree.get(); - expect(res).toEqual({ two: 2 }); - }, - ); + test('should allow setting the root from contructor and get without arg, returns root', () => { + const tree = new ContextTree({ two: 2 }); + const res = tree.get(); + expect(res).toEqual({ two: 2 }); + }); test('should get the nearest path', () => { const tree = new ContextTree(); diff --git a/test/specmap/index.js b/test/specmap/index.js index ddfce9c57..93c641eab 100644 --- a/test/specmap/index.js +++ b/test/specmap/index.js @@ -1,6 +1,7 @@ import cloneDeep from 'lodash/cloneDeep'; import xmock from 'xmock'; import traverse from 'traverse'; + import mapSpec, { SpecMap, plugins } from '../../src/specmap'; import lib from '../../src/specmap/lib'; @@ -27,37 +28,40 @@ describe('specmap', () => { test('should call plugins with patches', (done) => { mapSpec({ spec: { one: 1 }, - plugins: [{ - specMap: (patches) => { - try { - expect(patches).toEqual([{ - op: 'add', - path: [], - value: { one: 1 }, - }]); - done(); - } catch (e) { - done(e); - } + plugins: [ + { + specMap: (patches) => { + try { + expect(patches).toEqual([ + { + op: 'add', + path: [], + value: { one: 1 }, + }, + ]); + done(); + } catch (e) { + done(e); + } + }, }, - }], + ], }); }); - test( - 'should include a library of functions, including `add` ', - (done) => { - mapSpec({ - spec: { bob: true }, - plugins: [{ + test('should include a library of functions, including `add` ', (done) => { + mapSpec({ + spec: { bob: true }, + plugins: [ + { specMap(patches, specmap) { expect(typeof specmap.add).toBe('function'); done(); }, - }], - }); - }, - ); + }, + ], + }); + }); test('should accept simple functions for plugins', (done) => { mapSpec({ @@ -65,11 +69,13 @@ describe('specmap', () => { plugins: [ (patches) => { try { - expect(patches).toEqual([{ - op: 'add', - path: [], - value: { one: 1 }, - }]); + expect(patches).toEqual([ + { + op: 'add', + path: [], + value: { one: 1 }, + }, + ]); } catch (e) { done(e); } @@ -98,81 +104,83 @@ describe('specmap', () => { }); }); - test( - 'should block until promises resolve before running next plugin', - () => { - const p1 = (patches, specmap) => { - if (specmap.hasRun()) { - return undefined; - } - return specmap.replace(['val'], new Promise((resolve) => { + test('should block until promises resolve before running next plugin', () => { + const p1 = (patches, specmap) => { + if (specmap.hasRun()) { + return undefined; + } + return specmap.replace( + ['val'], + new Promise((resolve) => { setTimeout(() => { resolve('some val'); }, 50); - })); - }; - - const p2 = (patches, specmap) => { - if (specmap.hasRun()) { - return undefined; - } - if (patches[1].value !== 'some val' - && patches[2].value !== 'some val' - && patches[3].value !== 'some val') { - return [new Error('Promises not yet resolved')]; - } + }) + ); + }; + const p2 = (patches, specmap) => { + if (specmap.hasRun()) { return undefined; - }; + } + if ( + patches[1].value !== 'some val' && + patches[2].value !== 'some val' && + patches[3].value !== 'some val' + ) { + return [new Error('Promises not yet resolved')]; + } - return mapSpec({ - spec: {}, - plugins: [p1, p1, p1, p2], - }).then((result) => { - expect(result).toEqual({ - errors: [], - spec: { val: 'some val' }, - }); + return undefined; + }; + + return mapSpec({ + spec: {}, + plugins: [p1, p1, p1, p2], + }).then((result) => { + expect(result).toEqual({ + errors: [], + spec: { val: 'some val' }, }); - }, - ); - - test( - 'should not block the first plugin if it is executed multiple times at once', - () => { - let hasRunTwice = false; - const p1 = (patches, specmap) => { - if (!specmap.hasRun()) { - return [ - specmap.add(['val1'], 'some val1'), - specmap.add(['val2'], new Promise((resolve) => { + }); + }); + + test('should not block the first plugin if it is executed multiple times at once', () => { + let hasRunTwice = false; + const p1 = (patches, specmap) => { + if (!specmap.hasRun()) { + return [ + specmap.add(['val1'], 'some val1'), + specmap.add( + ['val2'], + new Promise((resolve) => { setTimeout(() => resolve('some val2'), 50); - })), - ]; - } - if (!hasRunTwice) { - hasRunTwice = true; - // We expect this to run immediately with the val1 patch, - // but without the val2 patch because the promise hasn't been resolved. - if (patches[0].value !== 'some val1' || patches[1] != null) { - return [new Error('Should not block')]; - } + }) + ), + ]; + } + if (!hasRunTwice) { + hasRunTwice = true; + // We expect this to run immediately with the val1 patch, + // but without the val2 patch because the promise hasn't been resolved. + if (patches[0].value !== 'some val1' || patches[1] != null) { + return [new Error('Should not block')]; } + } - return undefined; - }; + return undefined; + }; - return mapSpec({ - spec: {}, - plugins: [p1], - }).then((result) => { - expect(result).toEqual({ - errors: [], - spec: { val1: 'some val1', val2: 'some val2' }, - }); + return mapSpec({ + spec: {}, + plugins: [p1], + }).then((result) => { + expect(result).toEqual({ + errors: [], + spec: { val1: 'some val1', val2: 'some val2' }, }); - }, - ); + }); + }); test('records errors after each plugin', () => { return mapSpec({ @@ -193,10 +201,7 @@ describe('specmap', () => { ], }).then((result) => { expect(result).toEqual({ - errors: [ - new Error('This is not working'), - new TypeError('wrong type'), - ], + errors: [new Error('This is not working'), new TypeError('wrong type')], spec: { here: true }, }); }); @@ -212,10 +217,7 @@ describe('specmap', () => { return undefined; } hasRun = true; - return [ - new Error('This is not working'), - specmap.replace(['two'], 2), - ]; + return [new Error('This is not working'), specmap.replace(['two'], 2)]; }, ], }).then((result) => { @@ -282,10 +284,7 @@ describe('specmap', () => { }, }, }, - plugins: [ - addFour, - increment, - ], + plugins: [addFour, increment], }).then((res) => { expect(res).toEqual({ errors: [], @@ -366,7 +365,9 @@ describe('specmap', () => { return mapSpec({ spec: { one: 1 }, plugins: [ - () => { /* do nothing */ }, + () => { + /* do nothing */ + }, (patches, specmap) => { if (specmap.get(['two']) !== 2) { return specmap.add(['two'], 2); @@ -430,16 +431,15 @@ describe('specmap', () => { another: { $ref: '#/nested' }, }, plugins: [plugins.refs], - }) - .then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - nested: { one: 1 }, - another: { one: 1 }, - }, - }); + }).then((res) => { + expect(res).toEqual({ + errors: [], + spec: { + nested: { one: 1 }, + another: { one: 1 }, + }, }); + }); }); test('should resolve internal $refs in arrays', () => { @@ -449,61 +449,52 @@ describe('specmap', () => { another: [{ $ref: '#/nested' }], }, plugins: [plugins.refs], - }) - .then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - nested: { one: 1 }, - another: [{ one: 1 }], - }, - }); + }).then((res) => { + expect(res).toEqual({ + errors: [], + spec: { + nested: { one: 1 }, + another: [{ one: 1 }], + }, }); + }); }); - test( - 'should resolve internal $refs that points to object inside an array', - () => { - return mapSpec({ + test('should resolve internal $refs that points to object inside an array', () => { + return mapSpec({ + spec: { + nested: [{ one: 1 }], + another: { $ref: '#/nested' }, + }, + plugins: [plugins.refs], + }).then((res) => { + expect(res).toEqual({ + errors: [], spec: { nested: [{ one: 1 }], - another: { $ref: '#/nested' }, + another: [{ one: 1 }], }, - plugins: [plugins.refs], - }) - .then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - nested: [{ one: 1 }], - another: [{ one: 1 }], - }, - }); - }); - }, - ); + }); + }); + }); - test( - 'should resolve internal $refs that points to item inside an array', - () => { - return mapSpec({ + test('should resolve internal $refs that points to item inside an array', () => { + return mapSpec({ + spec: { + nested: [{ one: 1 }], + another: { $ref: '#/nested/0/one' }, + }, + plugins: [plugins.refs], + }).then((res) => { + expect(res).toEqual({ + errors: [], spec: { nested: [{ one: 1 }], - another: { $ref: '#/nested/0/one' }, + another: 1, }, - plugins: [plugins.refs], - }) - .then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - nested: [{ one: 1 }], - another: 1, - }, - }); - }); - }, - ); + }); + }); + }); test('should resolve a $ref without a pointer', () => { plugins.refs.docCache['http://some-path'] = { @@ -515,15 +506,14 @@ describe('specmap', () => { $ref: 'http://some-path', }, plugins: [plugins.refs], - }) - .then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - one: 1, - }, - }); + }).then((res) => { + expect(res).toEqual({ + errors: [], + spec: { + one: 1, + }, }); + }); }); test('should fail if we cannot resolve a ref', () => { @@ -534,16 +524,15 @@ describe('specmap', () => { }, context: { baseDoc: 'some-path' }, plugins: [plugins.refs], - }) - .then((res) => { - expect(res.spec).toEqual({ - nested: { one: 1 }, - another: { $ref: '#/not/here' }, - }); - expect(res.errors[0].$ref).toEqual('#/not/here'); - expect(res.errors[0].pointer).toEqual('/not/here'); - expect(res.errors[0].baseDoc).toEqual('some-path'); + }).then((res) => { + expect(res.spec).toEqual({ + nested: { one: 1 }, + another: { $ref: '#/not/here' }, }); + expect(res.errors[0].$ref).toEqual('#/not/here'); + expect(res.errors[0].pointer).toEqual('/not/here'); + expect(res.errors[0].baseDoc).toEqual('some-path'); + }); }); test('should resolve petstore-simple', () => { @@ -575,11 +564,10 @@ describe('specmap', () => { }, allowMetaPatches: true, plugins: [plugins.refs], - }) - .then((res) => { - expect(res.spec.one.$$ref).toEqual('#/two'); - expect(res.spec.two.$$ref).toEqual(undefined); - }); + }).then((res) => { + expect(res.spec.one.$$ref).toEqual('#/two'); + expect(res.spec.two.$$ref).toEqual(undefined); + }); }); describe('allowMetaPatches = true', () => { @@ -595,9 +583,11 @@ describe('specmap', () => { spec: { a: 1, $ref: 'http://example.com/common.json#/works' }, plugins: [plugins.refs], allowMetaPatches: true, - }).then((res) => { - expect(res.spec.$$ref).toEqual('http://example.com/common.json#/works'); - }).then(() => xapp.restore()); + }) + .then((res) => { + expect(res.spec.$$ref).toEqual('http://example.com/common.json#/works'); + }) + .then(() => xapp.restore()); }); test('should rewrite $$ref artifacts inside external $refs', () => { @@ -617,10 +607,12 @@ describe('specmap', () => { spec: { a: 1, $ref: 'http://example.com/common.json#/works' }, plugins: [plugins.refs], allowMetaPatches: true, - }).then((res) => { - expect(res.spec.$$ref).toEqual('http://example.com/common.json#/works'); - expect(res.spec.one.$$ref).toEqual('http://example.com/common.json#/works/two'); - }).then(() => xapp.restore()); + }) + .then((res) => { + expect(res.spec.$$ref).toEqual('http://example.com/common.json#/works'); + expect(res.spec.one.$$ref).toEqual('http://example.com/common.json#/works/two'); + }) + .then(() => xapp.restore()); }); }); @@ -635,10 +627,12 @@ describe('specmap', () => { return mapSpec({ spec: { $ref: 'http://example.com/common.json#/works' }, plugins: [plugins.refs], - }).then((res) => { - expect(res.errors).toEqual([]); - expect(res.spec).toEqual({ yay: true }); - }).then(() => xapp.restore()); + }) + .then((res) => { + expect(res.errors).toEqual([]); + expect(res.spec).toEqual({ yay: true }); + }) + .then(() => xapp.restore()); }); test('should store the absolute path, in context', () => { @@ -664,12 +658,14 @@ describe('specmap', () => { $ref: '../common.json#/almost', }, plugins: [plugins.refs], - }).then((res) => { - expect(res.errors).toEqual([]); - expect(res.spec).toEqual({ - whoop: true, - }); - }).then(() => xapp.restore()); + }) + .then((res) => { + expect(res.errors).toEqual([]); + expect(res.spec).toEqual({ + whoop: true, + }); + }) + .then(() => xapp.restore()); }); test('should use absPath for the context, not refPath', () => { @@ -698,15 +694,17 @@ describe('specmap', () => { $ref: 'models.json#/Parent', }, plugins: [plugins.refs], - }).then((res) => { - expect(res.errors).toEqual([]); - expect(res.spec).toEqual({ - parent: true, - child: { - child: true, - }, - }); - }).then(() => xapp.restore()); + }) + .then((res) => { + expect(res.errors).toEqual([]); + expect(res.spec).toEqual({ + parent: true, + child: { + child: true, + }, + }); + }) + .then(() => xapp.restore()); }); test('should resolve a complex spec', () => { @@ -720,12 +718,14 @@ describe('specmap', () => { return mapSpec({ spec, plugins: [plugins.refs], - }).then((res) => { - expect(res).toEqual({ - errors: [], - spec: resolved, - }); - }).then(() => xapp.restore()); + }) + .then((res) => { + expect(res).toEqual({ + errors: [], + spec: resolved, + }); + }) + .then(() => xapp.restore()); }); }); }); @@ -793,23 +793,20 @@ describe('specmap', () => { }); describe('context', () => { - test( - 'should allow access to root context (options supplied to SpecMap)', - (done) => { - return mapSpec({ - spec: { - top: { middle: { leaf: 'hi' } }, + test('should allow access to root context (options supplied to SpecMap)', (done) => { + return mapSpec({ + spec: { + top: { middle: { leaf: 'hi' } }, + }, + context: { name: 'root' }, + plugins: [ + (patches, inst) => { + expect(inst.getContext(['top', 'middle']).name).toEqual('root'); + done(); }, - context: { name: 'root' }, - plugins: [ - (patches, inst) => { - expect(inst.getContext(['top', 'middle']).name).toEqual('root'); - done(); - }, - ], - }); - }, - ); + ], + }); + }); test('should set / get context for a given path', (done) => { return mapSpec({ diff --git a/test/specmap/lib.js b/test/specmap/lib.js index b02dba277..8746860e1 100644 --- a/test/specmap/lib.js +++ b/test/specmap/lib.js @@ -86,24 +86,15 @@ describe('lib', () => { describe('parentPathMatch', () => { test('should match an exact path', () => { - expect(lib.parentPathMatch( - ['one', 'two'], - ['one', 'two'], - )).toEqual(true); + expect(lib.parentPathMatch(['one', 'two'], ['one', 'two'])).toEqual(true); }); test('should NOT match a child path', () => { - expect(lib.parentPathMatch( - ['one', 'two'], - ['one', 'two', 'three'], - )).toEqual(false); + expect(lib.parentPathMatch(['one', 'two'], ['one', 'two', 'three'])).toEqual(false); }); test('should match a parent path', () => { - expect(lib.parentPathMatch( - ['one', 'two'], - ['one'], - )).toEqual(true); + expect(lib.parentPathMatch(['one', 'two'], ['one'])).toEqual(true); }); }); }); diff --git a/test/specmap/parameters.js b/test/specmap/parameters.js index 74199779d..15a39f2f4 100644 --- a/test/specmap/parameters.js +++ b/test/specmap/parameters.js @@ -1,4 +1,5 @@ import xmock from 'xmock'; + import mapSpec, { plugins } from '../../src/specmap'; describe('parameters', () => { @@ -11,10 +12,7 @@ describe('parameters', () => { return mapSpec({ spec: { - parameters: [ - { one: 1 }, - { two: 2 }, - ], + parameters: [{ one: 1 }, { two: 2 }], }, plugins: [plugins.parameters], parameterMacro, @@ -37,77 +35,65 @@ describe('parameters', () => { }); }); - test( - 'should add default value to parameter taking to account first parameter (operation) passed in parameterMacro', - () => { - const parameterMacro = (operation) => operation.test; + test('should add default value to parameter taking to account first parameter (operation) passed in parameterMacro', () => { + const parameterMacro = (operation) => operation.test; - return mapSpec({ + return mapSpec({ + spec: { + test: { + test: 'pet', + parameters: [{ one: 1 }, { two: 2 }], + }, + }, + plugins: [plugins.parameters], + parameterMacro, + }).then((res) => { + expect(res).toEqual({ + errors: [], spec: { test: { test: 'pet', parameters: [ - { one: 1 }, - { two: 2 }, + { + one: 1, + default: 'pet', + }, + { + two: 2, + default: 'pet', + }, ], }, }, - plugins: [plugins.parameters], - parameterMacro, - }).then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - test: { - test: 'pet', - parameters: [ - { - one: 1, - default: 'pet', - }, - { - two: 2, - default: 'pet', - }, - ], - }, - }, - }); }); - }, - ); + }); + }); - test( - 'should add default value to parameter taking to account second parameter (parameter itself) passed in parameterMacro', - () => { - const parameterMacro = (operation, parameter) => parameter.test; + test('should add default value to parameter taking to account second parameter (parameter itself) passed in parameterMacro', () => { + const parameterMacro = (operation, parameter) => parameter.test; - return mapSpec({ + return mapSpec({ + spec: { + parameters: [{ test: 1 }, { test: 2 }], + }, + plugins: [plugins.parameters], + parameterMacro, + }).then((res) => { + expect(res).toEqual({ + errors: [], spec: { parameters: [ - { test: 1 }, - { test: 2 }, + { + test: 1, + default: 1, + }, + { + test: 2, + default: 2, + }, ], }, - plugins: [plugins.parameters], - parameterMacro, - }).then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - parameters: [ - { - test: 1, - default: 1, - }, - { - test: 2, - default: 2, - }, - ], - }, - }); }); - }, - ); + }); + }); }); diff --git a/test/specmap/properties.js b/test/specmap/properties.js index c05f56a59..8e0d00285 100644 --- a/test/specmap/properties.js +++ b/test/specmap/properties.js @@ -1,4 +1,5 @@ import xmock from 'xmock'; + import mapSpec, { plugins } from '../../src/specmap'; describe('properties', () => { @@ -35,41 +36,38 @@ describe('properties', () => { }); }); - test( - 'should add default value to each property taking to account first parameter (property) passed in modelPropertyMacro', - () => { - const modelPropertyMacro = (prop) => prop.test; + test('should add default value to each property taking to account first parameter (property) passed in modelPropertyMacro', () => { + const modelPropertyMacro = (prop) => prop.test; - return mapSpec({ + return mapSpec({ + spec: { + properties: { + one: { + test: 1, + }, + two: { + test: 2, + }, + }, + }, + plugins: [plugins.properties], + modelPropertyMacro, + }).then((res) => { + expect(res).toEqual({ + errors: [], spec: { properties: { one: { + default: 1, test: 1, }, two: { + default: 2, test: 2, }, }, }, - plugins: [plugins.properties], - modelPropertyMacro, - }).then((res) => { - expect(res).toEqual({ - errors: [], - spec: { - properties: { - one: { - default: 1, - test: 1, - }, - two: { - default: 2, - test: 2, - }, - }, - }, - }); }); - }, - ); + }); + }); }); diff --git a/test/specmap/refs.js b/test/specmap/refs.js index 9c73440d0..c0ba6a15e 100644 --- a/test/specmap/refs.js +++ b/test/specmap/refs.js @@ -2,6 +2,7 @@ import path from 'path'; import cloneDeep from 'lodash/cloneDeep'; import glob from 'glob'; import xmock from 'xmock'; + import mapSpec, { plugins } from '../../src/specmap'; const { refs } = plugins; @@ -54,13 +55,10 @@ describe('refs', () => { }); describe('relative paths', () => { - test( - 'should think of the basePath as pointing to a document, so use the parent folder for resolution', - () => { - const res = refs.absoluteify('one.json', 'http://example.com/two.json'); - expect(res).toEqual('http://example.com/one.json'); - }, - ); + test('should think of the basePath as pointing to a document, so use the parent folder for resolution', () => { + const res = refs.absoluteify('one.json', 'http://example.com/two.json'); + expect(res).toEqual('http://example.com/one.json'); + }); test('should handle ../', () => { const res = refs.absoluteify('../one.json', 'http://example.com/two/three/four.json'); @@ -112,22 +110,25 @@ describe('refs', () => { xapp.get(url, (req, res) => { res.send({ works: { yay: true } }); }); - return refs.getDoc(url).then((doc) => { - expect(doc).toEqual({ works: { yay: true } }); - }).then(() => { - expect(refs.docCache).toEqual({ - [url]: { works: { yay: true } }, - }); - // Change cache to verify we're using it - refs.docCache[url].works.yay = false; - return refs.getDoc(url).then((doc) => { - expect(doc).toEqual({ works: { yay: false } }); + return refs + .getDoc(url) + .then((doc) => { + expect(doc).toEqual({ works: { yay: true } }); + }) + .then(() => { + expect(refs.docCache).toEqual({ + [url]: { works: { yay: true } }, + }); + // Change cache to verify we're using it + refs.docCache[url].works.yay = false; + return refs.getDoc(url).then((doc) => { + expect(doc).toEqual({ works: { yay: false } }); + }); }); - }); }); test('should cache pending HTTP requests', () => { const url = 'http://example.com/common.json'; - xapp.get(url, () => { }); + xapp.get(url, () => {}); const p1 = refs.getDoc(url); const p2 = refs.getDoc(url); const p3 = refs.docCache[url]; @@ -141,10 +142,9 @@ describe('refs', () => { refs.docCache['some-path'] = { one: '1', }; - return refs.extractFromDoc('some-path', '/one') - .then((val) => { - expect(val).toEqual('1'); - }); + return refs.extractFromDoc('some-path', '/one').then((val) => { + expect(val).toEqual('1'); + }); }); test('should fail nicely', () => { @@ -152,7 +152,8 @@ describe('refs', () => { one: '1', }; - return refs.extractFromDoc('some-path', '/two', '#/two') + return refs + .extractFromDoc('some-path', '/two', '#/two') .then(() => { throw new Error('Should have failed'); }) @@ -169,14 +170,11 @@ describe('refs', () => { expect(res).toEqual('/one/'); }); - test( - 'should throw if there is no basePath, and we try to resolve a realtive url', - () => { - expect(() => { - refs.absoluteify('../'); - }).toThrow(); - }, - ); + test('should throw if there is no basePath, and we try to resolve a realtive url', () => { + expect(() => { + refs.absoluteify('../'); + }).toThrow(); + }); test('should return the absolute URL, with a different asset', () => { const res = refs.absoluteify('not-three.json', '/one/two/three.json'); @@ -192,15 +190,18 @@ describe('refs', () => { res.send({ works: { yay: true } }); }); - return refs.getDoc(url).then((doc) => { - expect(doc).toEqual({ works: { yay: true } }); - }).then(() => { - expect(refs.docCache).toEqual({ - [url]: { works: { yay: true } }, + return refs + .getDoc(url) + .then((doc) => { + expect(doc).toEqual({ works: { yay: true } }); + }) + .then(() => { + expect(refs.docCache).toEqual({ + [url]: { works: { yay: true } }, + }); + refs.clearCache(); + expect(refs.docCache).toEqual({}); }); - refs.clearCache(); - expect(refs.docCache).toEqual({}); - }); }); test('should clear the docCache, of particular items', () => { @@ -215,30 +216,36 @@ describe('refs', () => { res.send({ works: { yup: true } }); }); - return refs.getDoc(url).then((doc) => { - expect(doc).toEqual({ works: { yay: true } }); - }).then(() => { - expect(refs.docCache).toEqual({ - [url]: { works: { yay: true } }, - }); - - return refs.getDoc(url2).then((doc) => { - expect(doc).toEqual({ works: { yup: true } }); - }).then(() => { + return refs + .getDoc(url) + .then((doc) => { + expect(doc).toEqual({ works: { yay: true } }); + }) + .then(() => { expect(refs.docCache).toEqual({ [url]: { works: { yay: true } }, - [url2]: { works: { yup: true } }, }); - refs.clearCache(url); + return refs + .getDoc(url2) + .then((doc) => { + expect(doc).toEqual({ works: { yup: true } }); + }) + .then(() => { + expect(refs.docCache).toEqual({ + [url]: { works: { yay: true } }, + [url2]: { works: { yup: true } }, + }); - expect(refs.docCache).toEqual({ - [url2]: { - works: { yup: true }, - }, - }); + refs.clearCache(url); + + expect(refs.docCache).toEqual({ + [url2]: { + works: { yup: true }, + }, + }); + }); }); - }); }); }); @@ -248,13 +255,10 @@ describe('refs', () => { expect(subject).toEqual(['one', 'two', '/three']); }); - test( - 'should parse if JSON-Pointer does not start with forward dash', - () => { - const subject = refs.jsonPointerToArray('one/two/~1three'); - expect(subject).toEqual(['one', 'two', '/three']); - }, - ); + test('should parse if JSON-Pointer does not start with forward dash', () => { + const subject = refs.jsonPointerToArray('one/two/~1three'); + expect(subject).toEqual(['one', 'two', '/three']); + }); test('should return [""] for "" and "/"', () => { let subject = refs.jsonPointerToArray(''); @@ -285,7 +289,7 @@ describe('refs', () => { const group2 = f2.replace(/\//g, path.sep).substring(dir.length).split(path.sep)[1]; const no1 = Number(path.basename(f1).split('.')[0]); const no2 = Number(path.basename(f2).split('.')[0]); - return group1.localeCompare(group2) || (no1 - no2); + return group1.localeCompare(group2) || no1 - no2; }) .map((filename) => { return { name: filename, filename, ...require(filename) }; diff --git a/test/subtree-resolver.js b/test/subtree-resolver.js index 8dde9fcc4..0737337b4 100644 --- a/test/subtree-resolver.js +++ b/test/subtree-resolver.js @@ -1,4 +1,5 @@ import xmock from 'xmock'; + import resolve from '../src/subtree-resolver'; describe('subtree $ref resolver', () => { @@ -16,42 +17,66 @@ describe('subtree $ref resolver', () => { // refs.clearCache() }); - test( - 'should resolve a subtree of an object, and return the targeted subtree', - async () => { - const input = { - a: { + test('should resolve a subtree of an object, and return the targeted subtree', async () => { + const input = { + a: { + this: 'is my object', + }, + b: { + description: 'here is my stuff!', + contents: { + $ref: '#/a', + }, + }, + }; + + const res = await resolve(input, ['b']); + + expect(res).toEqual({ + errors: [], + spec: { + description: 'here is my stuff!', + contents: { this: 'is my object', + $$ref: '#/a', + }, + }, + }); + }); + + test('should resolve circular $refs when a baseDoc is provided', async () => { + const input = { + one: { + $ref: '#/two', + }, + two: { + a: { + $ref: '#/three', }, + }, + three: { b: { - description: 'here is my stuff!', - contents: { - $ref: '#/a', - }, + $ref: '#/two', }, - }; - - const res = await resolve(input, ['b']); + }, + }; - expect(res).toEqual({ - errors: [], - spec: { - description: 'here is my stuff!', - contents: { - this: 'is my object', - $$ref: '#/a', - }, - }, - }); - }, - ); + const res = await resolve(input, ['one'], { + baseDoc: 'http://example.com/swagger.json', + returnEntireTree: true, + }); - test( - 'should resolve circular $refs when a baseDoc is provided', - async () => { - const input = { + expect(res).toEqual({ + errors: [], + spec: { one: { - $ref: '#/two', + $$ref: '#/two', + a: { + $$ref: '#/three', + b: { + $ref: '#/two', + }, + }, }, two: { a: { @@ -63,39 +88,9 @@ describe('subtree $ref resolver', () => { $ref: '#/two', }, }, - }; - - const res = await resolve(input, ['one'], { - baseDoc: 'http://example.com/swagger.json', - returnEntireTree: true, - }); - - expect(res).toEqual({ - errors: [], - spec: { - one: { - $$ref: '#/two', - a: { - $$ref: '#/three', - b: { - $ref: '#/two', - }, - }, - }, - two: { - a: { - $ref: '#/three', - }, - }, - three: { - b: { - $ref: '#/two', - }, - }, - }, - }); - }, - ); + }, + }); + }); test('should return null when the path is invalid', async () => { const input = { diff --git a/test/swagger2/execute/apply-securities.js b/test/swagger2/execute/apply-securities.js index a5b9935f0..7ec243e3c 100644 --- a/test/swagger2/execute/apply-securities.js +++ b/test/swagger2/execute/apply-securities.js @@ -1,90 +1,90 @@ import { applySecurities } from '../../../src/execute/swagger2/build-request'; describe('swagger2 - execute - applySecurities', () => { - test( - 'should NOT add any securities, if the operation does not require it', - () => { - const spec = { - host: 'swagger.io', - basePath: '/v1', - security: [{ apiKey: [] }], - paths: { - '/one': { - get: { - operationId: 'getMe', - }, + test('should NOT add any securities, if the operation does not require it', () => { + const spec = { + host: 'swagger.io', + basePath: '/v1', + security: [{ apiKey: [] }], + paths: { + '/one': { + get: { + operationId: 'getMe', }, }, - securityDefinitions: { - apiKey: { - in: 'header', - name: 'api_key', - type: 'apiKey', - }, + }, + securityDefinitions: { + apiKey: { + in: 'header', + name: 'api_key', + type: 'apiKey', }, - }; - - const securities = {}; - const request = { - url: 'http://swagger.io/v1/one', - method: 'GET', - }; - - const applySecurity = applySecurities({ - request, securities, operation: spec.paths['/one'].get, spec, - }); - - expect(applySecurity).toEqual({ - url: 'http://swagger.io/v1/one', - method: 'GET', - }); - }, - ); - - test( - 'should add a basic auth if operation requires it and has header passed', - () => { - const spec = { - host: 'swagger.io', - basePath: '/v1', - security: [{ authMe: [] }], - paths: { - '/one': { - get: { - operationId: 'getMe', - security: [{ authMe: [] }], - }, + }, + }; + + const securities = {}; + const request = { + url: 'http://swagger.io/v1/one', + method: 'GET', + }; + + const applySecurity = applySecurities({ + request, + securities, + operation: spec.paths['/one'].get, + spec, + }); + + expect(applySecurity).toEqual({ + url: 'http://swagger.io/v1/one', + method: 'GET', + }); + }); + + test('should add a basic auth if operation requires it and has header passed', () => { + const spec = { + host: 'swagger.io', + basePath: '/v1', + security: [{ authMe: [] }], + paths: { + '/one': { + get: { + operationId: 'getMe', + security: [{ authMe: [] }], }, }, - securityDefinitions: { - authMe: { - type: 'basic', - }, + }, + securityDefinitions: { + authMe: { + type: 'basic', }, - }; - - const request = { - url: 'http://swagger.io/v1/one', - method: 'GET', - query: {}, - }; - const securities = { - authorized: { - authMe: { - header: 'Basic Zm9vOmJhcg==', - }, + }, + }; + + const request = { + url: 'http://swagger.io/v1/one', + method: 'GET', + query: {}, + }; + const securities = { + authorized: { + authMe: { + header: 'Basic Zm9vOmJhcg==', }, - }; + }, + }; - const applySecurity = applySecurities({ - request, securities, operation: spec.paths['/one'].get, spec, - }); + const applySecurity = applySecurities({ + request, + securities, + operation: spec.paths['/one'].get, + spec, + }); - expect(applySecurity.headers).toEqual({ - authorization: 'Basic Zm9vOmJhcg==', - }); - }, - ); + expect(applySecurity.headers).toEqual({ + authorization: 'Basic Zm9vOmJhcg==', + }); + }); test('should add a basic auth if operation requires it', () => { const spec = { @@ -121,7 +121,10 @@ describe('swagger2 - execute - applySecurities', () => { }; const applySecurity = applySecurities({ - request, securities, operation: spec.paths['/one'].get, spec, + request, + securities, + operation: spec.paths['/one'].get, + spec, }); expect(applySecurity.headers).toEqual({ @@ -164,7 +167,10 @@ describe('swagger2 - execute - applySecurities', () => { }; const applySecurity = applySecurities({ - request, securities, operation: spec.paths['/one'].get, spec, + request, + securities, + operation: spec.paths['/one'].get, + spec, }); expect(applySecurity.headers).toEqual({ @@ -213,7 +219,10 @@ describe('swagger2 - execute - applySecurities', () => { }; const applySecurity = applySecurities({ - request, securities, operation: spec.paths['/one'].get, spec, + request, + securities, + operation: spec.paths['/one'].get, + spec, }); expect(applySecurity.headers).toEqual({ diff --git a/test/swagger2/execute/build-request.js b/test/swagger2/execute/build-request.js index 4a1fd0329..d1fe9375e 100644 --- a/test/swagger2/execute/build-request.js +++ b/test/swagger2/execute/build-request.js @@ -35,7 +35,7 @@ describe('buildRequest - swagger 2.0', () => { method: 'GET', url: '/one?name=', credentials: 'same-origin', - headers: { }, + headers: {}, }); });