diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cfe457..2ace168 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.4.0] - 2026-05-07 + +### Added +- Added support for OpenAPI 3.2. + ## [2.3.0] - 2026-03-05 ### Added diff --git a/index.js b/index.js index 1c2346a..a378f2a 100644 --- a/index.js +++ b/index.js @@ -78,7 +78,9 @@ const endpointsParsed = require('./src/parser/endpoints.js')() const authorizationTokens = [] _.forEach(endpointsParsed, function (endpointParsed, i) { endpointsParsed[i].status = require('./src/parser/status.js')(endpointParsed.verb, endpointParsed.path) - if (endpointParsed.verb === 'POST' || endpointParsed.verb === 'PUT' || endpointParsed.verb === 'PATCH') { + const standardWriteMethods = ['POST', 'PUT', 'PATCH']; + const hasRequestBody = globalThis.definition.paths?.[endpointParsed.path]?.[endpointParsed.verb.toLowerCase()]?.requestBody; + if (standardWriteMethods.includes(endpointParsed.verb) || hasRequestBody) { endpointsParsed[i].body = require('./src/parser/'+version+'/body.js')(endpointParsed.verb, endpointParsed.path) endpointsParsed[i].consumes = require('./src/parser/'+version+'/consumes.js')(endpointParsed.verb, endpointParsed.path) } diff --git a/package-lock.json b/package-lock.json index fc4e705..4cd3e68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi2postman", - "version": "2.2.1", + "version": "2.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openapi2postman", - "version": "2.2.1", + "version": "2.4.0", "license": "ISC", "dependencies": { "js-yaml": "^4.1.0", @@ -120,9 +120,10 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } diff --git a/package.json b/package.json index 9bc5297..1ccfcf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openapi2postman", - "version": "2.3.0", + "version": "2.4.0", "description": "openapi2postman", "bin": { "o2p": "index.js" diff --git a/readme.md b/readme.md index d18c081..c2450dc 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ -# 🛠️ Openapi2Postman ![Release](https://img.shields.io/badge/release-2.0.x-purple) ![OpenApi](https://img.shields.io/badge/-openapi-%23Clojure?style=flat&logo=openapiinitiative&logoColor=white) ![Postman](https://img.shields.io/badge/postman-FF6C37?style=flat&logo=postman&logoColor=white) [![NPM](https://img.shields.io/badge/npm-%23CB3837.svg?style=flat&logo=npm&logoColor=white)](https://www.npmjs.com/package/openapi2postman) [![License: LGPL v3](https://img.shields.io/badge/license-LGPL_v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) +# 🛠️ Openapi2Postman ![Release](https://img.shields.io/badge/release-2.4.0-purple) ![OpenApi](https://img.shields.io/badge/-openapi-%23Clojure?style=flat&logo=openapiinitiative&logoColor=white) ![Postman](https://img.shields.io/badge/postman-FF6C37?style=flat&logo=postman&logoColor=white) [![NPM](https://img.shields.io/badge/npm-%23CB3837.svg?style=flat&logo=npm&logoColor=white)](https://www.npmjs.com/package/openapi2postman) [![License: LGPL v3](https://img.shields.io/badge/license-LGPL_v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) -**Openapi2Postman** creates automatic tests from Openapi 3.0 using postman format. Also, it creates environments files, depending of configuration. -Those collections can be importend in postan application. The tests includes tests for 2xx, 4xx... and tests to validate output formats. +**Openapi2Postman** creates automatic tests from OpenAPI 3.0, 3.1, and 3.2 specifications using postman format. Also, it creates environments files, depending of configuration. +Those collections can be imported in postman application. The tests includes tests for 2xx, 4xx... and tests to validate output formats.

