mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
Merge develop into feature/meta-data-function
This commit is contained in:
@@ -1,4 +1,11 @@
|
|||||||
# OpenAPI-Postman Changelog
|
# OpenAPI-Postman Changelog
|
||||||
|
#### v1.1.13 (April 21, 2020)
|
||||||
|
* Added support for detailed validation body mismatches with option detailedBlobValidation.
|
||||||
|
* Fix for [#8098](https://github.com/postmanlabs/postman-app-support/issues/8098) - Unable to validate schema with type array.
|
||||||
|
* Fixed URIError for invalid URI in transaction.
|
||||||
|
* Fix for [#152](https://github.com/postmanlabs/openapi-to-postman/issues/152) - Path references not resolved due to improver handling of special characters.
|
||||||
|
* Fix for [#160](https://github.com/postmanlabs/openapi-to-postman/issues/160) - Added handling for variables in local servers not a part of a URL segment. All path servers to be added as collection variables.
|
||||||
|
* Unresolved refs will not be stored in schemaResolutionCache.
|
||||||
|
|
||||||
#### v1.1.12 (Mar 26, 2020)
|
#### v1.1.12 (Mar 26, 2020)
|
||||||
* Fix for https://github.com/postmanlabs/openapi-to-postman/issues/133 and https://github.com/postmanlabs/openapi-to-postman/issues/101
|
* Fix for https://github.com/postmanlabs/openapi-to-postman/issues/133 and https://github.com/postmanlabs/openapi-to-postman/issues/101
|
||||||
|
|||||||
4
index.js
4
index.js
@@ -28,8 +28,8 @@ module.exports = {
|
|||||||
schema.mergeAndValidate(cb);
|
schema.mergeAndValidate(cb);
|
||||||
},
|
},
|
||||||
|
|
||||||
getOptions: function() {
|
getOptions: function(mode, criteria) {
|
||||||
return SchemaPack.getOptions();
|
return SchemaPack.getOptions(mode, criteria);
|
||||||
},
|
},
|
||||||
|
|
||||||
// new API
|
// new API
|
||||||
|
|||||||
49
lib/ajvValidationError.js
Normal file
49
lib/ajvValidationError.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function generates reason and reasonCodes (used in mismatch objects) using Ajv Validation Error
|
||||||
|
*
|
||||||
|
* @param {Object} ajvValidationErrorObj Ajv Validation Error Object (reference: https://ajv.js.org/#validation-errors)
|
||||||
|
* @param {Object} data data needed for generation of mismatch Object
|
||||||
|
*
|
||||||
|
* @returns {Object} mismatchObj with reason and reasonCode properties
|
||||||
|
*/
|
||||||
|
function ajvValidationError(ajvValidationErrorObj, data) {
|
||||||
|
var mismatchPropName = _.get(ajvValidationErrorObj, 'dataPath', '').slice(1),
|
||||||
|
mismatchObj = {
|
||||||
|
reason: `The ${data.humanPropName} property "${mismatchPropName}" ` +
|
||||||
|
`${ajvValidationErrorObj.message}`,
|
||||||
|
reasonCode: 'INVALID_TYPE'
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (ajvValidationErrorObj.keyword) {
|
||||||
|
|
||||||
|
case 'additionalProperties':
|
||||||
|
mismatchObj.reasonCode = 'MISSING_IN_SCHEMA';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'dependencies':
|
||||||
|
mismatchObj.reason = `The ${data.humanPropName} property "${mismatchPropName}" ` +
|
||||||
|
`should have property "${_.get(ajvValidationErrorObj, 'params.missingProperty')}" when property ` +
|
||||||
|
`"${_.get(ajvValidationErrorObj, 'params.property')}" is present`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'required':
|
||||||
|
mismatchObj.reasonCode = 'MISSING_IN_REQUEST';
|
||||||
|
mismatchObj.reason = `The ${data.humanPropName} property "${mismatchPropName}" should have required ` +
|
||||||
|
`property "${_.get(ajvValidationErrorObj, 'params.missingProperty')}"`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'propertyNames':
|
||||||
|
mismatchObj.reason = `The ${data.humanPropName} property "${mismatchPropName}" contains invalid ` +
|
||||||
|
`property named "${_.get(ajvValidationErrorObj, 'params.propertyName')}"`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mismatchObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ajvValidationError;
|
||||||
76
lib/deref.js
76
lib/deref.js
@@ -54,23 +54,28 @@ module.exports = {
|
|||||||
* @param {string} parameterSourceOption tells that the schema object is of request or response
|
* @param {string} parameterSourceOption tells that the schema object is of request or response
|
||||||
* @param {*} components components in openapi spec.
|
* @param {*} components components in openapi spec.
|
||||||
* @param {object} schemaResolutionCache stores already resolved references
|
* @param {object} schemaResolutionCache stores already resolved references
|
||||||
|
* @param {*} resolveFor - resolve refs for validation/conversion (value to be one of VALIDATION/CONVERSION)
|
||||||
* @param {*} stack counter which keeps a tab on nested schemas
|
* @param {*} stack counter which keeps a tab on nested schemas
|
||||||
* @param {*} seenRef References that are repeated. Used to identify circular references.
|
* @param {*} seenRef References that are repeated. Used to identify circular references.
|
||||||
* @returns {*} schema - schema that adheres to all individual schemas in schemaArr
|
* @returns {*} schema - schema that adheres to all individual schemas in schemaArr
|
||||||
*/
|
*/
|
||||||
resolveAllOf: function (schemaArr, parameterSourceOption, components, schemaResolutionCache, stack = 0, seenRef) {
|
resolveAllOf: function (schemaArr, parameterSourceOption, components, schemaResolutionCache,
|
||||||
|
resolveFor = 'CONVERSION', stack = 0, seenRef) {
|
||||||
|
|
||||||
if (!(schemaArr instanceof Array)) {
|
if (!(schemaArr instanceof Array)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schemaArr.length === 1) {
|
if (schemaArr.length === 1) {
|
||||||
// for just one entry in allOf, don't need to enforce type: object restriction
|
// for just one entry in allOf, don't need to enforce type: object restriction
|
||||||
return this.resolveRefs(schemaArr[0], parameterSourceOption, components, schemaResolutionCache, stack, seenRef);
|
return this.resolveRefs(schemaArr[0], parameterSourceOption, components, schemaResolutionCache, resolveFor,
|
||||||
|
stack, seenRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate one object for each schema
|
// generate one object for each schema
|
||||||
let indivObjects = schemaArr.map((schema) => {
|
let indivObjects = schemaArr.map((schema) => {
|
||||||
return this.resolveRefs(schema, parameterSourceOption, components, schemaResolutionCache, stack, seenRef);
|
return this.resolveRefs(schema, parameterSourceOption, components, schemaResolutionCache, resolveFor,
|
||||||
|
stack, seenRef);
|
||||||
}).filter((schema) => {
|
}).filter((schema) => {
|
||||||
return schema.type === 'object';
|
return schema.type === 'object';
|
||||||
}),
|
}),
|
||||||
@@ -107,16 +112,22 @@ module.exports = {
|
|||||||
* @param {string} parameterSourceOption tells that the schema object is of request or response
|
* @param {string} parameterSourceOption tells that the schema object is of request or response
|
||||||
* @param {*} components components in openapi spec.
|
* @param {*} components components in openapi spec.
|
||||||
* @param {object} schemaResolutionCache stores already resolved references
|
* @param {object} schemaResolutionCache stores already resolved references
|
||||||
|
* @param {*} resolveFor - resolve refs for validation/conversion (value to be one of VALIDATION/CONVERSION)
|
||||||
* @param {*} stack counter which keeps a tab on nested schemas
|
* @param {*} stack counter which keeps a tab on nested schemas
|
||||||
* @param {*} seenRef - References that are repeated. Used to identify circular references.
|
* @param {*} seenRef - References that are repeated. Used to identify circular references.
|
||||||
* @returns {*} schema satisfying JSON-schema-faker.
|
* @returns {*} schema satisfying JSON-schema-faker.
|
||||||
*/
|
*/
|
||||||
resolveRefs: function (schema, parameterSourceOption, components, schemaResolutionCache, stack = 0, seenRef = {}) {
|
|
||||||
var resolvedSchema, prop, splitRef;
|
resolveRefs: function (schema, parameterSourceOption, components, schemaResolutionCache,
|
||||||
|
resolveFor = 'CONVERSION', stack = 0, seenRef = {}) {
|
||||||
|
var resolvedSchema, prop, splitRef,
|
||||||
|
ERR_TOO_MANY_LEVELS = '<Error: Too many levels of nesting to fake this schema>';
|
||||||
|
|
||||||
stack++;
|
stack++;
|
||||||
schemaResolutionCache = schemaResolutionCache || {};
|
schemaResolutionCache = schemaResolutionCache || {};
|
||||||
|
|
||||||
if (stack > 20) {
|
if (stack > 20) {
|
||||||
return { value: '<Error: Too many levels of nesting to fake this schema>' };
|
return { value: ERR_TOO_MANY_LEVELS };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
@@ -124,16 +135,16 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (schema.anyOf) {
|
if (schema.anyOf) {
|
||||||
return this.resolveRefs(schema.anyOf[0], parameterSourceOption, components, schemaResolutionCache, stack,
|
return this.resolveRefs(schema.anyOf[0], parameterSourceOption, components, schemaResolutionCache, resolveFor,
|
||||||
_.cloneDeep(seenRef));
|
stack, _.cloneDeep(seenRef));
|
||||||
}
|
}
|
||||||
if (schema.oneOf) {
|
if (schema.oneOf) {
|
||||||
return this.resolveRefs(schema.oneOf[0], parameterSourceOption, components, schemaResolutionCache, stack,
|
return this.resolveRefs(schema.oneOf[0], parameterSourceOption, components, schemaResolutionCache, resolveFor,
|
||||||
_.cloneDeep(seenRef));
|
stack, _.cloneDeep(seenRef));
|
||||||
}
|
}
|
||||||
if (schema.allOf) {
|
if (schema.allOf) {
|
||||||
return this.resolveAllOf(schema.allOf, parameterSourceOption, components, schemaResolutionCache, stack,
|
return this.resolveAllOf(schema.allOf, parameterSourceOption, components, schemaResolutionCache, resolveFor,
|
||||||
_.cloneDeep(seenRef));
|
stack, _.cloneDeep(seenRef));
|
||||||
}
|
}
|
||||||
if (schema.$ref && _.isFunction(schema.$ref.split)) {
|
if (schema.$ref && _.isFunction(schema.$ref.split)) {
|
||||||
let refKey = schema.$ref;
|
let refKey = schema.$ref;
|
||||||
@@ -160,12 +171,27 @@ module.exports = {
|
|||||||
// will be resolved - we don't care about anything after the components part
|
// will be resolved - we don't care about anything after the components part
|
||||||
// splitRef.slice(1) will return ['components', 'schemas', 'PaginationEnvelope', 'properties', 'page']
|
// splitRef.slice(1) will return ['components', 'schemas', 'PaginationEnvelope', 'properties', 'page']
|
||||||
// not using _.get here because that fails if there's a . in the property name (Pagination.Envelope, for example)
|
// not using _.get here because that fails if there's a . in the property name (Pagination.Envelope, for example)
|
||||||
resolvedSchema = this._getEscaped(components, splitRef.slice(1));
|
|
||||||
|
splitRef = splitRef.slice(1).map((elem) => {
|
||||||
|
// https://swagger.io/docs/specification/using-ref#escape
|
||||||
|
// since / is the default delimiter, slashes are escaped with ~1
|
||||||
|
return decodeURIComponent(
|
||||||
|
elem
|
||||||
|
.replace(/~1/g, '/')
|
||||||
|
.replace(/~0/g, '~')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
resolvedSchema = this._getEscaped(components, splitRef);
|
||||||
|
|
||||||
if (resolvedSchema) {
|
if (resolvedSchema) {
|
||||||
let refResolvedSchema = this.resolveRefs(resolvedSchema, parameterSourceOption,
|
let refResolvedSchema = this.resolveRefs(resolvedSchema, parameterSourceOption,
|
||||||
components, schemaResolutionCache, stack, _.cloneDeep(seenRef));
|
components, schemaResolutionCache, resolveFor, stack, _.cloneDeep(seenRef));
|
||||||
schemaResolutionCache[refKey] = refResolvedSchema;
|
|
||||||
|
if (refResolvedSchema && refResolvedSchema.value !== ERR_TOO_MANY_LEVELS) {
|
||||||
|
schemaResolutionCache[refKey] = refResolvedSchema;
|
||||||
|
}
|
||||||
|
|
||||||
return refResolvedSchema;
|
return refResolvedSchema;
|
||||||
}
|
}
|
||||||
return { value: 'reference ' + schema.$ref + ' not found in the OpenAPI spec' };
|
return { value: 'reference ' + schema.$ref + ' not found in the OpenAPI spec' };
|
||||||
@@ -196,7 +222,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
tempSchema.properties[prop] = this.resolveRefs(property,
|
tempSchema.properties[prop] = this.resolveRefs(property,
|
||||||
parameterSourceOption, components, schemaResolutionCache, stack, _.cloneDeep(seenRef));
|
parameterSourceOption, components, schemaResolutionCache, resolveFor, stack, _.cloneDeep(seenRef));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tempSchema;
|
return tempSchema;
|
||||||
@@ -207,15 +233,19 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
else if (schema.type === 'array' && schema.items) {
|
else if (schema.type === 'array' && schema.items) {
|
||||||
|
|
||||||
// This nonsense is needed because the schemaFaker doesn't respect options.maxItems/minItems
|
// For VALIDATION - keep minItems and maxItems properties defined by user in schema as is
|
||||||
schema.maxItems = 2;
|
// FOR CONVERSION - need to set both properties to 2 for schema faking
|
||||||
schema.minItems = 2;
|
if (resolveFor === 'CONVERSION') {
|
||||||
|
// This is needed because the schemaFaker doesn't respect options.maxItems/minItems
|
||||||
|
schema.maxItems = 2;
|
||||||
|
schema.minItems = 2;
|
||||||
|
}
|
||||||
// have to create a shallow clone of schema object,
|
// have to create a shallow clone of schema object,
|
||||||
// so that the original schema.items object will not change
|
// so that the original schema.items object will not change
|
||||||
// without this, schemas with circular references aren't faked correctly
|
// without this, schemas with circular references aren't faked correctly
|
||||||
let tempSchema = _.omit(schema, 'items');
|
let tempSchema = _.omit(schema, 'items');
|
||||||
tempSchema.items = this.resolveRefs(schema.items, parameterSourceOption,
|
tempSchema.items = this.resolveRefs(schema.items, parameterSourceOption,
|
||||||
components, schemaResolutionCache, stack, _.cloneDeep(seenRef));
|
components, schemaResolutionCache, resolveFor, stack, _.cloneDeep(seenRef));
|
||||||
return tempSchema;
|
return tempSchema;
|
||||||
}
|
}
|
||||||
else if (!schema.hasOwnProperty('default')) {
|
else if (!schema.hasOwnProperty('default')) {
|
||||||
@@ -251,7 +281,11 @@ module.exports = {
|
|||||||
if (!schema.type) {
|
if (!schema.type) {
|
||||||
schema.type = 'string';
|
schema.type = 'string';
|
||||||
}
|
}
|
||||||
delete schema.format;
|
|
||||||
|
// For VALIDATION - Keep format as is to perform ajv validation on format
|
||||||
|
if (resolveFor !== 'VALIDATION') {
|
||||||
|
delete schema.format;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
|
|||||||
134
lib/options.js
134
lib/options.js
@@ -12,74 +12,80 @@ module.exports = {
|
|||||||
* availableOptions - allowed values (only for type=enum)
|
* availableOptions - allowed values (only for type=enum)
|
||||||
* description - human-readable description of the item
|
* description - human-readable description of the item
|
||||||
* external - whether the option is settable via the API
|
* external - whether the option is settable via the API
|
||||||
|
* usage - array of supported types of usage (i.e. CONVERSION, VALIDATION)
|
||||||
*
|
*
|
||||||
* @param {string} [mode='document'] Describes use-case. 'document' will return an array
|
* @param {string} [mode='document'] Describes use-case. 'document' will return an array
|
||||||
* with all options being described. 'use' will return the default values of all options
|
* with all options being described. 'use' will return the default values of all options
|
||||||
|
* @param {Object} criteria Decribes required criteria for options to be returned. can have properties
|
||||||
|
* external: <boolean>
|
||||||
|
* usage: <array> (Array of supported usage type - CONVERSION, VALIDATION)
|
||||||
* @returns {mixed} An array or object (depending on mode) that describes available options
|
* @returns {mixed} An array or object (depending on mode) that describes available options
|
||||||
*/
|
*/
|
||||||
getOptions: function(mode = 'document') {
|
getOptions: function(mode = 'document', criteria = {}) {
|
||||||
|
// Override mode & criteria if first arg is criteria (objects)
|
||||||
|
if (typeof mode === 'object') {
|
||||||
|
criteria = mode;
|
||||||
|
mode = 'document';
|
||||||
|
}
|
||||||
|
|
||||||
let optsArray = [
|
let optsArray = [
|
||||||
{
|
{
|
||||||
name: 'Set request name source',
|
name: 'Naming requests',
|
||||||
id: 'requestNameSource',
|
id: 'requestNameSource',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: 'fallback',
|
default: 'Fallback',
|
||||||
availableOptions: ['url', 'fallback'],
|
availableOptions: ['Url', 'Fallback'],
|
||||||
description: 'Option for setting source for a request name',
|
description: 'Determines how the requests inside the generated collection will be named.' +
|
||||||
external: true
|
' If “Fallback” is selected, the request will be named after one of the following schema' +
|
||||||
|
' values: `description`, `operationid`, `url`.',
|
||||||
|
external: true,
|
||||||
|
usage: ['CONVERSION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Set indent character',
|
name: 'Set indent character',
|
||||||
id: 'indentCharacter',
|
id: 'indentCharacter',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: ' ',
|
default: 'Space',
|
||||||
availableOptions: [' ', '\t'],
|
availableOptions: ['Space', 'Tab'],
|
||||||
description: 'Option for setting indentation character',
|
description: 'Option for setting indentation character',
|
||||||
external: true
|
external: true,
|
||||||
|
usage: ['CONVERSION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Toggle for collapsing folder for long routes',
|
name: 'Collapse redundant folders',
|
||||||
id: 'collapseFolders',
|
id: 'collapseFolders',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: true,
|
default: true,
|
||||||
description: 'Determines whether the importer should attempt to collapse redundant folders into one.' +
|
description: 'Importing will collapse all folders that have only one child element and lack ' +
|
||||||
'Folders are redundant if they have only one child element, and don\'t' +
|
'persistent folder-level data.',
|
||||||
'have any folder-level data to persist.',
|
external: true,
|
||||||
external: true
|
usage: ['CONVERSION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Set root request parameters type',
|
name: 'Request parameter generation',
|
||||||
id: 'requestParametersResolution',
|
id: 'requestParametersResolution',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: 'schema',
|
default: 'Schema',
|
||||||
availableOptions: ['example', 'schema'],
|
availableOptions: ['Example', 'Schema'],
|
||||||
description: 'Determines how request parameters (query parameters, path parameters, headers,' +
|
description: 'Select whether to generate the request parameters based on the' +
|
||||||
'or the request body) should be generated. Setting this to schema will cause the importer to' +
|
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
|
||||||
'use the parameter\'s schema as an indicator; `example` will cause the example (if provided)' +
|
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
|
||||||
'to be picked up.',
|
' in the schema.',
|
||||||
external: true
|
external: true,
|
||||||
|
usage: ['CONVERSION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Set example request and response parameters type',
|
name: 'Response parameter generation',
|
||||||
id: 'exampleParametersResolution',
|
id: 'exampleParametersResolution',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: 'example',
|
default: 'Example',
|
||||||
availableOptions: ['example', 'schema'],
|
availableOptions: ['Example', 'Schema'],
|
||||||
description: 'Determines how response parameters (query parameters, path parameters, headers,' +
|
description: 'Select whether to generate the response parameters based on the' +
|
||||||
'or the request body) should be generated. Setting this to schema will cause the importer to' +
|
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
|
||||||
'use the parameter\'s schema as an indicator; `example` will cause the example (if provided)' +
|
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
|
||||||
'to be picked up.',
|
' in the schema.',
|
||||||
external: true
|
external: true,
|
||||||
},
|
usage: ['CONVERSION']
|
||||||
{
|
|
||||||
name: 'Set folder strategy',
|
|
||||||
id: 'folderStrategy',
|
|
||||||
type: 'enum',
|
|
||||||
default: 'paths',
|
|
||||||
availableOptions: ['paths', 'tags'],
|
|
||||||
description: 'Determines whether the importer should attempt to create the folders according' +
|
|
||||||
'to paths or tags which are given in the spec.',
|
|
||||||
external: true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Enable Schema Faking',
|
name: 'Enable Schema Faking',
|
||||||
@@ -87,15 +93,17 @@ module.exports = {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: true,
|
default: true,
|
||||||
description: 'Whether or not schemas should be faked.',
|
description: 'Whether or not schemas should be faked.',
|
||||||
external: false
|
external: false,
|
||||||
|
usage: ['CONVERSION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Short error messages during request <> schema validation',
|
name: 'Short error messages during request <> schema validation',
|
||||||
id: 'shortValidationErrors',
|
id: 'shortValidationErrors',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
description: 'Whether detailed error messages are required for request <> schema validation operations',
|
description: 'Whether detailed error messages are required for request <> schema validation operations.',
|
||||||
external: false
|
external: true,
|
||||||
|
usage: ['VALIDATION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Properties to ignore during validation',
|
name: 'Properties to ignore during validation',
|
||||||
@@ -105,7 +113,8 @@ module.exports = {
|
|||||||
description: 'Specific properties (parts of a request/response pair) to ignore during validation.' +
|
description: 'Specific properties (parts of a request/response pair) to ignore during validation.' +
|
||||||
' Must be sent as an array of strings. Valid inputs in the array: PATHVARIABLE, QUERYPARAM,' +
|
' Must be sent as an array of strings. Valid inputs in the array: PATHVARIABLE, QUERYPARAM,' +
|
||||||
' HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY',
|
' HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY',
|
||||||
external: true
|
external: true,
|
||||||
|
usage: ['VALIDATION']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Whether MISSING_IN_SCHEMA mismatches should be returned',
|
name: 'Whether MISSING_IN_SCHEMA mismatches should be returned',
|
||||||
@@ -114,15 +123,48 @@ module.exports = {
|
|||||||
default: false,
|
default: false,
|
||||||
description: 'MISSING_IN_SCHEMA indicates that an extra parameter was included in the request. For most ' +
|
description: 'MISSING_IN_SCHEMA indicates that an extra parameter was included in the request. For most ' +
|
||||||
'use cases, this need not be considered an error.',
|
'use cases, this need not be considered an error.',
|
||||||
external: true
|
external: true,
|
||||||
|
usage: ['VALIDATION']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Show detailed body validation messages',
|
||||||
|
id: 'detailedBlobValidation',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'Determines whether to show detailed mismatch information for application/json content ' +
|
||||||
|
'in the request/response body.',
|
||||||
|
external: true,
|
||||||
|
usage: ['VALIDATION']
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Filter options based on criteria
|
||||||
|
if (_.isObject(criteria)) {
|
||||||
|
typeof criteria.external === 'boolean' && (optsArray = _.filter(optsArray, { external: criteria.external }));
|
||||||
|
if (_.isArray(criteria.usage)) {
|
||||||
|
let tempOptsArray = [];
|
||||||
|
|
||||||
|
_.forEach(criteria.usage, (usageCriteria) => {
|
||||||
|
tempOptsArray = _.concat(tempOptsArray, _.filter(optsArray, (option) => {
|
||||||
|
return _.includes(option.usage, usageCriteria);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
optsArray = tempOptsArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mode === 'use') {
|
if (mode === 'use') {
|
||||||
// options to be used as default kv-pairs
|
// options to be used as default kv-pairs
|
||||||
let defOptions = {};
|
let defOptions = {};
|
||||||
_.each(optsArray, (opt) => {
|
_.each(optsArray, (opt) => {
|
||||||
defOptions[opt.id] = opt.default;
|
// special handling for indent character as in documentation it states `Tab` and `Space`
|
||||||
|
// but for the generation mode, we need actual values
|
||||||
|
if (opt.id === 'indentCharacter') {
|
||||||
|
defOptions[opt.id] = opt.default === 'tab' ? '\t' : ' ';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defOptions[opt.id] = opt.default;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return defOptions;
|
return defOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const async = require('async'),
|
|||||||
_ = require('lodash'),
|
_ = require('lodash'),
|
||||||
xmlFaker = require('./xmlSchemaFaker.js'),
|
xmlFaker = require('./xmlSchemaFaker.js'),
|
||||||
openApiErr = require('./error.js'),
|
openApiErr = require('./error.js'),
|
||||||
|
ajvValidationError = require('./ajvValidationError'),
|
||||||
utils = require('./utils.js'),
|
utils = require('./utils.js'),
|
||||||
defaultOptions = require('../lib/options.js').getOptions('use'),
|
defaultOptions = require('../lib/options.js').getOptions('use'),
|
||||||
{ Node, Trie } = require('./trie.js'),
|
{ Node, Trie } = require('./trie.js'),
|
||||||
@@ -60,10 +61,15 @@ const async = require('async'),
|
|||||||
QUERYPARAM: 'query parameter',
|
QUERYPARAM: 'query parameter',
|
||||||
PATHVARIABLE: 'path variable',
|
PATHVARIABLE: 'path variable',
|
||||||
HEADER: 'header',
|
HEADER: 'header',
|
||||||
REQUEST_BODY: 'request body',
|
BODY: 'request body',
|
||||||
RESPONSE_HEADER: 'response header',
|
RESPONSE_HEADER: 'response header',
|
||||||
RESPONSE_BODY: 'response body'
|
RESPONSE_BODY: 'response body'
|
||||||
},
|
},
|
||||||
|
// Specifies types of processing Refs
|
||||||
|
PROCESSING_TYPE = {
|
||||||
|
VALIDATION: 'VALIDATION',
|
||||||
|
CONVERSION: 'CONVERSION'
|
||||||
|
},
|
||||||
|
|
||||||
// These are the methods supported in the PathItem schema
|
// These are the methods supported in the PathItem schema
|
||||||
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#pathItemObject
|
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#pathItemObject
|
||||||
@@ -121,7 +127,8 @@ function safeSchemaFaker(oldSchema, resolveTo, parameterSourceOption, components
|
|||||||
schemaResolutionCache = _.get(schemaCache, 'schemaResolutionCache', {}),
|
schemaResolutionCache = _.get(schemaCache, 'schemaResolutionCache', {}),
|
||||||
schemaFakerCache = _.get(schemaCache, 'schemaFakerCache', {});
|
schemaFakerCache = _.get(schemaCache, 'schemaFakerCache', {});
|
||||||
|
|
||||||
resolvedSchema = deref.resolveRefs(oldSchema, parameterSourceOption, components, schemaResolutionCache);
|
resolvedSchema = deref.resolveRefs(oldSchema, parameterSourceOption, components, schemaResolutionCache,
|
||||||
|
PROCESSING_TYPE.CONVERSION);
|
||||||
key = JSON.stringify(resolvedSchema);
|
key = JSON.stringify(resolvedSchema);
|
||||||
|
|
||||||
if (resolveTo === 'schema') {
|
if (resolveTo === 'schema') {
|
||||||
@@ -1522,7 +1529,7 @@ module.exports = {
|
|||||||
return path.match(/(\{\{[^\/\{\}]+\}\})/g);
|
return path.match(/(\{\{[^\/\{\}]+\}\})/g);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Separates outs collection and path variables from the reqUrl
|
/** Separates out collection and path variables from the reqUrl
|
||||||
*
|
*
|
||||||
* @param {string} reqUrl Request Url
|
* @param {string} reqUrl Request Url
|
||||||
* @param {Array} pathVars Path variables
|
* @param {Array} pathVars Path variables
|
||||||
@@ -1558,7 +1565,7 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { reqUrl, pathVars, collectionVars };
|
return { url: reqUrl, pathVars, collectionVars };
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1605,7 +1612,7 @@ module.exports = {
|
|||||||
sanitizeResult = this.sanitizeUrlPathParams(reqUrl, reqParams.path);
|
sanitizeResult = this.sanitizeUrlPathParams(reqUrl, reqParams.path);
|
||||||
|
|
||||||
// Updated reqUrl
|
// Updated reqUrl
|
||||||
reqUrl = sanitizeResult.reqUrl;
|
reqUrl = sanitizeResult.url;
|
||||||
|
|
||||||
// Updated reqParams.path
|
// Updated reqParams.path
|
||||||
reqParams.path = sanitizeResult.pathVars;
|
reqParams.path = sanitizeResult.pathVars;
|
||||||
@@ -1625,24 +1632,59 @@ module.exports = {
|
|||||||
|
|
||||||
if (Array.isArray(localServers) && localServers.length) {
|
if (Array.isArray(localServers) && localServers.length) {
|
||||||
serverObj = operationItem.properties.servers[0];
|
serverObj = operationItem.properties.servers[0];
|
||||||
baseUrl = serverObj.url.replace(/{/g, ':').replace(/}/g, '');
|
|
||||||
baseUrl += reqUrl;
|
// convert all {anything} to {{anything}}
|
||||||
|
baseUrl = this.fixPathVariablesInUrl(serverObj.url);
|
||||||
|
|
||||||
|
// add serverObj variables to pathVarArray
|
||||||
if (serverObj.variables) {
|
if (serverObj.variables) {
|
||||||
pathVarArray = this.convertPathVariables('method', [], serverObj.variables, components, options, schemaCache);
|
_.forOwn(serverObj.variables, (value, key) => {
|
||||||
|
pathVarArray.push({
|
||||||
|
name: key,
|
||||||
|
value: value.default || '',
|
||||||
|
description: this.getParameterDescription(value)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// use pathVarAray to sanitize url for path params and collection variables.
|
||||||
|
sanitizeResult = this.sanitizeUrlPathParams(baseUrl, pathVarArray);
|
||||||
|
|
||||||
|
// update the base url with update url
|
||||||
|
baseUrl = sanitizeResult.url;
|
||||||
|
|
||||||
|
// Add new collection variables to the variableStore
|
||||||
|
sanitizeResult.collectionVars.forEach((element) => {
|
||||||
|
if (!variableStore[element.name]) {
|
||||||
|
variableStore[element.name] = {
|
||||||
|
id: element.name,
|
||||||
|
value: element.value || '',
|
||||||
|
description: element.description,
|
||||||
|
type: 'collection'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove all the collection variables from serverObj.variables
|
||||||
|
serverObj.pathVariables = {};
|
||||||
|
sanitizeResult.pathVars.forEach((element) => {
|
||||||
|
serverObj.pathVariables[element.name] = serverObj.variables[element.name];
|
||||||
|
});
|
||||||
|
|
||||||
|
// use this new filterd serverObj.pathVariables
|
||||||
|
// to generate pm path variables.
|
||||||
|
pathVarArray = this.convertPathVariables('method', [],
|
||||||
|
serverObj.pathVariables, components, options, schemaCache);
|
||||||
}
|
}
|
||||||
|
baseUrl += reqUrl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// accounting for the overriding of the root level servers object if present at the path level
|
// accounting for the overriding of the root level servers object if present at the path level
|
||||||
if (Array.isArray(globalServers) && globalServers.length) {
|
if (Array.isArray(globalServers) && globalServers.length) {
|
||||||
if (operationItem.servers[0].hasOwnProperty('variables')) {
|
// All the global servers present at the path level are taken care of in generateTrieFromPaths
|
||||||
serverObj = operationItem.servers[0];
|
// Just adding the same structure of the url as the display URL.
|
||||||
baseUrl = serverObj.url.replace(/{/g, ':').replace(/}/g, '');
|
displayUrl = '{{' + operationItem.path + 'Url}}' + reqUrl;
|
||||||
pathVariables = serverObj.variables;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
displayUrl = '{{' + operationItem.path + 'Url}}' + reqUrl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// In case there are no server available use the baseUrl
|
||||||
else {
|
else {
|
||||||
baseUrl += reqUrl;
|
baseUrl += reqUrl;
|
||||||
if (pathVariables) {
|
if (pathVariables) {
|
||||||
@@ -1950,7 +1992,7 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {*} property - one of QUERYPARAM, PATHVARIABLE, HEADER, REQUEST_BODY, RESPONSE_HEADER, RESPONSE_BODY
|
* @param {*} property - one of QUERYPARAM, PATHVARIABLE, HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY
|
||||||
* @param {*} jsonPathPrefix - this will be prepended to all JSON schema paths on the request
|
* @param {*} jsonPathPrefix - this will be prepended to all JSON schema paths on the request
|
||||||
* @param {*} txnParamName - Optional - The name of the param being validated (useful for query params,
|
* @param {*} txnParamName - Optional - The name of the param being validated (useful for query params,
|
||||||
* req headers, res headers)
|
* req headers, res headers)
|
||||||
@@ -2035,6 +2077,7 @@ module.exports = {
|
|||||||
// simpler cases are handled by a type check
|
// simpler cases are handled by a type check
|
||||||
if (schema.type === 'array' || schema.type === 'object') {
|
if (schema.type === 'array' || schema.type === 'object') {
|
||||||
try {
|
try {
|
||||||
|
// the unknown formats are ones that are allowed in OAS, but not JSON schema
|
||||||
ajv = new Ajv({ unknownFormats: ['int32', 'int64'], allErrors: true });
|
ajv = new Ajv({ unknownFormats: ['int32', 'int64'], allErrors: true });
|
||||||
validate = ajv.compile(schema);
|
validate = ajv.compile(schema);
|
||||||
res = validate(valueToUse);
|
res = validate(valueToUse);
|
||||||
@@ -2044,13 +2087,33 @@ module.exports = {
|
|||||||
// input was invalid. Don't throw mismatch
|
// input was invalid. Don't throw mismatch
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
mismatches.push({
|
// Show detailed validation mismatches for only request/response body
|
||||||
property: property,
|
if (options.detailedBlobValidation && needJsonMatching) {
|
||||||
transactionJsonPath: jsonPathPrefix,
|
_.forEach(validate.errors, (ajvError) => {
|
||||||
schemaJsonPath: schemaPathPrefix,
|
mismatches.push(_.assign({
|
||||||
reasonCode: 'INVALID_TYPE',
|
property: property,
|
||||||
reason: 'The property didn\'t match the specified schema'
|
transactionJsonPath: jsonPathPrefix + ajvError.dataPath,
|
||||||
});
|
schemaJsonPath: schemaPathPrefix + ajvError.schemaPath.replace(/\//g, '.').slice(1)
|
||||||
|
}, ajvValidationError(ajvError, { property, humanPropName })));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let mismatchObj = {
|
||||||
|
reason: 'The property didn\'t match the specified schema',
|
||||||
|
reasonCode: 'INVALID_TYPE'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (property === 'BODY') {
|
||||||
|
mismatchObj.reason = 'The request body didn\'t match the specified schema';
|
||||||
|
mismatchObj.reasonCode = 'INVALID_BODY';
|
||||||
|
}
|
||||||
|
|
||||||
|
mismatches.push(_.assign({
|
||||||
|
property: property,
|
||||||
|
transactionJsonPath: jsonPathPrefix,
|
||||||
|
schemaJsonPath: schemaPathPrefix
|
||||||
|
}, mismatchObj));
|
||||||
|
}
|
||||||
|
|
||||||
// only return AJV mismatches
|
// only return AJV mismatches
|
||||||
return callback(null, mismatches);
|
return callback(null, mismatches);
|
||||||
@@ -2150,7 +2213,8 @@ module.exports = {
|
|||||||
pathVar.key,
|
pathVar.key,
|
||||||
pathVar.value,
|
pathVar.value,
|
||||||
schemaPathVar.pathPrefix + '[?(@.name==\'' + schemaPathVar.name + '\')]',
|
schemaPathVar.pathPrefix + '[?(@.name==\'' + schemaPathVar.name + '\')]',
|
||||||
deref.resolveRefs(schemaPathVar.schema, 'request', components, schemaResolutionCache),
|
deref.resolveRefs(schemaPathVar.schema, 'request', components, schemaResolutionCache,
|
||||||
|
PROCESSING_TYPE.VALIDATION),
|
||||||
components, options, cb);
|
components, options, cb);
|
||||||
}, 0);
|
}, 0);
|
||||||
}, (err, res) => {
|
}, (err, res) => {
|
||||||
@@ -2251,7 +2315,8 @@ module.exports = {
|
|||||||
pQuery.key,
|
pQuery.key,
|
||||||
pQuery.value,
|
pQuery.value,
|
||||||
schemaParam.pathPrefix + '[?(@.name==\'' + schemaParam.name + '\')]',
|
schemaParam.pathPrefix + '[?(@.name==\'' + schemaParam.name + '\')]',
|
||||||
deref.resolveRefs(schemaParam.schema, 'request', components, schemaResolutionCache),
|
deref.resolveRefs(schemaParam.schema, 'request', components, schemaResolutionCache,
|
||||||
|
PROCESSING_TYPE.VALIDATION),
|
||||||
components, options,
|
components, options,
|
||||||
cb
|
cb
|
||||||
);
|
);
|
||||||
@@ -2312,7 +2377,8 @@ module.exports = {
|
|||||||
pHeader.key,
|
pHeader.key,
|
||||||
pHeader.value,
|
pHeader.value,
|
||||||
schemaHeader.pathPrefix + '[?(@.name==\'' + schemaHeader.name + '\')]',
|
schemaHeader.pathPrefix + '[?(@.name==\'' + schemaHeader.name + '\')]',
|
||||||
deref.resolveRefs(schemaHeader.schema, 'request', components, schemaResolutionCache),
|
deref.resolveRefs(schemaHeader.schema, 'request', components, schemaResolutionCache,
|
||||||
|
PROCESSING_TYPE.VALIDATION),
|
||||||
components, options,
|
components, options,
|
||||||
cb
|
cb
|
||||||
);
|
);
|
||||||
@@ -2362,7 +2428,7 @@ module.exports = {
|
|||||||
mismatches.push({
|
mismatches.push({
|
||||||
property: mismatchProperty,
|
property: mismatchProperty,
|
||||||
transactionJsonPath: transactionPathPrefix + '/' + pHeader.key,
|
transactionJsonPath: transactionPathPrefix + '/' + pHeader.key,
|
||||||
schemaJsonPath: schemaPathPrefix + '/headers',
|
schemaJsonPath: schemaPathPrefix + '.headers',
|
||||||
reasonCode: 'MISSING_IN_SCHEMA',
|
reasonCode: 'MISSING_IN_SCHEMA',
|
||||||
reason: `The header ${pHeader.key} was not found in the schema`
|
reason: `The header ${pHeader.key} was not found in the schema`
|
||||||
});
|
});
|
||||||
@@ -2381,7 +2447,8 @@ module.exports = {
|
|||||||
pHeader.key,
|
pHeader.key,
|
||||||
pHeader.value,
|
pHeader.value,
|
||||||
schemaPathPrefix + '.headers[' + pHeader.key + ']',
|
schemaPathPrefix + '.headers[' + pHeader.key + ']',
|
||||||
deref.resolveRefs(schemaHeader.schema, 'response', components, schemaResolutionCache),
|
deref.resolveRefs(schemaHeader.schema, 'response', components, schemaResolutionCache,
|
||||||
|
PROCESSING_TYPE.VALIDATION),
|
||||||
components,
|
components,
|
||||||
options,
|
options,
|
||||||
cb
|
cb
|
||||||
@@ -2413,54 +2480,31 @@ module.exports = {
|
|||||||
// check for body modes
|
// check for body modes
|
||||||
// TODO: The application/json can be anything that's application/*+json
|
// TODO: The application/json can be anything that's application/*+json
|
||||||
let jsonSchemaBody = _.get(schemaPath, ['requestBody', 'content', 'application/json', 'schema']),
|
let jsonSchemaBody = _.get(schemaPath, ['requestBody', 'content', 'application/json', 'schema']),
|
||||||
mismatches = [],
|
|
||||||
mismatchProperty = 'BODY';
|
mismatchProperty = 'BODY';
|
||||||
|
|
||||||
if (options.validationPropertiesToIgnore.includes(mismatchProperty)) {
|
if (options.validationPropertiesToIgnore.includes(mismatchProperty)) {
|
||||||
return callback(null, []);
|
return callback(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only raw for now
|
||||||
if (requestBody && requestBody.mode === 'raw' && jsonSchemaBody) {
|
if (requestBody && requestBody.mode === 'raw' && jsonSchemaBody) {
|
||||||
// only raw for now
|
setTimeout(() => {
|
||||||
// the unknown formats are ones that are allowed in OAS, but not JSON schema
|
return this.checkValueAgainstSchema(mismatchProperty,
|
||||||
let ajv,
|
transactionPathPrefix,
|
||||||
validate,
|
null, // no param name for the request body
|
||||||
res = true;
|
requestBody.raw,
|
||||||
|
schemaPathPrefix + '.requestBody.content[application/json].schema',
|
||||||
try {
|
deref.resolveRefs(jsonSchemaBody, 'request', components, schemaResolutionCache,
|
||||||
ajv = new Ajv({ unknownFormats: ['int32', 'int64'], allErrors: true });
|
PROCESSING_TYPE.VALIDATION),
|
||||||
validate = ajv.compile(deref.resolveRefs(jsonSchemaBody, 'request', components, schemaResolutionCache));
|
components,
|
||||||
res = validate(JSON.parse(requestBody.raw));
|
_.extend({}, options, { shortValidationErrors: true }),
|
||||||
}
|
callback
|
||||||
catch (e) {
|
);
|
||||||
// something went wrong validating the schema
|
}, 0);
|
||||||
// input was invalid. Don't throw mismatch
|
}
|
||||||
}
|
else {
|
||||||
if (!res) {
|
return callback(null, []);
|
||||||
mismatches.push({
|
|
||||||
property: mismatchProperty,
|
|
||||||
transactionJsonPath: transactionPathPrefix,
|
|
||||||
schemaJsonPath: schemaPathPrefix + 'requestBody.content.application.json.schema',
|
|
||||||
reasonCode: 'INVALID_BODY',
|
|
||||||
reason: 'The request body didn\'t match the specified schema'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Not validating parts of the body for now
|
|
||||||
// _.each(validate.errors, (error) => {
|
|
||||||
// // error.keyword can be https://ajv.js.org/keywords.html
|
|
||||||
// mismatches.push({
|
|
||||||
// property: 'REQUEST_BODY',
|
|
||||||
// transactionJsonPath: transactionPathPrefix + error.dataPath,
|
|
||||||
// schemaJsonPath: schemaPathPrefix + 'requestBody.content.application.json.schema.' + error.schemaPath,
|
|
||||||
// reasonCode: error.keyword.toUpperCase(),
|
|
||||||
// reason: error.message
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
return callback(null, mismatches);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(null, []);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
checkResponseBody: function (schemaResponse, body, transactionPathPrefix, schemaPathPrefix,
|
checkResponseBody: function (schemaResponse, body, transactionPathPrefix, schemaPathPrefix,
|
||||||
@@ -2489,10 +2533,11 @@ module.exports = {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
return this.checkValueAgainstSchema(mismatchProperty,
|
return this.checkValueAgainstSchema(mismatchProperty,
|
||||||
transactionPathPrefix,
|
transactionPathPrefix,
|
||||||
null, // no param name for the request body
|
null, // no param name for the response body
|
||||||
body,
|
body,
|
||||||
schemaPathPrefix + '.content[application/json].schema',
|
schemaPathPrefix + '.content[application/json].schema',
|
||||||
deref.resolveRefs(schemaContent, 'response', components, schemaResolutionCache),
|
deref.resolveRefs(schemaContent, 'response', components, schemaResolutionCache,
|
||||||
|
PROCESSING_TYPE.VALIDATION),
|
||||||
components,
|
components,
|
||||||
_.extend({}, options, { shortValidationErrors: true }),
|
_.extend({}, options, { shortValidationErrors: true }),
|
||||||
callback
|
callback
|
||||||
@@ -2526,13 +2571,13 @@ module.exports = {
|
|||||||
async.parallel({
|
async.parallel({
|
||||||
headers: (cb) => {
|
headers: (cb) => {
|
||||||
this.checkResponseHeaders(thisSchemaResponse, response.header,
|
this.checkResponseHeaders(thisSchemaResponse, response.header,
|
||||||
transactionPathPrefix + '[' + response.id + ']header',
|
transactionPathPrefix + '[' + response.id + '].header',
|
||||||
schemaPathPrefix + '.responses.' + responsePathPrefix, components, options, schemaResolutionCache, cb);
|
schemaPathPrefix + '.responses.' + responsePathPrefix, components, options, schemaResolutionCache, cb);
|
||||||
},
|
},
|
||||||
body: (cb) => {
|
body: (cb) => {
|
||||||
// assume it's JSON at this point
|
// assume it's JSON at this point
|
||||||
this.checkResponseBody(thisSchemaResponse, response.body,
|
this.checkResponseBody(thisSchemaResponse, response.body,
|
||||||
transactionPathPrefix + '[' + response.id + ']body',
|
transactionPathPrefix + '[' + response.id + '].body',
|
||||||
schemaPathPrefix + '.responses.' + responsePathPrefix, components, options, schemaResolutionCache, cb);
|
schemaPathPrefix + '.responses.' + responsePathPrefix, components, options, schemaResolutionCache, cb);
|
||||||
}
|
}
|
||||||
}, (err, result) => {
|
}, (err, result) => {
|
||||||
@@ -2658,4 +2703,3 @@ module.exports = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ class SchemaPack {
|
|||||||
);
|
);
|
||||||
// hardcoding this option - not exposed to users yet
|
// hardcoding this option - not exposed to users yet
|
||||||
this.computedOptions.schemaFaker = true;
|
this.computedOptions.schemaFaker = true;
|
||||||
this.metaData = null;
|
let indentCharacter = this.computedOptions.indentCharacter;
|
||||||
|
this.computedOptions.indentCharacter = indentCharacter === 'tab' ? '\t' : ' ';
|
||||||
|
|
||||||
this.validate();
|
this.validate();
|
||||||
}
|
}
|
||||||
@@ -515,8 +516,8 @@ class SchemaPack {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getOptions() {
|
static getOptions(mode, criteria) {
|
||||||
return getOptions();
|
return getOptions(mode, criteria);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
lib/utils.js
16
lib/utils.js
@@ -1,3 +1,5 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
// this will have non-OAS-related utils
|
// this will have non-OAS-related utils
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -10,6 +12,11 @@ module.exports = {
|
|||||||
// set the default value to that option if the user has not defined
|
// set the default value to that option if the user has not defined
|
||||||
if (userOptions[id] === undefined) {
|
if (userOptions[id] === undefined) {
|
||||||
retVal[id] = defaultOptions[id].default;
|
retVal[id] = defaultOptions[id].default;
|
||||||
|
|
||||||
|
// ignore case-sensitivity for enum option with type string
|
||||||
|
if (defaultOptions[id].type === 'enum' && _.isString(retVal[id])) {
|
||||||
|
retVal[id] = _.toLower(defaultOptions[id].default);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,12 +31,19 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'enum':
|
case 'enum':
|
||||||
if (defaultOptions[id].availableOptions.includes(userOptions[id])) {
|
// ignore case-sensitivity for string options
|
||||||
|
if ((defaultOptions[id].availableOptions.includes(userOptions[id])) ||
|
||||||
|
(_.isString(userOptions[id]) &&
|
||||||
|
_.map(defaultOptions[id].availableOptions, _.toLower).includes(_.toLower(userOptions[id])))) {
|
||||||
retVal[id] = userOptions[id];
|
retVal[id] = userOptions[id];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
retVal[id] = defaultOptions[id].default;
|
retVal[id] = defaultOptions[id].default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore case-sensitivity for string options
|
||||||
|
_.isString(retVal[id]) && (retVal[id] = _.toLower(retVal[id]));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'array':
|
case 'array':
|
||||||
// user input needs to be parsed
|
// user input needs to be parsed
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openapi-to-postmanv2",
|
"name": "openapi-to-postmanv2",
|
||||||
"version": "1.1.12",
|
"version": "1.1.13",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openapi-to-postmanv2",
|
"name": "openapi-to-postmanv2",
|
||||||
"version": "1.1.12",
|
"version": "1.1.13",
|
||||||
"description": "Convert a given OpenAPI specification to Postman Collection v2.0",
|
"description": "Convert a given OpenAPI specification to Postman Collection v2.0",
|
||||||
"homepage": "https://github.com/postmanlabs/openapi-to-postman",
|
"homepage": "https://github.com/postmanlabs/openapi-to-postman",
|
||||||
"bugs": "https://github.com/postmanlabs/openapi-to-postman/issues",
|
"bugs": "https://github.com/postmanlabs/openapi-to-postman/issues",
|
||||||
|
|||||||
152
test/data/valid_openapi/issue#160.json
Normal file
152
test/data/valid_openapi/issue#160.json
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"info": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "#160",
|
||||||
|
"license": {
|
||||||
|
"name": "MIT"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://petstore.swagger.io/v1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/pets": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://petstore.swagger.io:{port}/{basePath}",
|
||||||
|
"variables": {
|
||||||
|
"port": {
|
||||||
|
"enum": [
|
||||||
|
"8443",
|
||||||
|
"443"
|
||||||
|
],
|
||||||
|
"default": "8443"
|
||||||
|
},
|
||||||
|
"basePath": {
|
||||||
|
"default": "v2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"summary": "List all pets",
|
||||||
|
"operationId": "listPets",
|
||||||
|
"tags": [
|
||||||
|
"pets"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"description": "How many items to return at one time (max 100)",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A paged array of pets",
|
||||||
|
"headers": {
|
||||||
|
"x-next": {
|
||||||
|
"description": "A link to the next page of responses",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Pets"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"summary": "Create a pet",
|
||||||
|
"operationId": "createPets",
|
||||||
|
"tags": [
|
||||||
|
"pets"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Null response"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"Pet": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Pets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Pet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Error": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"code",
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
113
test/data/valid_openapi/path-refs-error.yaml
Normal file
113
test/data/valid_openapi/path-refs-error.yaml
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
version: 1.0.0
|
||||||
|
title: Swagger Petstore
|
||||||
|
license:
|
||||||
|
name: MIT
|
||||||
|
servers:
|
||||||
|
- url: http://petstore.swagger.io/v1
|
||||||
|
paths:
|
||||||
|
/pets:
|
||||||
|
get:
|
||||||
|
summary: List all pets
|
||||||
|
operationId: listPets
|
||||||
|
tags:
|
||||||
|
- pets
|
||||||
|
parameters:
|
||||||
|
- name: limit
|
||||||
|
in: query
|
||||||
|
description: How many items to return at one time (max 100)
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: A paged array of pets
|
||||||
|
headers:
|
||||||
|
x-next:
|
||||||
|
description: A link to the next page of responses
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
newprop:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
tag:
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
description: unexpected error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
required:
|
||||||
|
- code
|
||||||
|
- message
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
post:
|
||||||
|
summary: Create a pet
|
||||||
|
operationId: createPets
|
||||||
|
tags:
|
||||||
|
- pets
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Null response
|
||||||
|
default:
|
||||||
|
description: unexpected error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
oneOf:
|
||||||
|
- $ref: "#/paths/~1pets/get/responses/200/content/applicati\
|
||||||
|
on~1json/schema/properties/newprop"
|
||||||
|
- $ref: "#/paths/~1pets/get/responses/default/content/appli\
|
||||||
|
cation~1json/schema"
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Pet:
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
tag:
|
||||||
|
type: string
|
||||||
|
Pets:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Pet"
|
||||||
|
Error:
|
||||||
|
required:
|
||||||
|
- code
|
||||||
|
- message
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
@@ -22,7 +22,19 @@
|
|||||||
"summary": "Should use the other domain",
|
"summary": "Should use the other domain",
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "https://other-api.example.com"
|
"url": "http://petstore.swagger.io:{port}/{basePath}",
|
||||||
|
"variables": {
|
||||||
|
"port": {
|
||||||
|
"enum": [
|
||||||
|
"8443",
|
||||||
|
"443"
|
||||||
|
],
|
||||||
|
"default": "8443"
|
||||||
|
},
|
||||||
|
"basePath": {
|
||||||
|
"default": "v2"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
180
test/data/valid_openapi/too-many-refs.json
Normal file
180
test/data/valid_openapi/too-many-refs.json
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"info": {
|
||||||
|
"description": "Too Many Refs",
|
||||||
|
"version": "v1",
|
||||||
|
"title": "Too Many Refs",
|
||||||
|
"termsOfService": "http://www.example.com/termsOfService",
|
||||||
|
"contact": {
|
||||||
|
"name": "Sample",
|
||||||
|
"url": "http://sample.com/",
|
||||||
|
"email": "sample@sample.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "Folder tree"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/path": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Some path"
|
||||||
|
],
|
||||||
|
"summary": "Too many refs path",
|
||||||
|
"description": "Returns a list of folders in a nested, tree structure.",
|
||||||
|
"operationId": "listFolderTree",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/b"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/path2": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Some path"
|
||||||
|
],
|
||||||
|
"summary": "Too many refs path",
|
||||||
|
"description": "Returns a list of folders in a nested, tree structure.",
|
||||||
|
"operationId": "listFolderTree",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/k"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "https://{host}/sample/api",
|
||||||
|
"variables": {
|
||||||
|
"host": {
|
||||||
|
"default": "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"b": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"c": {
|
||||||
|
"$ref": "#/components/schemas/c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"c": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"d": {
|
||||||
|
"$ref": "#/components/schemas/d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"d": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"e": {
|
||||||
|
"$ref": "#/components/schemas/e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"e": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"f": {
|
||||||
|
"$ref": "#/components/schemas/f"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"f": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"g": {
|
||||||
|
"$ref": "#/components/schemas/g"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"g": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"h": {
|
||||||
|
"$ref": "#/components/schemas/h"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"h": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"i": {
|
||||||
|
"$ref": "#/components/schemas/i"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"i": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"j": {
|
||||||
|
"$ref": "#/components/schemas/j"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"j": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"k": {
|
||||||
|
"$ref": "#/components/schemas/k"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"k": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"l": {
|
||||||
|
"$ref": "#/components/schemas/a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"_postman_id": "7a1d1b7f-f6c3-4ce1-8c1f-1e93fc4a470d",
|
||||||
|
"name": "lets see",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
|
},
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"id": "req",
|
||||||
|
"name": "Sample endpoint: Returns details about a particular user",
|
||||||
|
"request": {
|
||||||
|
"auth": {
|
||||||
|
"type": "noauth"
|
||||||
|
},
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/user?id=1",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"query": [
|
||||||
|
{
|
||||||
|
"key": "id",
|
||||||
|
"value": "1",
|
||||||
|
"description": "(Required) ID of the user"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"data\": [\n {\n \"id\": \"5e5792b234d88e12b8511b92\",\n \"accountNumber\": \"1YNykgIi3T2NDeElON0IqcPOpPI\",\n \"entityName\": \"Farmer Freddy's Veg\",\n \"entityPhone\": \"+4420832132132\",\n \"incType\": \"sole\",\n \"companyNumber\": 10000,\n \"needThisNot\": \"hello\",\n \"website\": \"https://farmer-freddy.null\",\n \"turnover\": 10000,\n \"description\": \"def\",\n \"status\": \"tradingAccepted\",\n \"offers\": [\n \"organic-vegetables\",\n \"organic-fruits\",\n \"101\"\n ],\n \"wants\": [\n \"carpentry\",\n \"beer\",\n \"beer\"\n ],\n \"isFavorite\": true\n }\n ],\n \"meta\": {\n \"notNeeded\": 1,\n \"numberOfResults\": 1,\n \"totalPages\": 1\n }\n}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": [
|
||||||
|
{
|
||||||
|
"id": "res",
|
||||||
|
"name": "OK",
|
||||||
|
"originalRequest": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/user?id=1",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"query": [
|
||||||
|
{
|
||||||
|
"key": "id",
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "OK",
|
||||||
|
"code": 200,
|
||||||
|
"_postman_previewlanguage": "json",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cookie": [],
|
||||||
|
"body": "{\n \"data\": [\n {\n \"id\": \"5e5792b234d88e12b8511b92\",\n \"accountNumber\": \"1YNykgIi3T2NDeElON0IqcPOpPI\",\n \"entityName\": \"Farmer Freddy's Veg\",\n \"entityPhone\": \"+4420832132132\",\n \"incType\": \"sole\",\n \"companyNumber\": \"none\",\n \"website\": \"https://farmer-freddy.null\",\n \"turnover\": 10000,\n \"description\": \"High quality carpentry at a reasonable price.\",\n \"status\": \"wrongEnum\",\n \"offers\": [\n \"organic-vegetables\",\n \"organic-fruits\"\n ],\n \"wants\": [\n \"carpentry\",\n \"beer\"\n ],\n \"isFavorite\": true\n }\n ],\n \"meta\": {\n \"numberOfResults\": 1,\n \"totalPages\": 1\n }\n}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variable": [
|
||||||
|
{
|
||||||
|
"id": "baseUrl",
|
||||||
|
"key": "baseUrl",
|
||||||
|
"value": "http://localhost:3000",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"protocolProfileBehavior": {}
|
||||||
|
}
|
||||||
127
test/data/validationData/detailedValidationExampleSchema.yaml
Normal file
127
test/data/validationData/detailedValidationExampleSchema.yaml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
version: 1
|
||||||
|
title: IMPORT-202
|
||||||
|
servers:
|
||||||
|
- url: 'http://localhost:3000'
|
||||||
|
paths:
|
||||||
|
/user:
|
||||||
|
get:
|
||||||
|
summary: 'Sample endpoint: Returns details about a particular user'
|
||||||
|
operationId: listUser
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: query
|
||||||
|
description: ID of the user
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Entity'
|
||||||
|
meta:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
numberOfResults:
|
||||||
|
type: number
|
||||||
|
format: int32
|
||||||
|
totalPages:
|
||||||
|
type: number
|
||||||
|
format: int32
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Entity'
|
||||||
|
meta:
|
||||||
|
type: object
|
||||||
|
maxProperties: 1
|
||||||
|
additionalProperties: false
|
||||||
|
propertyNames:
|
||||||
|
pattern: '^_'
|
||||||
|
properties:
|
||||||
|
numberOfResults:
|
||||||
|
type: number
|
||||||
|
format: int32
|
||||||
|
totalPages:
|
||||||
|
type: number
|
||||||
|
format: int32
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Entity:
|
||||||
|
type: object
|
||||||
|
title: Entity
|
||||||
|
description: A single and unique entity linked to a user
|
||||||
|
minProperties: 50
|
||||||
|
required: [id, needThis]
|
||||||
|
dependencies:
|
||||||
|
id: [needThis, accountNumber]
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
maxLength: 5
|
||||||
|
accountNumber:
|
||||||
|
type: string
|
||||||
|
minLength: 50
|
||||||
|
entityName:
|
||||||
|
type: string
|
||||||
|
format: ipv4
|
||||||
|
entityPhone:
|
||||||
|
type: string
|
||||||
|
incType:
|
||||||
|
type: string
|
||||||
|
const: 'Postman'
|
||||||
|
companyNumber:
|
||||||
|
type: number
|
||||||
|
exclusiveMinimum: 10000
|
||||||
|
website:
|
||||||
|
type: number
|
||||||
|
turnover:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
multipleOf: 7
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
pattern: '[abc]+'
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- pending
|
||||||
|
- accepted
|
||||||
|
- rejected
|
||||||
|
- tradingPending
|
||||||
|
- tradingAccepted
|
||||||
|
- tradingRejected
|
||||||
|
offers:
|
||||||
|
type: array
|
||||||
|
items: [
|
||||||
|
type: string,
|
||||||
|
type: string
|
||||||
|
]
|
||||||
|
additionalItems: false
|
||||||
|
wants:
|
||||||
|
type: array
|
||||||
|
uniqueItems: true
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
isFavorite:
|
||||||
|
type: boolean
|
||||||
|
needThis:
|
||||||
|
type: string
|
||||||
@@ -5,70 +5,70 @@ const optionIds = [
|
|||||||
'collapseFolders',
|
'collapseFolders',
|
||||||
'requestParametersResolution',
|
'requestParametersResolution',
|
||||||
'exampleParametersResolution',
|
'exampleParametersResolution',
|
||||||
'folderStrategy',
|
|
||||||
'indentCharacter',
|
'indentCharacter',
|
||||||
'requestNameSource',
|
'requestNameSource',
|
||||||
|
'shortValidationErrors',
|
||||||
'validationPropertiesToIgnore',
|
'validationPropertiesToIgnore',
|
||||||
'showMissingInSchemaErrors'
|
'showMissingInSchemaErrors',
|
||||||
|
'detailedBlobValidation'
|
||||||
],
|
],
|
||||||
expectedOptions = {
|
expectedOptions = {
|
||||||
collapseFolders: {
|
collapseFolders: {
|
||||||
name: 'Toggle for collapsing folder for long routes',
|
name: 'Collapse redundant folders',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: true,
|
default: true,
|
||||||
description: 'Determines whether the importer should attempt to collapse redundant folders into one.' +
|
description: 'Importing will collapse all folders that have only one child element and lack ' +
|
||||||
'Folders are redundant if they have only one child element, and don\'t' +
|
'persistent folder-level data.'
|
||||||
'have any folder-level data to persist.'
|
|
||||||
},
|
},
|
||||||
requestParametersResolution: {
|
requestParametersResolution: {
|
||||||
name: 'Set root request parameters type',
|
name: 'Request parameter generation',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: 'schema',
|
default: 'Schema',
|
||||||
availableOptions: ['example', 'schema'],
|
availableOptions: ['Example', 'Schema'],
|
||||||
description: 'Determines how request parameters (query parameters, path parameters, headers,' +
|
description: 'Select whether to generate the request parameters based on the' +
|
||||||
'or the request body) should be generated. Setting this to schema will cause the importer to' +
|
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
|
||||||
'use the parameter\'s schema as an indicator; `example` will cause the example (if provided)' +
|
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
|
||||||
'to be picked up.'
|
' in the schema.'
|
||||||
},
|
},
|
||||||
exampleParametersResolution: {
|
exampleParametersResolution: {
|
||||||
name: 'Set example request and response parameters type',
|
name: 'Response parameter generation',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: 'example',
|
default: 'Example',
|
||||||
availableOptions: ['example', 'schema'],
|
availableOptions: ['Example', 'Schema'],
|
||||||
description: 'Determines how response parameters (query parameters, path parameters, headers,' +
|
description: 'Select whether to generate the response parameters based on the' +
|
||||||
'or the request body) should be generated. Setting this to schema will cause the importer to' +
|
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
|
||||||
'use the parameter\'s schema as an indicator; `example` will cause the example (if provided)' +
|
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
|
||||||
'to be picked up.'
|
' in the schema.'
|
||||||
},
|
|
||||||
folderStrategy: {
|
|
||||||
name: 'Set folder strategy',
|
|
||||||
type: 'enum',
|
|
||||||
default: 'paths',
|
|
||||||
availableOptions: ['paths', 'tags'],
|
|
||||||
description: 'Determines whether the importer should attempt to create the folders according' +
|
|
||||||
'to paths or tags which are given in the spec.'
|
|
||||||
},
|
},
|
||||||
indentCharacter: {
|
indentCharacter: {
|
||||||
name: 'Set indent character',
|
name: 'Set indent character',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: ' ',
|
default: 'Space',
|
||||||
availableOptions: [' ', '\t'],
|
availableOptions: ['Space', 'Tab'],
|
||||||
description: 'Option for setting indentation character'
|
description: 'Option for setting indentation character'
|
||||||
},
|
},
|
||||||
requestNameSource: {
|
requestNameSource: {
|
||||||
name: 'Set request name source',
|
name: 'Naming requests',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
default: 'fallback',
|
default: 'Fallback',
|
||||||
availableOptions: ['url', 'uKnown', 'fallback'],
|
availableOptions: ['Url', 'Fallback'],
|
||||||
description: 'Option for setting source for a request name'
|
description: 'Determines how the requests inside the generated collection will be named.' +
|
||||||
|
' If “Fallback” is selected, the request will be named after one of the following schema' +
|
||||||
|
' values: `description`, `operationid`, `url`.'
|
||||||
|
},
|
||||||
|
shortValidationErrors: {
|
||||||
|
name: 'Short error messages during request <> schema validation',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'Whether detailed error messages are required for request <> schema validation operations.'
|
||||||
},
|
},
|
||||||
validationPropertiesToIgnore: {
|
validationPropertiesToIgnore: {
|
||||||
name: 'Properties to ignore during validation',
|
name: 'Properties to ignore during validation',
|
||||||
type: 'array',
|
type: 'array',
|
||||||
default: [],
|
default: [],
|
||||||
description: 'Specific properties (parts of a request/response pair) to ignore during validation.' +
|
description: 'Specific properties (parts of a request/response pair) to ignore during validation.' +
|
||||||
' Must be sent as an array of strings. Valid inputs in the array: PATHVARIABLE, QUERYPARAM,' +
|
' Must be sent as an array of strings. Valid inputs in the array: PATHVARIABLE, QUERYPARAM,' +
|
||||||
' HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY'
|
' HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY'
|
||||||
},
|
},
|
||||||
showMissingInSchemaErrors: {
|
showMissingInSchemaErrors: {
|
||||||
name: 'Whether MISSING_IN_SCHEMA mismatches should be returned',
|
name: 'Whether MISSING_IN_SCHEMA mismatches should be returned',
|
||||||
@@ -76,6 +76,14 @@ const optionIds = [
|
|||||||
default: false,
|
default: false,
|
||||||
description: 'MISSING_IN_SCHEMA indicates that an extra parameter was included in the request. For most ' +
|
description: 'MISSING_IN_SCHEMA indicates that an extra parameter was included in the request. For most ' +
|
||||||
'use cases, this need not be considered an error.'
|
'use cases, this need not be considered an error.'
|
||||||
|
},
|
||||||
|
detailedBlobValidation: {
|
||||||
|
name: 'Show detailed body validation messages',
|
||||||
|
id: 'detailedBlobValidation',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'Determines whether to show detailed mismatch information for application/json content ' +
|
||||||
|
'in the request/response body.'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -111,5 +119,18 @@ describe('getOptions', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('must return all valid options based on criteria', function () {
|
||||||
|
getOptions({ usage: ['CONVERSION'] }).forEach((option) => {
|
||||||
|
expect(option.id).to.be.oneOf(optionIds);
|
||||||
|
expect(option.usage).to.include('CONVERSION');
|
||||||
|
});
|
||||||
|
|
||||||
|
getOptions({ external: true, usage: ['VALIDATION'] }).forEach((option) => {
|
||||||
|
expect(option.id).to.be.oneOf(optionIds);
|
||||||
|
expect(option.external).to.eql(true);
|
||||||
|
expect(option.usage).to.include('VALIDATION');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ describe('CONVERT FUNCTION TESTS ', function() {
|
|||||||
var testSpec = path.join(__dirname, VALID_OPENAPI_PATH + '/test.json'),
|
var testSpec = path.join(__dirname, VALID_OPENAPI_PATH + '/test.json'),
|
||||||
testSpec1 = path.join(__dirname, VALID_OPENAPI_PATH + '/test1.json'),
|
testSpec1 = path.join(__dirname, VALID_OPENAPI_PATH + '/test1.json'),
|
||||||
issue133 = path.join(__dirname, VALID_OPENAPI_PATH + '/issue#133.json'),
|
issue133 = path.join(__dirname, VALID_OPENAPI_PATH + '/issue#133.json'),
|
||||||
|
issue160 = path.join(__dirname, VALID_OPENAPI_PATH, '/issue#160.json'),
|
||||||
unique_items_schema = path.join(__dirname, VALID_OPENAPI_PATH + '/unique_items_schema.json'),
|
unique_items_schema = path.join(__dirname, VALID_OPENAPI_PATH + '/unique_items_schema.json'),
|
||||||
serverOverRidingSpec = path.join(__dirname, VALID_OPENAPI_PATH + '/server_overriding.json'),
|
serverOverRidingSpec = path.join(__dirname, VALID_OPENAPI_PATH + '/server_overriding.json'),
|
||||||
infoHavingContactOnlySpec = path.join(__dirname, VALID_OPENAPI_PATH + '/info_having_contact_only.json'),
|
infoHavingContactOnlySpec = path.join(__dirname, VALID_OPENAPI_PATH + '/info_having_contact_only.json'),
|
||||||
@@ -30,7 +31,44 @@ describe('CONVERT FUNCTION TESTS ', function() {
|
|||||||
requiredInParams = path.join(__dirname, VALID_OPENAPI_PATH, '/required_in_parameters.json'),
|
requiredInParams = path.join(__dirname, VALID_OPENAPI_PATH, '/required_in_parameters.json'),
|
||||||
multipleRefs = path.join(__dirname, VALID_OPENAPI_PATH, '/multiple_refs.json'),
|
multipleRefs = path.join(__dirname, VALID_OPENAPI_PATH, '/multiple_refs.json'),
|
||||||
issue150 = path.join(__dirname, VALID_OPENAPI_PATH + '/issue#150.yml'),
|
issue150 = path.join(__dirname, VALID_OPENAPI_PATH + '/issue#150.yml'),
|
||||||
issue173 = path.join(__dirname, VALID_OPENAPI_PATH, '/issue#173.yml');
|
issue173 = path.join(__dirname, VALID_OPENAPI_PATH, '/issue#173.yml'),
|
||||||
|
issue152 = path.join(__dirname, VALID_OPENAPI_PATH, '/path-refs-error.yaml'),
|
||||||
|
tooManyRefs = path.join(__dirname, VALID_OPENAPI_PATH, '/too-many-refs.json');
|
||||||
|
|
||||||
|
it('Should generate collection conforming to schema for and fail if not valid ' +
|
||||||
|
tooManyRefs, function(done) {
|
||||||
|
var openapi = fs.readFileSync(tooManyRefs, 'utf8'),
|
||||||
|
body;
|
||||||
|
Converter.convert({ type: 'string', data: openapi }, { schemaFaker: true }, (err, conversionResult) => {
|
||||||
|
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(conversionResult.result).to.equal(true);
|
||||||
|
expect(conversionResult.output.length).to.equal(1);
|
||||||
|
expect(conversionResult.output[0].type).to.equal('collection');
|
||||||
|
expect(conversionResult.output[0].data).to.have.property('info');
|
||||||
|
expect(conversionResult.output[0].data).to.have.property('item');
|
||||||
|
body = conversionResult.output[0].data.item[1].response[0].body;
|
||||||
|
expect(body).to.not.contain('<Error: Too many levels of nesting to fake this schema>');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should generate collection conforming to schema for and fail if not valid ' +
|
||||||
|
issue152, function(done) {
|
||||||
|
var openapi = fs.readFileSync(issue152, 'utf8'),
|
||||||
|
refNotFound = 'reference #/paths/~1pets/get/responses/200/content/application~1json/schema/properties/newprop' +
|
||||||
|
' not found in the OpenAPI spec';
|
||||||
|
Converter.convert({ type: 'string', data: openapi }, { schemaFaker: true }, (err, conversionResult) => {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(conversionResult.result).to.equal(true);
|
||||||
|
expect(conversionResult.output.length).to.equal(1);
|
||||||
|
expect(conversionResult.output[0].type).to.equal('collection');
|
||||||
|
expect(conversionResult.output[0].data).to.have.property('info');
|
||||||
|
expect(conversionResult.output[0].data).to.have.property('item');
|
||||||
|
expect(conversionResult.output[0].data.item[0].item[1].response[1].body).to.not.contain(refNotFound);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Should generate collection conforming to schema for and fail if not valid ' +
|
it('Should generate collection conforming to schema for and fail if not valid ' +
|
||||||
testSpec, function(done) {
|
testSpec, function(done) {
|
||||||
@@ -79,6 +117,21 @@ describe('CONVERT FUNCTION TESTS ', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('#GITHUB-160 should generate correct display url for path containing servers' +
|
||||||
|
issue160, function(done) {
|
||||||
|
var openapi = fs.readFileSync(issue160, 'utf8');
|
||||||
|
Converter.convert({ type: 'string', data: openapi }, {}, (err, conversionResult) => {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(conversionResult.result).to.equal(true);
|
||||||
|
expect(conversionResult.output.length).to.equal(1);
|
||||||
|
expect(conversionResult.output[0].type).to.equal('collection');
|
||||||
|
expect(conversionResult.output[0].data).to.have.property('info');
|
||||||
|
expect(conversionResult.output[0].data).to.have.property('item');
|
||||||
|
expect(conversionResult.output[0].data.item[0].item[0].request.url.host[0]).to.equal('{{petsUrl}}');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Should not get stuck while resolving circular references' +
|
it('Should not get stuck while resolving circular references' +
|
||||||
unique_items_schema, function(done) {
|
unique_items_schema, function(done) {
|
||||||
Converter.convert({ type: 'file', data:
|
Converter.convert({ type: 'file', data:
|
||||||
@@ -163,12 +216,13 @@ describe('CONVERT FUNCTION TESTS ', function() {
|
|||||||
let request = conversionResult.output[0].data.item[1].request,
|
let request = conversionResult.output[0].data.item[1].request,
|
||||||
protocol = request.url.protocol,
|
protocol = request.url.protocol,
|
||||||
host = request.url.host.join('.'),
|
host = request.url.host.join('.'),
|
||||||
|
port = request.url.port,
|
||||||
path = request.url.path.join('/'),
|
path = request.url.path.join('/'),
|
||||||
endPoint = protocol + '://' + host + '/' + path,
|
endPoint = protocol + '://' + host + ':' + port + '/' + path,
|
||||||
host1 = conversionResult.output[0].data.variable[0].value,
|
host1 = conversionResult.output[0].data.variable[0].value,
|
||||||
path1 = conversionResult.output[0].data.item[0].request.url.path.join('/'),
|
path1 = conversionResult.output[0].data.item[0].request.url.path.join('/'),
|
||||||
endPoint1 = host1 + '/' + path1;
|
endPoint1 = host1 + '/' + path1;
|
||||||
expect(endPoint).to.equal('https://other-api.example.com/secondary-domain/fails');
|
expect(endPoint).to.equal('http://petstore.swagger.io:{{port}}/:basePath/secondary-domain/fails');
|
||||||
expect(endPoint1).to.equal('https://api.example.com/primary-domain/works');
|
expect(endPoint1).to.equal('https://api.example.com/primary-domain/works');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ describe('DEREF FUNCTION TESTS ', function() {
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
schemaWithTypeArray = {
|
||||||
|
$ref: '#/components/schemas/schemaTypeArray'
|
||||||
|
},
|
||||||
componentsAndPaths = {
|
componentsAndPaths = {
|
||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
@@ -69,6 +72,14 @@ describe('DEREF FUNCTION TESTS ', function() {
|
|||||||
format: 'email'
|
format: 'email'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
schemaTypeArray: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
minItems: 5,
|
||||||
|
maxItems: 55
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +88,9 @@ describe('DEREF FUNCTION TESTS ', function() {
|
|||||||
output = deref.resolveRefs(schema, parameterSource, componentsAndPaths),
|
output = deref.resolveRefs(schema, parameterSource, componentsAndPaths),
|
||||||
output_withdot = deref.resolveRefs(schemaWithDotInKey, parameterSource, componentsAndPaths),
|
output_withdot = deref.resolveRefs(schemaWithDotInKey, parameterSource, componentsAndPaths),
|
||||||
output_customFormat = deref.resolveRefs(schemaWithCustomFormat, parameterSource, componentsAndPaths),
|
output_customFormat = deref.resolveRefs(schemaWithCustomFormat, parameterSource, componentsAndPaths),
|
||||||
output_withAllOf = deref.resolveRefs(schemaWithAllOf, parameterSource, componentsAndPaths);
|
output_withAllOf = deref.resolveRefs(schemaWithAllOf, parameterSource, componentsAndPaths),
|
||||||
|
output_validationTypeArray = deref.resolveRefs(schemaWithTypeArray, parameterSource, componentsAndPaths,
|
||||||
|
{}, 'VALIDATION');
|
||||||
|
|
||||||
|
|
||||||
expect(output).to.deep.include({ type: 'object',
|
expect(output).to.deep.include({ type: 'object',
|
||||||
@@ -100,6 +113,17 @@ describe('DEREF FUNCTION TESTS ', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// deref.resolveRef() should not change minItems and maxItems for VALIDATION
|
||||||
|
expect(output_validationTypeArray).to.deep.include({
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
default: '<string>'
|
||||||
|
},
|
||||||
|
minItems: 5,
|
||||||
|
maxItems: 55
|
||||||
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2070,8 +2070,8 @@ describe('SCHEMA UTILITY FUNCTION TESTS ', function () {
|
|||||||
resultObj = SchemaUtils.sanitizeUrlPathParams('/anotherpath/{{path}}/{{new-path-variable}}.{{onemore}}',
|
resultObj = SchemaUtils.sanitizeUrlPathParams('/anotherpath/{{path}}/{{new-path-variable}}.{{onemore}}',
|
||||||
pathParams);
|
pathParams);
|
||||||
|
|
||||||
expect(resultObj).to.have.property('reqUrl');
|
expect(resultObj).to.have.property('url');
|
||||||
expect(resultObj.reqUrl).to.equal('/anotherpath/:path/{{new-path-variable}}.{{onemore}}');
|
expect(resultObj.url).to.equal('/anotherpath/:path/{{new-path-variable}}.{{onemore}}');
|
||||||
expect(resultObj).to.have.property('pathVars');
|
expect(resultObj).to.have.property('pathVars');
|
||||||
expect(resultObj).to.have.property('collectionVars');
|
expect(resultObj).to.have.property('collectionVars');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user