Ekapp/swagger/test/unit/plugins/validate-semantic/2and3/schemas.js

1178 lines
33 KiB
JavaScript

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)
})
})
})
})