diff --git a/seeds/parserAuthorizationInitialOpenApi3.2.json b/seeds/parserAuthorizationInitialOpenApi3.2.json new file mode 100644 index 0000000..f509ef4 --- /dev/null +++ b/seeds/parserAuthorizationInitialOpenApi3.2.json @@ -0,0 +1,290 @@ +{ + "openapi": "3.2.0", + "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.2 specification", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "Swagger API Team", + "email": "apiteam@swagger.io", + "url": "http://swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "http://petstore.swagger.io/api" + } + ], + "security": [ + { + "ApiKeyAuth": [] + } + ], + "paths": { + "/pets": { + "get": { + "security": [ + { + "OAuth2": ["admin"] + } + ], + "description": "Returns all pets from the system that the user has access to", + "operationId": "findPets", + "parameters": [ + { + "name": "tags", + "in": "query", + "description": "tags to filter by", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "limit", + "in": "query", + "description": "maximum number of results to return", + "required": false, + "schema": { + "type": ["integer", "null"], + "format": "int32", + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "default": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "post": { + "description": "Creates a new pet in the store. Duplicates are allowed", + "operationId": "addPet", + "requestBody": { + "description": "Pet to add to the store", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPet" + } + } + } + }, + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "default": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, + "/pets/{id}": { + "get": { + "description": "Returns a pet based on a single ID", + "operationId": "findPetById", + "parameters": [ + { + "$ref": "#/components/parameters/PetId" + } + ], + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "404": { + "description": "pet not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "delete": { + "description": "Deletes a single pet based on the ID supplied", + "operationId": "deletePet", + "parameters": [ + { + "$ref": "#/components/parameters/PetId" + } + ], + "responses": { + "204": { + "description": "pet deleted" + }, + "default": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + } + }, + "components": { + "parameters": { + "PetId": { + "name": "id", + "in": "path", + "description": "ID of pet", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 1 + } + } + }, + "securitySchemes": { + "BasicAuth": { + "type": "http", + "scheme": "basic" + }, + "BearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "X-API-Key" + }, + "OpenID": { + "type": "openIdConnect", + "openIdConnectUrl": "https://example.com/.well-known/openid-configuration" + }, + "OAuth2": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "authorizationUrl": "https://example.com/oauth/authorize", + "tokenUrl": "https://example.com/oauth/token", + "scopes": { + "read": "Grants read access", + "write": "Grants write access", + "admin": "Grants access to admin operations" + } + } + } + } + }, + "schemas": { + "Pet": { + "allOf": [ + { + "$ref": "#/components/schemas/NewPet" + }, + { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + }, + "unevaluatedProperties": false + } + ] + }, + "NewPet": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "tag": { + "type": ["string", "null"], + "examples": ["dog", "cat", null] + }, + "status": { + "type": "string", + "const": "available" + } + }, + "unevaluatedProperties": false + }, + "Error": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "required": ["code", "message"], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + }, + "unevaluatedProperties": false + } + } + } +} diff --git a/seeds/parserBodyItemSchema3.2.json b/seeds/parserBodyItemSchema3.2.json new file mode 100644 index 0000000..b3c9290 --- /dev/null +++ b/seeds/parserBodyItemSchema3.2.json @@ -0,0 +1,30 @@ +{ + "openapi": "3.2.0", + "info": { "version": "1.0.0", "title": "Streaming API" }, + "servers": [{ "url": "https://api.example.com/v1" }], + "paths": { + "/events": { + "get": { + "operationId": "streamEvents", + "responses": { + "200": { + "description": "Server-sent event stream", + "content": { + "application/jsonl": { + "itemSchema": { + "type": "object", + "required": ["id", "type"], + "properties": { + "id": { "type": "integer" }, + "type": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "components": { "schemas": {} } +} diff --git a/seeds/parserBodyItemSchemaResult3.2.json b/seeds/parserBodyItemSchemaResult3.2.json new file mode 100644 index 0000000..a45d3ca --- /dev/null +++ b/seeds/parserBodyItemSchemaResult3.2.json @@ -0,0 +1,10 @@ +{ + "200": { + "type": "object", + "required": ["id", "type"], + "properties": { + "id": { "type": "integer" }, + "type": { "type": "string" } + } + } +} diff --git a/seeds/parserEndpointsAdditionalOps3.2.json b/seeds/parserEndpointsAdditionalOps3.2.json new file mode 100644 index 0000000..b7fc563 --- /dev/null +++ b/seeds/parserEndpointsAdditionalOps3.2.json @@ -0,0 +1,24 @@ +{ + "openapi": "3.2.0", + "info": { "version": "1.0.0", "title": "Additional Operations API" }, + "servers": [{ "url": "https://api.example.com/v1" }], + "paths": { + "/pets": { + "get": { + "operationId": "listPets", + "responses": { + "200": { "description": "A list of pets" } + } + }, + "additionalOperations": { + "SEARCH": { + "operationId": "searchPets", + "responses": { + "200": { "description": "Search results" } + } + } + } + } + }, + "components": { "schemas": {} } +} diff --git a/seeds/parserEndpointsCustomMethod3.2.json b/seeds/parserEndpointsCustomMethod3.2.json new file mode 100644 index 0000000..3a57683 --- /dev/null +++ b/seeds/parserEndpointsCustomMethod3.2.json @@ -0,0 +1,22 @@ +{ + "openapi": "3.2.0", + "info": { "version": "1.0.0", "title": "Custom Methods API" }, + "servers": [{ "url": "https://api.example.com/v1" }], + "paths": { + "/pets": { + "get": { + "operationId": "listPets", + "responses": { + "200": { "description": "A list of pets" } + } + }, + "search": { + "operationId": "searchPets", + "responses": { + "200": { "description": "Search results" } + } + } + } + }, + "components": { "schemas": {} } +} diff --git a/seeds/parserEndpointsCustomMethodResult3.2.json b/seeds/parserEndpointsCustomMethodResult3.2.json new file mode 100644 index 0000000..bbfbed9 --- /dev/null +++ b/seeds/parserEndpointsCustomMethodResult3.2.json @@ -0,0 +1,4 @@ +[ + { "verb": "GET", "path": "/pets" }, + { "verb": "SEARCH", "path": "/pets" } +] diff --git a/seeds/parserInitialGoodOpenApi3.2.0.json b/seeds/parserInitialGoodOpenApi3.2.0.json new file mode 100644 index 0000000..abfc384 --- /dev/null +++ b/seeds/parserInitialGoodOpenApi3.2.0.json @@ -0,0 +1,178 @@ +{ + "openapi":"3.2.0", + "info":{ + "version":"1.0.0", + "title":"Swagger Petstore", + "license":{ + "name":"MIT" + } + }, + "servers":[ + { + "url":"https://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":{ + "$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" + } + } + } + } + } + } + }, + "/pets/{petId}":{ + "get":{ + "summary":"Info for a specific pet", + "operationId":"showPetById", + "tags":[ + "pets" + ], + "parameters":[ + { + "name":"petId", + "in":"path", + "required":true, + "description":"The id of the pet to retrieve", + "schema":{ + "type":"string", + "example":"asdf" + } + } + ], + "responses":{ + "200":{ + "description":"Expected response to a valid request", + "content":{ + "application/json":{ + "schema":{ + "$ref":"#/components/schemas/Pet" + } + } + } + }, + "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" + } + } + } + } + } + } diff --git a/seeds/parserInitialGoodOpenApi3.2.json b/seeds/parserInitialGoodOpenApi3.2.json new file mode 100644 index 0000000..abfc384 --- /dev/null +++ b/seeds/parserInitialGoodOpenApi3.2.json @@ -0,0 +1,178 @@ +{ + "openapi":"3.2.0", + "info":{ + "version":"1.0.0", + "title":"Swagger Petstore", + "license":{ + "name":"MIT" + } + }, + "servers":[ + { + "url":"https://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":{ + "$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" + } + } + } + } + } + } + }, + "/pets/{petId}":{ + "get":{ + "summary":"Info for a specific pet", + "operationId":"showPetById", + "tags":[ + "pets" + ], + "parameters":[ + { + "name":"petId", + "in":"path", + "required":true, + "description":"The id of the pet to retrieve", + "schema":{ + "type":"string", + "example":"asdf" + } + } + ], + "responses":{ + "200":{ + "description":"Expected response to a valid request", + "content":{ + "application/json":{ + "schema":{ + "$ref":"#/components/schemas/Pet" + } + } + } + }, + "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" + } + } + } + } + } + } diff --git a/seeds/parserInitialGoodOpenApiExpanded3.2.json b/seeds/parserInitialGoodOpenApiExpanded3.2.json new file mode 100644 index 0000000..8ee6005 --- /dev/null +++ b/seeds/parserInitialGoodOpenApiExpanded3.2.json @@ -0,0 +1,215 @@ +{ + "openapi": "3.2.0", + "jsonSchemaDialect": "https://spec.openapis.org/oas/3.2/dialect/base", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore" + }, + "servers": [ + { + "url": "http://petstore.swagger.io/api" + } + ], + "paths": { + "/pets": { + "get": { + "operationId": "findPets", + "parameters": [ + { + "name": "tags", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "limit", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "500": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "post": { + "operationId": "addPet", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPet" + } + } + } + }, + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "500": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, + "/pets/{id}": { + "get": { + "operationId": "findPetById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "500": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "delete": { + "operationId": "deletePet", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "pet deleted" + }, + "500": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Pet": { + "allOf": [ + { + "$ref": "#/components/schemas/NewPet" + }, + { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "NewPet": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "Error": { + "type": "object", + "required": ["code", "message"], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + } + } + } +} diff --git a/seeds/parserMicroksinitialGood3.2.json b/seeds/parserMicroksinitialGood3.2.json new file mode 100644 index 0000000..f5123bc --- /dev/null +++ b/seeds/parserMicroksinitialGood3.2.json @@ -0,0 +1,117 @@ +{ + "openapi": "3.2.0", + "info": { + "title": "Swagger Petstore 2.0", + "description": "This is a sample server Petstore server.", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "email": "apiteam@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://petstore.swagger.io/v2" + }, + { + "url": "http://petstore.swagger.io/v2" + } + ], + "paths": { + "/user": { + "post": { + "tags": ["user"], + "summary": "Create user", + "operationId": "createUser", + "requestBody": { + "required": true, + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/{username}": { + "get": { + "tags": ["user"], + "summary": "Get user by user name", + "operationId": "getUserByName", + "parameters": [ + { + "name": "username", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "x-microcks-operation": { + "delay": 100, + "dispatcher": "SCRIPT", + "dispatcherRules": "def headers = mockRequest.getRequestHeaders(); if (headers.hasValues(\"X-Microcks-Response-Name\")) { return headers.get(\"X-Microcks-Response-Name\", \"null\") }" + } + } + } + }, + "components": { + "schemas": { + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "username": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "password": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "userStatus": { + "type": "integer", + "format": "int32" + } + } + } + } + } +} diff --git a/seeds/parserQueryParamsQuerystring3.2.json b/seeds/parserQueryParamsQuerystring3.2.json new file mode 100644 index 0000000..2ba0ac4 --- /dev/null +++ b/seeds/parserQueryParamsQuerystring3.2.json @@ -0,0 +1,25 @@ +{ + "openapi": "3.2.0", + "info": { "version": "1.0.0", "title": "Querystring Param API" }, + "servers": [{ "url": "https://api.example.com/v1" }], + "paths": { + "/search": { + "get": { + "operationId": "search", + "parameters": [ + { + "name": "q", + "in": "querystring", + "description": "Full query string to pass as a single value", + "required": false, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Search results" } + } + } + } + }, + "components": { "schemas": {} } +} diff --git a/seeds/parserSummaryOpenApi3.2.json b/seeds/parserSummaryOpenApi3.2.json new file mode 100644 index 0000000..dd5fc8b --- /dev/null +++ b/seeds/parserSummaryOpenApi3.2.json @@ -0,0 +1,117 @@ +{ + "openapi": "3.2.0", + "jsonSchemaDialect": "https://spec.openapis.org/oas/3.2/dialect/base", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.2 specification", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "Swagger API Team", + "email": "apiteam@swagger.io", + "url": "http://swagger.io" + }, + "license": { + "name": "Apache 2.0", + "identifier": "Apache-2.0" + } + }, + "servers": [ + { + "url": "http://petstore.swagger.io/api" + } + ], + "security": [ + { + "ApiKeyAuth": [] + } + ], + "paths": { + "/pets": { + "get": { + "summary": "Pets list", + "operationId": "findPets", + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + } + } + }, + "post": { + "summary": "Create pet", + "operationId": "addPet", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPet" + } + } + } + }, + "responses": { + "200": { + "description": "pet response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "X-API-Key" + } + }, + "schemas": { + "Pet": { + "allOf": [ + { + "$ref": "#/components/schemas/NewPet" + }, + { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer" + } + } + } + ] + }, + "NewPet": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "tag": { + "type": ["string", "null"] + } + } + } + } + } +} diff --git a/src/parser/endpoints.js b/src/parser/endpoints.js index 2563283..eb4880b 100644 --- a/src/parser/endpoints.js +++ b/src/parser/endpoints.js @@ -18,10 +18,12 @@ module.exports = function () { const items = []; _.forEach(globalThis.definition.paths, function (pathInfo, path) { _.forEach(pathInfo, function (verbInfo, verb) { - items.push({ - 'verb': _.toUpper(verb), - 'path': path - }); + if (_.isObject(verbInfo) && verbInfo.responses) { + items.push({ + 'verb': _.toUpper(verb), + 'path': path + }); + } }); }); return items; diff --git a/src/parser/openapi3/body.js b/src/parser/openapi3/body.js index db696f6..920630b 100644 --- a/src/parser/openapi3/body.js +++ b/src/parser/openapi3/body.js @@ -5,6 +5,14 @@ const _ = require('lodash') const checkCircularReferences = require('../../utils/circularRef.js'); +const STREAMING_CONTENT_TYPES = [ + 'application/jsonl', + 'application/ndjson', + 'application/x-ndjson', + 'text/event-stream', + 'multipart/mixed', +] + module.exports = function () { const MAX_DEPTH_LEVEL = 20; @@ -40,24 +48,27 @@ module.exports = function () { while (!properContent && index < contentsArray.length) { const mediaType = body.content[contentsArray[index]]; - if (!mediaType.schema) { + const effectiveSchema = mediaType.schema || mediaType.itemSchema; + + if (!effectiveSchema) { if (contentsArray[index] === 'application/octet-stream') { return { type: 'string', format: 'binary' }; } + index++; continue; } - const withoutRefs = replaceRefs(mediaType.schema, 1); + const withoutRefs = replaceRefs(effectiveSchema, 1); switch (contentsArray[index]) { case 'application/x-www-form-urlencoded': schema = replaceAllOfs(withoutRefs); properContent = true; break; case 'multipart/form-data': - schema = replaceAllOfs(body.content[contentsArray[index]].schema); + schema = replaceAllOfs(body.content[contentsArray[index]].schema || body.content[contentsArray[index]].itemSchema); properContent = true; break; default: @@ -70,9 +81,10 @@ module.exports = function () { if (!properContent && contentsArray.length > 0) { const firstContentType = contentsArray[0]; const mediaType = body.content[firstContentType]; + const effectiveSchema = mediaType?.schema || mediaType?.itemSchema; - if (mediaType?.schema) { - const withoutRefs = replaceRefs(mediaType.schema, 1); + if (effectiveSchema) { + const withoutRefs = replaceRefs(effectiveSchema, 1); return replaceAllOfs(withoutRefs); } } @@ -85,8 +97,22 @@ module.exports = function () { } const bodyResponses = {} _.forEach(endpoint['responses'], function (response, status) { + let schema = null + if (response?.content?.['application/json']?.schema) { - const withOutRefs = replaceRefs(response.content['application/json'].schema, 1) + schema = response.content['application/json'].schema + } else if (response?.content) { + for (const streamType of STREAMING_CONTENT_TYPES) { + const mt = response.content[streamType] + if (mt) { + schema = mt.schema || mt.itemSchema + if (schema) break + } + } + } + + if (schema) { + const withOutRefs = replaceRefs(schema, 1) bodyResponses[status] = replaceAllOfs(withOutRefs) if (bodyResponses[status].hasOwnProperty('required')) { const requiredWtihoutDuplicates = bodyResponses[status].required.filter((value, index, arr) => { @@ -241,4 +267,4 @@ module.exports = function () { return result } -}() \ No newline at end of file +}() diff --git a/src/parser/openapi3/queryParams.js b/src/parser/openapi3/queryParams.js index 650c2df..647f641 100644 --- a/src/parser/openapi3/queryParams.js +++ b/src/parser/openapi3/queryParams.js @@ -15,9 +15,9 @@ module.exports = function() { const param = queryParam.schema ? queryParam : getContentProperty(queryParam); const obj = { - name: queryParam.name, - type: param.schema.type, - required : queryParam.required, + name: queryParam.name, + type: param.schema.type, + required : queryParam.required, }; const example = getExamples(param); @@ -29,6 +29,20 @@ module.exports = function() { result.push(obj); }); + const queryStringParams = _.filter(parameters, ['in', 'querystring']) + _.forEach(queryStringParams, function(queryParam) { + const obj = { + name: queryParam.name, + type: queryParam.schema?.type || 'string', + required: queryParam.required, + } + const example = getExamples(queryParam) + if (example !== undefined && example !== null) { + obj.example = example + } + result.push(obj) + }) + return result }; diff --git a/src/parser/openapi3/refs.js b/src/parser/openapi3/refs.js index 8029f0e..26ecd3d 100644 --- a/src/parser/openapi3/refs.js +++ b/src/parser/openapi3/refs.js @@ -7,12 +7,18 @@ function eachRecursive(obj) { if (typeof obj[k] == "object" && obj[k] !== null) { eachRecursive(obj[k]); } else if (k == '$ref') { + const siblings = {} + for (const sib of Object.keys(obj)) { + if (sib !== '$ref') { + siblings[sib] = obj[sib] + } + } let property = obj[k] property = property.replace('#/', '') let propertiesArray = property.split('/') let refObject = findObject(globalThis.definition, propertiesArray) delete obj[k] - Object.assign(obj, refObject) + Object.assign(obj, refObject, siblings) } } } @@ -26,9 +32,23 @@ function findObject(obj, propertiesArray) { return findObject(obj[property], propertiesArray) } +function liftAdditionalOperations() { + if (!globalThis.definition.paths) return + for (const path in globalThis.definition.paths) { + const pathItem = globalThis.definition.paths[path] + if (pathItem && typeof pathItem.additionalOperations === 'object' && pathItem.additionalOperations !== null) { + for (const method in pathItem.additionalOperations) { + pathItem[method.toLowerCase()] = pathItem.additionalOperations[method] + } + delete pathItem.additionalOperations + } + } +} + module.exports = function() { return function get() { eachRecursive(globalThis.definition) + liftAdditionalOperations() return globalThis.definition } }() \ No newline at end of file diff --git a/src/parser/openapiAuthorizationDefinition.js b/src/parser/openapiAuthorizationDefinition.js index a8d2be6..3276ccb 100644 --- a/src/parser/openapiAuthorizationDefinition.js +++ b/src/parser/openapiAuthorizationDefinition.js @@ -4,6 +4,7 @@ const _ = require('lodash'); +const FLOW_PRIORITY = ['authorizationCode', 'clientCredentials', 'password', 'deviceAuthorization', 'implicit'] module.exports = function() { @@ -13,8 +14,9 @@ module.exports = function() { definition = oAuthDefinition[i]; } const data = parseUrl(definition.flows) - const authKey = _.keys(global.definition.security[0])[0] - return generateDefinition(data,authKey) + if (!data) return null + const authKey = _.keys(globalThis.definition.security[0])[0] + return generateDefinition(data,authKey) } function generateDefinition(data,auth){ @@ -88,19 +90,32 @@ module.exports = function() { } function parseUrl(flows) { - let getTokenUrl - for (const i in flows) { - getTokenUrl = flows[i]; + let targetFlow = null + for (const flowName of FLOW_PRIORITY) { + if (flows[flowName]?.tokenUrl) { + targetFlow = flows[flowName] + break + } } - const urlObject = new URL(getTokenUrl.tokenUrl); + if (!targetFlow) { + for (const name in flows) { + if (flows[name]?.tokenUrl) { + targetFlow = flows[name] + break + } + } + } + if (!targetFlow?.tokenUrl) return null + + const urlObject = new URL(targetFlow.tokenUrl); const host = `${urlObject.protocol}//${urlObject.host}`; - const path = urlObject.pathname.split('/').filter(segment => segment); + const path = urlObject.pathname.split('/').filter(Boolean); return { - raw: getTokenUrl.tokenUrl, + raw: targetFlow.tokenUrl, host: host, path: path }; -} + } }() \ No newline at end of file diff --git a/src/parser/version.js b/src/parser/version.js index 534bd7f..0980e69 100644 --- a/src/parser/version.js +++ b/src/parser/version.js @@ -3,17 +3,18 @@ 'use strict' module.exports = function() { - + return function get(){ const versions = { swagger : ['2.0', '2.0.0'], openapi3 : ['3.0', '3.0.0', '3.0.1','3.0.2', '3.0.3'], - openapi31 : ['3.1', '3.1.0', '3.1.1', '3.1.2'] + openapi31 : ['3.1', '3.1.0', '3.1.1', '3.1.2'], + openapi32 : ['3.2', '3.2.0'] } if (versions.swagger.includes(globalThis.definition.swagger)) { return 'swagger2' - } else if (versions.openapi3.includes(globalThis.definition.openapi) || versions.openapi31.includes(globalThis.definition.openapi)) { + } else if (versions.openapi3.includes(globalThis.definition.openapi) || versions.openapi31.includes(globalThis.definition.openapi) || versions.openapi32.includes(globalThis.definition.openapi)) { return 'openapi3' } else { require('../utils/error.js')('Specification is not supported') diff --git a/test/parser-authorization.js b/test/parser-authorization.js index 6c81a19..19e8505 100644 --- a/test/parser-authorization.js +++ b/test/parser-authorization.js @@ -23,4 +23,7 @@ describe('parser-authorization', () => { checkAuth('auth general oa3.1', 'parserAuthorizationInitialOpenApi3.1.json','POST', '/pets', 'ApiKeyAuth'); checkAuth('auth endpoint oa3.1', 'parserAuthorizationInitialOpenApi3.1.json','GET', '/pets', 'OAuth2'); + checkAuth('auth general oa3.2', 'parserAuthorizationInitialOpenApi3.2.json','POST', '/pets', 'ApiKeyAuth'); + checkAuth('auth endpoint oa3.2', 'parserAuthorizationInitialOpenApi3.2.json','GET', '/pets', 'OAuth2'); + }); \ No newline at end of file diff --git a/test/parser-body.js b/test/parser-body.js index 026d338..11c8b37 100644 --- a/test/parser-body.js +++ b/test/parser-body.js @@ -49,4 +49,14 @@ describe('parser-body', () => { checkBody('body allof loop swagger2','swagger2','parserBodyAllofLoopInitial.json','POST','/apple',false,'parserInitialGoodResultAllOfLoop.json'); checkBody('body allof string swagger2','swagger2','parserBodyAllofString.json','POST','/apple',false,'parserInitialGoodResultAllOfString.json'); + + checkBody('body void request openapi3.2','openapi3','parserInitialGoodOpenApi3.2.json','GET','/pets',false,null); + + checkBody('body fill request openapi3.2','openapi3','parserInitialGoodOpenApiExpanded3.2.json','POST','/pets',false,'parserInitialGoodResultPetRequest.json'); + + checkBody('body items,ref and allof response openapi3.2','openapi3','parserInitialGoodOpenApiExpanded3.2.json','GET','/pets',true,'parserInitialGoodResultRespArray.json'); + + checkBody('body ref and allof response openapi3.2','openapi3','parserInitialGoodOpenApiExpanded3.2.json','POST','/pets',true,'parserInitialGoodResultRespObject.json'); + + checkBody('body streaming itemSchema response openapi3.2','openapi3','parserBodyItemSchema3.2.json','GET','/events',true,'parserBodyItemSchemaResult3.2.json'); }); \ No newline at end of file diff --git a/test/parser-consumes.js b/test/parser-consumes.js index 769d1ea..e5bd5db 100644 --- a/test/parser-consumes.js +++ b/test/parser-consumes.js @@ -1,6 +1,6 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert') +const assert = require('node:assert') describe('parser-consumes', () => { @@ -36,4 +36,12 @@ describe('parser-consumes', () => { assert.equal(consumes, 'application/json'); }) + it('specifies openapi3.2', () => { + + globalThis.definition = require('../seeds/parserInitialGoodOpenApiExpanded3.2.json'); + + const consumes = require('../src/parser/openapi3/consumes.js')('POST','/pets'); + assert.equal(consumes, 'application/json'); + }) + }) \ No newline at end of file diff --git a/test/parser-endpoints.js b/test/parser-endpoints.js index 7085240..7712f02 100644 --- a/test/parser-endpoints.js +++ b/test/parser-endpoints.js @@ -44,4 +44,8 @@ describe('parser-endpoints', () => { checkEndpoints('endpoints good openapi3.1', 'parserInitialGoodOpenApi3.1.json', 'parserEndpointsGoodOpenApi3Result.json'); + checkEndpoints('endpoints good openapi3.2', 'parserInitialGoodOpenApi3.2.json', 'parserEndpointsGoodOpenApi3Result.json'); + + checkEndpoints('endpoints openapi3.2 additionalOperations lifted to path level', 'parserEndpointsCustomMethod3.2.json', 'parserEndpointsCustomMethodResult3.2.json'); + }); \ No newline at end of file diff --git a/test/parser-microcks.js b/test/parser-microcks.js index edf57ce..313edc9 100644 --- a/test/parser-microcks.js +++ b/test/parser-microcks.js @@ -1,6 +1,6 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert') +const assert = require('node:assert') describe('parser-microcks', () => { @@ -38,4 +38,11 @@ describe('parser-microcks', () => { assert.equal(microcks, true); }) + it('specifies openapi3.2', () => { + + globalThis.definition = require('../seeds/parserMicroksinitialGood3.2.json'); + const microcks = require('../src/parser/openapi3/microcks.js')('GET','/user/{username}'); + assert.equal(microcks, true); + }) + }) diff --git a/test/parser-pathParameters.js b/test/parser-pathParameters.js index 5a0dbee..691b38a 100644 --- a/test/parser-pathParameters.js +++ b/test/parser-pathParameters.js @@ -1,6 +1,6 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert'); +const assert = require('node:assert'); describe('parser-pathParameters', () => { @@ -28,4 +28,12 @@ describe('parser-pathParameters', () => { assert.deepStrictEqual(status, [ { name: 'petId', type: 'string', example: 'asdf' } ]) }) + it('good openapi3.2', () => { + + globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.2.json') + + const status = require('../src/parser/openapi3/pathParameters.js')('GET','/pets/{petId}') + assert.deepStrictEqual(status, [ { name: 'petId', type: 'string', example: 'asdf' } ]) + }) + }) \ No newline at end of file diff --git a/test/parser-queryParams.js b/test/parser-queryParams.js index f38fc2f..0c7dcb6 100644 --- a/test/parser-queryParams.js +++ b/test/parser-queryParams.js @@ -1,6 +1,6 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert'); +const assert = require('node:assert'); describe('parser-queryParams', () => { @@ -29,4 +29,11 @@ describe('parser-queryParams', () => { testQuery('queryParams fill openapi3.1', 'openapi3', 'parserInitialGoodOpenApiExpanded3.1.json', 'GET', '/pets', results.tagsLimit(true)); testQuery('queryParams void openapi3.1', 'openapi3', 'parserInitialGoodOpenApiExpanded3.1.json', 'POST', '/pets', results.empty); + testQuery('queryParams fill openapi3.2', 'openapi3', 'parserInitialGoodOpenApiExpanded3.2.json', 'GET', '/pets', results.tagsLimit(true)); + testQuery('queryParams void openapi3.2', 'openapi3', 'parserInitialGoodOpenApiExpanded3.2.json', 'POST', '/pets', results.empty); + + testQuery('queryParams querystring openapi3.2', 'openapi3', 'parserQueryParamsQuerystring3.2.json', 'GET', '/search', [ + { name: 'q', type: 'string', required: false } + ]); + }); \ No newline at end of file diff --git a/test/parser-schemaHostBasePath.js b/test/parser-schemaHostBasePath.js index 073aad3..759c701 100644 --- a/test/parser-schemaHostBasePath.js +++ b/test/parser-schemaHostBasePath.js @@ -1,30 +1,26 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert'); +const assert = require('node:assert'); + +const openapi3Cases = [ + { version: '3.0', seed: '../seeds/parserInitialGoodOpenApi3.json', host: 'https://petstore.swagger.io', basePath: '/v1' }, + { version: '3.1', seed: '../seeds/parserInitialGoodOpenApi3.1.json', host: 'https://petstore.swagger.io', basePath: '/v1' }, + { version: '3.2', seed: '../seeds/parserInitialGoodOpenApi3.2.json', host: 'https://petstore.swagger.io', basePath: '/v1' }, +]; describe('parser-schemaHostBasePath', () => { it('good swagger2', () => { - globalThis.definition = require('../seeds/parserSchemaHostBasePathInitialGood.json'); - const schemaHostBasePath = require('../src/parser/swagger2/schemaHostBasePath.js')(); assert.deepStrictEqual(schemaHostBasePath, { host: 'https://myserver.com', basePath: '/first/second' }); - }) - - it('good openapi3.0', () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.json'); - - const schemaHostBasePath = require('../src/parser/openapi3/schemaHostBasePath.js')(); - assert.deepStrictEqual(schemaHostBasePath, { host: 'http://petstore.swagger.io', basePath: '/v1' }); - }) - - it('good openapi3.1', () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.1.json'); - - const schemaHostBasePath = require('../src/parser/openapi3/schemaHostBasePath.js')(); - assert.deepStrictEqual(schemaHostBasePath, { host: 'https://petstore.swagger.io', basePath: '/v1' }); - }) + }); + + openapi3Cases.forEach(({ version, seed, host, basePath }) => { + it(`good openapi${version}`, () => { + globalThis.definition = require(seed); + const schemaHostBasePath = require('../src/parser/openapi3/schemaHostBasePath.js')(); + assert.deepStrictEqual(schemaHostBasePath, { host, basePath }); + }); + }); }); \ No newline at end of file diff --git a/test/parser-status.js b/test/parser-status.js index 28b7009..ff2e11e 100644 --- a/test/parser-status.js +++ b/test/parser-status.js @@ -1,6 +1,6 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert'); +const assert = require('node:assert'); describe('parser-status', () => { @@ -28,4 +28,12 @@ describe('parser-status', () => { assert.deepStrictEqual(status, [ 201, 500 ]) }) + it('good openapi3.2', () => { + + globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.2.json') + + const status = require('../src/parser/status.js')('POST','/pets') + assert.deepStrictEqual(status, [ 201, 500 ]) + }) + }); \ No newline at end of file diff --git a/test/parser-summary.js b/test/parser-summary.js index 4f6a74f..e3495af 100644 --- a/test/parser-summary.js +++ b/test/parser-summary.js @@ -1,6 +1,6 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert'); +const assert = require('node:assert'); describe('parser-summary', () => { @@ -28,4 +28,12 @@ describe('parser-summary', () => { assert.equal(summary, "Create pet") }) + it('good openapi3.2', () => { + + globalThis.definition = require('../seeds/parserSummaryOpenApi3.2.json') + + const summary = require('../src/parser/summary.js')('POST','/pets') + assert.equal(summary, "Create pet") + }) + }) \ No newline at end of file diff --git a/test/parser-version.js b/test/parser-version.js index b466e06..85d050b 100644 --- a/test/parser-version.js +++ b/test/parser-version.js @@ -1,62 +1,31 @@ /** Part of APIAddicts. See LICENSE fileor full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/ -const assert = require('assert') +const assert = require('node:assert') + +const openapi3Cases = [ + { name: 'openapi3.0', seed: '../seeds/parserInitialGoodOpenApi3.json' }, + { name: 'openapi version 3.0.2', seed: '../seeds/parserInitialGoodOpenApi3.0.2.json' }, + { name: 'openapi version 3.0.3', seed: '../seeds/parserInitialGoodOpenApi3.0.3.json' }, + { name: 'openapi3.1', seed: '../seeds/parserInitialGoodOpenApi3.1.json' }, + { name: 'openapi version 3.1.1', seed: '../seeds/parserInitialGoodOpenApi3.1.1.json' }, + { name: 'openapi version 3.1.2', seed: '../seeds/parserInitialGoodOpenApi3.1.2.json' }, + { name: 'openapi3.2', seed: '../seeds/parserInitialGoodOpenApi3.2.json' }, + { name: 'openapi version 3.2.0', seed: '../seeds/parserInitialGoodOpenApi3.2.0.json' }, +]; describe('parser-version', () => { - - it('swagger2', () => { - - globalThis.definition = require('../seeds/parserInitialGood.json') - const version = require('../src/parser/version.js')() - assert.equal(version, 'swagger2') + it('swagger2', () => { + globalThis.definition = require('../seeds/parserInitialGood.json'); + const version = require('../src/parser/version.js')(); + assert.equal(version, 'swagger2'); }); - it('openapi3.0', () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.json') - - const version = require('../src/parser/version.js')() - assert.equal(version, 'openapi3') + openapi3Cases.forEach(({ name, seed }) => { + it(name, () => { + globalThis.definition = require(seed); + const version = require('../src/parser/version.js')(); + assert.equal(version, 'openapi3'); + }); }); - - it('openapi version 3.0.2' , () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.0.2.json') - - const version = require('../src/parser/version.js')() - assert.equal(version, 'openapi3') - }) - - it('openapi version 3.0.3' , () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.0.3.json') - - const version = require('../src/parser/version.js')() - assert.equal(version, 'openapi3') - }) - - it('openapi3.1', () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.1.json') - - const version = require('../src/parser/version.js')() - assert.equal(version, 'openapi3') - }); - - it('openapi version 3.1.1' , () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.1.1.json') - - const version = require('../src/parser/version.js')() - assert.equal(version, 'openapi3') - }) - - it('openapi version 3.1.2' , () => { - - globalThis.definition = require('../seeds/parserInitialGoodOpenApi3.1.2.json') - - const version = require('../src/parser/version.js')() - assert.equal(version, 'openapi3') - }) }); \ No newline at end of file