import expect from "expect" import validateHelper, { expectNoErrors } from "../validate-helper.js" describe(`validation plugin - semantic - 2and3 schemas`, () => { describe(`array schemas must have an Object value in "items"`, () => { it("should return an error for an array items value in Swagger 2", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { "parameters": [ { name: "myParam", in: "query", type: "array", items: [{ type: "object" }] } ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["paths", "/pets", "get", "parameters", "0", "items"]) expect(firstError.message).toEqual("`items` must be an object") }) }) it("should return an error for an array items value in OpenAPI 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "myParam", in: "query", schema: { type: "array", items: [{ type: "object" }] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["paths", "/pets", "get", "parameters", "0", "schema", "items"]) expect(firstError.message).toEqual("`items` must be an object") }) }) it("should return an error for a missing items value for an array schema in Swagger 2", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { "parameters": [ { name: "myParam", in: "query", type: "array" } ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.message).toEqual("Schemas with 'type: array', require a sibling 'items: ' field") expect(firstError.path).toEqual(["paths", "/pets", "get", "parameters", "0"]) }) }) it("should return an error for a missing items value for an array schema in OpenAPI 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "myParam", in: "query", schema: { type: "array" } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["paths", "/pets", "get", "parameters", "0", "schema"]) expect(firstError.message).toEqual("Schemas with 'type: array', require a sibling 'items: ' field") }) }) it("should not return an error for a missing items value for a non-array schema in Swagger 2", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { "parameters": [ { name: "myParam", in: "query", type: "object" } ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) it("should not return an error for a missing items value for a non-array schema in OpenAPI 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "myParam", in: "query", schema: { type: "object" } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) }) describe("minimums and maximums", () => { describe("OpenAPI 2.0", () => { it("should return an error when minimum is more than maximum", () => { const spec = { swagger: "2.0", definitions: { MyNumber: { minimum: 5, maximum: 2 } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter( a => a.level == "error") // Ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.message).toMatch(/.*minimum.*lower.*maximum.*/) expect(firstError.path).toEqual(["definitions", "MyNumber", "minimum"]) }) }) it("should not return an error when minimum is less than maximum", () => { const spec = { swagger: "2.0", definitions: { MyNumber: { minimum: 1, maximum: 2 } } } return expectNoErrors(spec) }) it("should not return an error when minimum is equal to maximum", () => { const spec = { swagger: "2.0", definitions: { MyNumber: { minimum: 1, maximum: 1 } } } return expectNoErrors(spec) }) it("should return an error when minProperties is more than maxProperties", () => { const spec = { swagger: "2.0", definitions: { MyObject: { minProperties: 5, maxProperties: 2 } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter(a => a.level === "error") // ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.message).toMatch(/.*minProperties.*lower.*maxProperties.*/) expect(firstError.path).toEqual(["definitions", "MyObject", "minProperties"]) }) }) it("should not return an error when minProperties is less than maxProperties", () => { const spec = { swagger: "2.0", definitions: { MyObject: { minProperties: 1, maxProperties: 2 } } } return expectNoErrors(spec) }) it("should not return an error when minProperties is equal to maxProperties", () => { const spec = { swagger: "2.0", definitions: { MyObject: { minProperties: 1, maxProperties: 1 } } } return expectNoErrors(spec) }) it("should return an error when minLength is more than maxLength", () => { const spec = { swagger: "2.0", definitions: { MyString: { minLength: 5, maxLength: 2 } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter(a => a.level === "error") // ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.path).toEqual(["definitions", "MyString", "minLength"]) expect(firstError.message).toMatch(/.*minLength.*lower.*maxLength.*/) }) }) it("should not return an error when minLength is less than maxLength", () => { const spec = { swagger: "2.0", definitions: { MyString: { minLength: 1, maxLength: 2 } } } return expectNoErrors(spec) }) it("should not return an error when minLength is equal to maxLength", () => { const spec = { swagger: "2.0", definitions: { MyString: { minLength: 1, maxLength: 1 } } } return expectNoErrors(spec) }) it("should return an error when minItems is more than maxItems", () => { const spec = { swagger: "2.0", definitions: { MyArray: { minItems: 5, maxItems: 2 } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter(a => a.level === "error") // ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.path).toEqual(["definitions", "MyArray", "minItems"]) expect(firstError.message).toMatch(/.*minItems.*lower.*maxItems.*/) }) }) it("should not return an error when minItems is less than maxItems", () => { const spec = { swagger: "2.0", definitions: { MyArray: { minItems: 1, maxItems: 2 } } } return expectNoErrors(spec) }) it("should not return an error when minItems is equal to maxItems", () => { const spec = { swagger: "2.0", definitions: { MyArray: { minItems: 1, maxItems: 1 } } } return expectNoErrors(spec) }) }) describe("OpenAPI 3.0", () => { it("should return an error when minimum is more than maximum", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyNumber: { minimum: 5, maximum: 2 } } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter( a => a.level == "error") // Ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.message).toMatch(/.*minimum.*lower.*maximum.*/) expect(firstError.path).toEqual(["components", "schemas", "MyNumber", "minimum"]) }) }) it("should not return an error when minimum is less than maximum", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyNumber: { minimum: 1, maximum: 2 } } } } return expectNoErrors(spec) }) it("should not return an error when minimum is equal to maximum", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyNumber: { minimum: 1, maximum: 1 } } } } return expectNoErrors(spec) }) it("should return an error when minProperties is more than maxProperties", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyObject: { minProperties: 5, maxProperties: 2 } } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter(a => a.level === "error") // ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.message).toMatch(/.*minProperties.*lower.*maxProperties.*/) expect(firstError.path).toEqual(["components", "schemas", "MyObject", "minProperties"]) }) }) it("should not return an error when minProperties is less than maxProperties", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyObject: { minProperties: 1, maxProperties: 2 } } } } return expectNoErrors(spec) }) it("should not return an error when minProperties is equal to maxProperties", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyObject: { minProperties: 1, maxProperties: 1 } } } } return expectNoErrors(spec) }) it("should return an error when minLength is more than maxLength", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyString: { minLength: 5, maxLength: 2 } } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter(a => a.level === "error") // ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.path).toEqual(["components", "schemas", "MyString", "minLength"]) expect(firstError.message).toMatch(/.*minLength.*lower.*maxLength.*/) }) }) it("should not return an error when minLength is less than maxLength", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyString: { minLength: 1, maxLength: 2 } } } } return expectNoErrors(spec) }) it("should not return an error when minLength is equal to maxLength", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyString: { minLength: 1, maxLength: 1 } } } } return expectNoErrors(spec) }) it("should return an error when minItems is more than maxItems", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyArray: { minItems: 5, maxItems: 2 } } } } return validateHelper(spec) .then(system => { let allErrors = system.errSelectors.allErrors().toJS() allErrors = allErrors.filter(a => a.level === "error") // ignore warnings expect(allErrors.length).toEqual(1) const firstError = allErrors[0] expect(firstError.path).toEqual(["components", "schemas", "MyArray", "minItems"]) expect(firstError.message).toMatch(/.*minItems.*lower.*maxItems.*/) }) }) it("should not return an error when minItems is less than maxItems", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyArray: { minItems: 1, maxItems: 2 } } } } return expectNoErrors(spec) }) it("should not return an error when minItems is equal to maxItems", () => { const spec = { openapi: "3.0.0", components: { schemas: { MyArray: { minItems: 1, maxItems: 1 } } } } return expectNoErrors(spec) }) }) }) }) describe(`values in Enum must be instance of the defined type`, () => { // Numbers tests it("should return an error for a text value in a enum number type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "number", in: "query", schema: { type: "number", enum: [1, "text", 3] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(1) expect(allErrors[0]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 1] }) }) }) it("should return an error for a number value inside quotes in a enum number type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "number", in: "query", schema: { type: "number", enum: [1, 2, "3"] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(1) expect(allErrors[0]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 2] }) }) }) it("should not return an error when all items are number in a enum number type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "number", in: "query", schema: { type: "number", enum: [1, 2, 3] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) //Array Tests it("should return an error for a non array value in a enum array type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "arraySample", in: "query", schema: { type: "array", enum: [1, 2, 3], items: { type: "array", items: { type: "number" } } } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS().filter((err => err.source !== "")) expect(allErrors.length).toEqual(3) expect(allErrors[0]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 0] }) expect(allErrors[1]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 1] }) expect(allErrors[2]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 2] }) }) }) it("should not return a type error when all items are array in a enum array type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "arraySample", in: "query", schema: { type: "array", enum: [[1,2],[3,4]], items: { type: "number" } } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) //Object Tests it("should return an error for a non object value (array) in a enum object type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "objectSample", in: "query", schema: { type: "object", enum: [[1,3], 2, 3] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(3) expect(allErrors[0]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 0] }) expect(allErrors[1]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 1] }) expect(allErrors[2]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 2] }) }) }) it("should return an error for a null value in a enum object type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "objectSample", in: "query", schema: { type: "object", enum: [null] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors[0]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 0] }) }) }) it("should not return an error when all items are array in a enum array type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "objectSample", in: "query", schema: { type: "object", enum: [{ok: "Sample"},{}] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) //Boolean Tests it("should return an error for a non boolean value in a boolean array type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "booleanEnum", in: "query", schema: { type: "boolean", enum: [1, true, false] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors[0]).toInclude({ level: "warning", message: "enum value should conform to its schema's `type`", path: ["paths", "/pets", "get", "parameters", "0", "schema", "enum", 0] }) }) }) it("should not return an error when all items are boolean in a boolean array type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "booleanEnum", in: "query", schema: { type: "boolean", enum: [true, false] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) it("should not return an error for a null value in a enum object when nullable is true type in OpenApi 3", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { name: "objectSample", in: "query", schema: { type: "object", nullable: true, enum: [null] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) describe(`schema defaults must be present in enums`, () => { it("should return an error for an invalid Swagger 2 parameter definition", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { "parameters": [ { "name": "num", "in": "query", "type": "number", enum: [1, 2, 3], default: 0 }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["paths", "/pets", "get", "parameters", "0", "default"]) expect(firstError.message).toEqual("Default values must be present in `enum`") }) }) it("should return an error for an invalid Swagger 2 schema definition", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { responses: { 200: { schema: { $ref: "#/definitions/MySchema" } } } } } }, "definitions": { "MySchema": { "type": "number", enum: [1, 2, 3], default: 0 } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["definitions", "MySchema","default"]) expect(firstError.message).toEqual("Default values must be present in `enum`") }) }) it("should return an error for an invalid OpenAPI 3 parameter definition", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { "name": "num", "in": "query", "type": "number", schema: { enum: [1, 2, 3], default: 0 } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["paths", "/pets", "get", "parameters", "0", "schema", "default"]) expect(firstError.message).toEqual("Default values must be present in `enum`") }) }) it("should return an error for an invalid OpenAPI 3 parameter component", () => { const spec = { openapi: "3.0.0", components: { parameters: { MyParam: { "name": "num", "in": "query", "type": "number", schema: { enum: [1, 2, 3], default: 0 } } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() const firstError = allErrors[0] expect(allErrors.length).toEqual(1) expect(firstError.path).toEqual(["components", "parameters", "MyParam", "schema", "default"]) expect(firstError.message).toEqual("Default values must be present in `enum`") }) }) it("should return no errors for a Swagger 2 definition without default set", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { "parameters": [ { "name": "num", "in": "query", "type": "number", enum: [1, 2, 3] }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) it("should return no errors for an OpenAPI 3 definition without default set", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { "name": "num", "in": "query", "type": "number", schema: { enum: [1, 2, 3] } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) it("should return no errors for a Swagger 2 definition without enum set", () => { const spec = { swagger: "2.0", "paths": { "/pets": { "get": { "parameters": [ { "name": "num", "in": "query", "type": "number", default: 0 }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) it("should return no errors for an OpenAPI 3 definition without enum set", () => { const spec = { openapi: "3.0.0", "paths": { "/pets": { "get": { "parameters": [ { "name": "num", "in": "query", "type": "number", schema: { default: 0 } }, ] } } } } return validateHelper(spec) .then(system => { const allErrors = system.errSelectors.allErrors().toJS() expect(allErrors.length).toEqual(0) }) }) }) })