From f3b035ccba3810d11605d7ae7073fd8cda1ec2e0 Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Mon, 17 Jun 2024 10:21:58 +0100 Subject: [PATCH 1/6] update test for redocly configurable rules --- test/unit/definitionGenerator.spec.js | 1330 ++++++++++++++----------- 1 file changed, 743 insertions(+), 587 deletions(-) diff --git a/test/unit/definitionGenerator.spec.js b/test/unit/definitionGenerator.spec.js index bb5dc2f..6038ace 100644 --- a/test/unit/definitionGenerator.spec.js +++ b/test/unit/definitionGenerator.spec.js @@ -1,629 +1,785 @@ -'use strict' - -const fs = require('fs').promises -const path = require('path') -const expect = require('chai').expect - -const serverlessMock = require('../helpers/serverless') -const modelsDocument = require('../models/models/models.json') -const DefinitionGenerator = require('../../src/definitionGenerator') - -describe('DefinitionGenerator', () => { - let mockServerless - const v4 = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i); - beforeEach(function() { - mockServerless = JSON.parse(JSON.stringify(serverlessMock)) - Object.assign(mockServerless.service.custom.documentation, modelsDocument) +"use strict"; + +const fs = require("fs").promises; +const path = require("path"); +const expect = require("chai").expect; + +const serverlessMock = require("../helpers/serverless"); +const modelsDocument = require("../models/models/models.json"); +const DefinitionGenerator = require("../../src/definitionGenerator"); + +describe("DefinitionGenerator", () => { + let mockServerless; + const v4 = new RegExp( + /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i + ); + beforeEach(function () { + mockServerless = JSON.parse(JSON.stringify(serverlessMock)); + Object.assign(mockServerless.service.custom.documentation, modelsDocument); + }); + + describe("constructor", () => { + it("should return a definitionGenerator", function () { + const expected = new DefinitionGenerator(mockServerless, {}); + expect(expected).to.be.an.instanceOf(DefinitionGenerator); }); - describe('constructor', () => { - it('should return a definitionGenerator', function() { - const expected = new DefinitionGenerator(mockServerless, {}) - expect(expected).to.be.an.instanceOf(DefinitionGenerator) - }); - - it('should default to version 3.0.0 of openAPI when openAPI version is not passed in', function() { - const serverlessWithoutOpenAPIVersion = JSON.parse(JSON.stringify(mockServerless)) - delete serverlessWithoutOpenAPIVersion.processedInput; - let expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') - - Object.assign(serverlessWithoutOpenAPIVersion, {processedInput: {}}) - expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') - - serverlessWithoutOpenAPIVersion.processedInput = { - options: {} - } - expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') - - serverlessWithoutOpenAPIVersion.processedInput.options = { - test: 'abc' - } - - expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') - - serverlessWithoutOpenAPIVersion.processedInput.options = { - openApiVersion: null - } - - expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') + it("should default to version 3.0.0 of openAPI when openAPI version is not passed in", function () { + const serverlessWithoutOpenAPIVersion = JSON.parse( + JSON.stringify(mockServerless) + ); + delete serverlessWithoutOpenAPIVersion.processedInput; + let expected = new DefinitionGenerator( + serverlessWithoutOpenAPIVersion, + {} + ); + expect(expected.version).to.be.equal("3.0.0"); + + Object.assign(serverlessWithoutOpenAPIVersion, { processedInput: {} }); + expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.0"); + + serverlessWithoutOpenAPIVersion.processedInput = { + options: {}, + }; + expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.0"); + + serverlessWithoutOpenAPIVersion.processedInput.options = { + test: "abc", + }; + + expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.0"); + + serverlessWithoutOpenAPIVersion.processedInput.options = { + openApiVersion: null, + }; + + expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.0"); + + serverlessWithoutOpenAPIVersion.processedInput.options = { + openApiVersion: undefined, + }; + + expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.0"); + + serverlessWithoutOpenAPIVersion.processedInput.options = { + openapiVersion: undefined, + }; + + expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.0"); + }); - serverlessWithoutOpenAPIVersion.processedInput.options = { - openApiVersion: undefined - } + it("should respect the version of openAPI when passed in", function () { + const serverlessWithOpenAPIVersion = JSON.parse( + JSON.stringify(mockServerless) + ); + serverlessWithOpenAPIVersion.processedInput.options.openApiVersion = + "3.0.2"; + let expected = new DefinitionGenerator(serverlessWithOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.2"); + + serverlessWithOpenAPIVersion.processedInput.options.openApiVersion = + "3.0.1"; + expected = new DefinitionGenerator(serverlessWithOpenAPIVersion, {}); + expect(expected.version).to.be.equal("3.0.1"); + }); - expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') + it(`correctly resolves external redocly rules`, async function () { + await fs.mkdir(path.resolve("options")).catch((err) => { + console.error(err); + throw err; + }); + + await fs + .copyFile( + path.resolve("test/helpers/redocly.json"), + path.resolve("options/redocly.json") + ) + .catch((err) => { + console.error(err); + throw err; + }); - serverlessWithoutOpenAPIVersion.processedInput.options = { - openapiVersion: undefined - } + const expected = new DefinitionGenerator(mockServerless, {}); - expected = new DefinitionGenerator(serverlessWithoutOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.0') - }); + expect(expected.REDOCLY_RULES).to.have.property( + "operation-2xx-response", + "warn" + ); - it('should respect the version of openAPI when passed in', function() { - const serverlessWithOpenAPIVersion = JSON.parse(JSON.stringify(mockServerless)) - serverlessWithOpenAPIVersion.processedInput.options.openApiVersion = '3.0.2' - let expected = new DefinitionGenerator(serverlessWithOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.2') + await fs.rm(path.resolve("options/redocly.json")).catch((err) => { + console.error(err); + throw err; + }); - serverlessWithOpenAPIVersion.processedInput.options.openApiVersion = '3.0.1' - expected = new DefinitionGenerator(serverlessWithOpenAPIVersion, {}) - expect(expected.version).to.be.equal('3.0.1') - }); + await fs.rmdir(path.resolve("options")).catch((err) => { + console.error(err); + throw err; + }); }); + }); - describe('createInfo', () => { - it('should create openAPI info object correctly', function() { - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + describe("createInfo", () => { + it("should create openAPI info object correctly", function () { + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - // expect(definitionGenerator.openAPI.info).to.deep.equal(mockServerless.service.custom.documentation) - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + // expect(definitionGenerator.openAPI.info).to.deep.equal(mockServerless.service.custom.documentation) + }); - it('should use the service name when documentation title has not been supplied', function() { - delete mockServerless.service.custom.documentation.title - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + it("should use the service name when documentation title has not been supplied", function () { + delete mockServerless.service.custom.documentation.title; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info.title).to.be.equal(mockServerless.service.service) - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info.title).to.be.equal( + mockServerless.service.service + ); + }); - it('should use the service name when documentation description has not been supplied', function() { - delete mockServerless.service.custom.documentation.description - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + it("should use the service name when documentation description has not been supplied", function () { + delete mockServerless.service.custom.documentation.description; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info.description).to.be.equal('') - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info.description).to.be.equal(""); + }); - it('should use an empty string when documentation description has not been supplied', function() { - delete mockServerless.service.custom.documentation.description - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + it("should use an empty string when documentation description has not been supplied", function () { + delete mockServerless.service.custom.documentation.description; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info.description).to.be.equal('') - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info.description).to.be.equal(""); + }); - it('should generate a uuid for version when documentation version has not been supplied', function() { - delete mockServerless.service.custom.documentation.version + it("should generate a uuid for version when documentation version has not been supplied", function () { + delete mockServerless.service.custom.documentation.version; - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(v4.test(definitionGenerator.openAPI.info.version)).to.be.true - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(v4.test(definitionGenerator.openAPI.info.version)).to.be.true; + }); - it('should assign a contact Object when a contact object is included', function() { - mockServerless.service.custom.documentation.contact = { - name: 'John', - url: 'http://example.com', - email: 'john@example.com' - } - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.have.property('contact') - expect(definitionGenerator.openAPI.info.contact).to.be.an('object') - expect(definitionGenerator.openAPI.info.contact.name).to.be.an('string') - }); + it("should assign a contact Object when a contact object is included", function () { + mockServerless.service.custom.documentation.contact = { + name: "John", + url: "http://example.com", + email: "john@example.com", + }; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.have.property("contact"); + expect(definitionGenerator.openAPI.info.contact).to.be.an("object"); + expect(definitionGenerator.openAPI.info.contact.name).to.be.an("string"); + }); - it('should only assign a contact url if one is provided', function() { - mockServerless.service.custom.documentation.contact = { - name: 'John', - email: 'john@example.com' - } - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.have.property('contact') - expect(definitionGenerator.openAPI.info.contact).to.be.an('object') - expect(definitionGenerator.openAPI.info.contact.name).to.be.an('string') - expect(definitionGenerator.openAPI.info.contact).to.not.have.property('url') - }); + it("should only assign a contact url if one is provided", function () { + mockServerless.service.custom.documentation.contact = { + name: "John", + email: "john@example.com", + }; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.have.property("contact"); + expect(definitionGenerator.openAPI.info.contact).to.be.an("object"); + expect(definitionGenerator.openAPI.info.contact.name).to.be.an("string"); + expect(definitionGenerator.openAPI.info.contact).to.not.have.property( + "url" + ); + }); - it('should assign a license Object when a license object is included with a name', function() { - mockServerless.service.custom.documentation.license = { - name: 'Apache 2.0', - url: 'https://www.apache.org/licenses/LICENSE-2.0.html', - } - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.have.property('license') - expect(definitionGenerator.openAPI.info.license).to.be.an('object') - expect(definitionGenerator.openAPI.info.license.name).to.be.an('string') - }); + it("should assign a license Object when a license object is included with a name", function () { + mockServerless.service.custom.documentation.license = { + name: "Apache 2.0", + url: "https://www.apache.org/licenses/LICENSE-2.0.html", + }; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.have.property("license"); + expect(definitionGenerator.openAPI.info.license).to.be.an("object"); + expect(definitionGenerator.openAPI.info.license.name).to.be.an("string"); + }); - it('should not assign a license Object when a license object is included without a name', function() { - mockServerless.service.custom.documentation.license = { - url: 'https://www.apache.org/licenses/LICENSE-2.0.html', - } - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + it("should not assign a license Object when a license object is included without a name", function () { + mockServerless.service.custom.documentation.license = { + url: "https://www.apache.org/licenses/LICENSE-2.0.html", + }; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.not.have.property('license') - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.not.have.property("license"); + }); - it('should only assign a contact url if one is provided', function() { - mockServerless.service.custom.documentation.license = { - name: 'John', - } - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.have.property('license') - expect(definitionGenerator.openAPI.info.license).to.be.an('object') - expect(definitionGenerator.openAPI.info.license.name).to.be.an('string') - expect(definitionGenerator.openAPI.info.license).to.not.have.property('url') - }); + it("should only assign a contact url if one is provided", function () { + mockServerless.service.custom.documentation.license = { + name: "John", + }; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.have.property("license"); + expect(definitionGenerator.openAPI.info.license).to.be.an("object"); + expect(definitionGenerator.openAPI.info.license.name).to.be.an("string"); + expect(definitionGenerator.openAPI.info.license).to.not.have.property( + "url" + ); + }); - it('should assign specification extension fields when included', function() { - mockServerless.service.custom.documentation['x-field'] = 'john' - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + it("should assign specification extension fields when included", function () { + mockServerless.service.custom.documentation["x-field"] = "john"; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.have.property('x-field') - expect(definitionGenerator.openAPI.info['x-field']).to.be.equal('john') - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.have.property("x-field"); + expect(definitionGenerator.openAPI.info["x-field"]).to.be.equal("john"); + }); - it('should ignore fields that do not conform to specifiction extension', function() { - mockServerless.service.custom.documentation.otherField = 'john' - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createInfo() + it("should ignore fields that do not conform to specifiction extension", function () { + mockServerless.service.custom.documentation.otherField = "john"; + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createInfo(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.be.an('object') - expect(definitionGenerator.openAPI.info).to.not.have.property('otherField') - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.be.an("object"); + expect(definitionGenerator.openAPI.info).to.not.have.property( + "otherField" + ); + }); + }); + + describe("createSecuritySchemes", () => { + describe("API Keys", () => { + it("should add an API Key security scheme to components", function () { + mockServerless.service.custom.documentation.securitySchemes = { + api_key: { + type: "apiKey", + name: "Authorization", + in: "header", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.have.property( + "securitySchemes" + ); + expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an( + "object" + ); + expect( + definitionGenerator.openAPI.components.securitySchemes + ).to.have.property("api_key"); + expect( + definitionGenerator.openAPI.components.securitySchemes.api_key + ).to.have.property("type"); + expect( + definitionGenerator.openAPI.components.securitySchemes.api_key.type + ).to.be.equal("apiKey"); + }); + + it("should throw an error when name is missing from an API Key scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + api_key: { + type: "apiKey", + in: "header", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw( + 'Security Scheme for "apiKey" requires the name of the header, query or cookie parameter to be used' + ); + }); + + it("should throw an error when in is missing from an API Key scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + api_key: { + type: "apiKey", + name: "Authorization", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw( + 'Security Scheme for "apiKey" requires the location of the API key: header, query or cookie parameter' + ); + }); }); - describe('createSecuritySchemes', () => { - describe('API Keys', () => { - it('should add an API Key security scheme to components', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'api_key': { - type: 'apiKey', - name: 'Authorization', - in: 'header' - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes') - expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('api_key') - expect(definitionGenerator.openAPI.components.securitySchemes.api_key).to.have.property('type') - expect(definitionGenerator.openAPI.components.securitySchemes.api_key.type).to.be.equal('apiKey') - }); - - it('should throw an error when name is missing from an API Key scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'api_key': { - type: 'apiKey', - in: 'header' - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('Security Scheme for "apiKey" requires the name of the header, query or cookie parameter to be used') - }); - - it('should throw an error when in is missing from an API Key scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'api_key': { - type: 'apiKey', - name: 'Authorization', - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('Security Scheme for "apiKey" requires the location of the API key: header, query or cookie parameter') - }); - }); - - describe('HTTP', () => { - it('should add an HTTP security scheme to components', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'http_key': { - type: 'http', - scheme: 'basic' - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes') - expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('http_key') - }); - - it('should throw an error when scheme is missing from an HTTP scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'http_key': { - type: 'http', - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('Security Scheme for "http" requires scheme') - }); - }); + describe("HTTP", () => { + it("should add an HTTP security scheme to components", function () { + mockServerless.service.custom.documentation.securitySchemes = { + http_key: { + type: "http", + scheme: "basic", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.have.property( + "securitySchemes" + ); + expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an( + "object" + ); + expect( + definitionGenerator.openAPI.components.securitySchemes + ).to.have.property("http_key"); + }); + + it("should throw an error when scheme is missing from an HTTP scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + http_key: { + type: "http", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw('Security Scheme for "http" requires scheme'); + }); + }); - describe('openIdConnect', () => { - it('should add an openIdConnect security scheme to components', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'openIdConnect_key': { - type: 'openIdConnect', - openIdConnectUrl: 'http://example.com' - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes') - expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('openIdConnect_key') - }); - - it('should throw an error when openIdConnectUrl is missing from an openIdConnect scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'openIdConnect_key': { - type: 'openIdConnect', - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('Security Scheme for "openIdConnect" requires openIdConnectUrl') - }); - }); + describe("openIdConnect", () => { + it("should add an openIdConnect security scheme to components", function () { + mockServerless.service.custom.documentation.securitySchemes = { + openIdConnect_key: { + type: "openIdConnect", + openIdConnectUrl: "http://example.com", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.have.property( + "securitySchemes" + ); + expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an( + "object" + ); + expect( + definitionGenerator.openAPI.components.securitySchemes + ).to.have.property("openIdConnect_key"); + }); + + it("should throw an error when openIdConnectUrl is missing from an openIdConnect scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + openIdConnect_key: { + type: "openIdConnect", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw( + 'Security Scheme for "openIdConnect" requires openIdConnectUrl' + ); + }); + }); - describe('oauth2', () => { - it('should add an oauth2 security scheme to components', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - implicit: { - authorizationUrl: 'http://example.org/api/oauth/dialog', - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes') - expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('oAuth2_key') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key).to.have.property('type') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key).to.have.property('flows') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows).to.have.property('implicit') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows.implicit).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows.implicit).to.have.property('scopes') - expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows.implicit.scopes).to.be.an('object') - }); - - it('should throw an error when flows is missing from an oauth2 scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('Security Scheme for "oauth2" requires flows') - }); - - it('should throw an error when authorizationUrl is missing from an oauth2 implicit flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - implicit: { - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 implicit flow requires an authorizationUrl') - }); - - it('should throw an error when authorizationUrl is missing from an oauth2 authorizationCode flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - authorizationCode: { - tokenUrl: 'http://example.com', - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 authorizationCode flow requires an authorizationUrl') - }); - - it('should throw an error when tokenUrl is missing from an oauth2 authorizationCode flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - authorizationCode: { - authorizationUrl: 'http://example.org/api/oauth/dialog', - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 authorizationCode flow requires a tokenUrl') - }); - - it('should throw an error when tokenUrl is missing from an oauth2 password flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - password: { - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 password flow requires a tokenUrl') - }); - - it('should throw an error when tokenUrl is missing from an oauth2 clientCredentials flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - clientCredentials: { - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 clientCredentials flow requires a tokenUrl') - }); - - it('should throw an error when scopes is missing from an oauth2 clientCredentials flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - clientCredentials: { - tokenUrl: 'http://example.com', - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 clientCredentials flow requires scopes') - }); - - it('should throw an error when scopes is missing from an oauth2 authorizationCode flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - authorizationCode: { - tokenUrl: 'http://example.com', - authorizationUrl: 'http://example.org/api/oauth/dialog', - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 authorizationCode flow requires scopes') - }); - - it('should throw an error when scopes is missing from an oauth2 password flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - password: { - tokenUrl: 'http://example.com', - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 password flow requires scopes') - }); - - it('should throw an error when scopes is missing from an oauth2 implicit flow scheme', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - implicit: { - authorizationUrl: 'http://example.org/api/oauth/dialog', - } - } - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - }).to.throw('oAuth2 implicit flow requires scopes') - }); - }); + describe("oauth2", () => { + it("should add an oauth2 security scheme to components", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + implicit: { + authorizationUrl: "http://example.org/api/oauth/dialog", + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.have.property( + "securitySchemes" + ); + expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an( + "object" + ); + expect( + definitionGenerator.openAPI.components.securitySchemes + ).to.have.property("oAuth2_key"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + ).to.be.an("object"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + ).to.have.property("type"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + ).to.have.property("flows"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + .flows + ).to.be.an("object"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + .flows + ).to.have.property("implicit"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + .flows.implicit + ).to.be.an("object"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + .flows.implicit + ).to.have.property("scopes"); + expect( + definitionGenerator.openAPI.components.securitySchemes.oAuth2_key + .flows.implicit.scopes + ).to.be.an("object"); + }); + + it("should throw an error when flows is missing from an oauth2 scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw('Security Scheme for "oauth2" requires flows'); + }); + + it("should throw an error when authorizationUrl is missing from an oauth2 implicit flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + implicit: { + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 implicit flow requires an authorizationUrl"); + }); + + it("should throw an error when authorizationUrl is missing from an oauth2 authorizationCode flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + authorizationCode: { + tokenUrl: "http://example.com", + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw( + "oAuth2 authorizationCode flow requires an authorizationUrl" + ); + }); + + it("should throw an error when tokenUrl is missing from an oauth2 authorizationCode flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + authorizationCode: { + authorizationUrl: "http://example.org/api/oauth/dialog", + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 authorizationCode flow requires a tokenUrl"); + }); + + it("should throw an error when tokenUrl is missing from an oauth2 password flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + password: { + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 password flow requires a tokenUrl"); + }); + + it("should throw an error when tokenUrl is missing from an oauth2 clientCredentials flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + clientCredentials: { + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 clientCredentials flow requires a tokenUrl"); + }); + + it("should throw an error when scopes is missing from an oauth2 clientCredentials flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + clientCredentials: { + tokenUrl: "http://example.com", + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 clientCredentials flow requires scopes"); + }); + + it("should throw an error when scopes is missing from an oauth2 authorizationCode flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + authorizationCode: { + tokenUrl: "http://example.com", + authorizationUrl: "http://example.org/api/oauth/dialog", + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 authorizationCode flow requires scopes"); + }); + + it("should throw an error when scopes is missing from an oauth2 password flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + password: { + tokenUrl: "http://example.com", + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 password flow requires scopes"); + }); + + it("should throw an error when scopes is missing from an oauth2 implicit flow scheme", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + implicit: { + authorizationUrl: "http://example.org/api/oauth/dialog", + }, + }, + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + }).to.throw("oAuth2 implicit flow requires scopes"); + }); + }); - describe('Multiple Schemes', () => { - it('should add an oauth2 and an apiKey security scheme to components', function() { - mockServerless.service.custom.documentation.securitySchemes = { - 'oAuth2_key': { - type: 'oauth2', - flows: { - implicit: { - authorizationUrl: 'http://example.org/api/oauth/dialog', - scopes: { - 'write:pets': 'modify pets in your account', - 'read:pets': 'read your pets' - } - } - } - }, - 'api_key': { - type: 'apiKey', - name: 'Authorization', - in: 'header' - } - } - - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes) - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.be.an('object') - expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes') - expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object') - expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('oAuth2_key') - expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('api_key') - }); - }); + describe("Multiple Schemes", () => { + it("should add an oauth2 and an apiKey security scheme to components", function () { + mockServerless.service.custom.documentation.securitySchemes = { + oAuth2_key: { + type: "oauth2", + flows: { + implicit: { + authorizationUrl: "http://example.org/api/oauth/dialog", + scopes: { + "write:pets": "modify pets in your account", + "read:pets": "read your pets", + }, + }, + }, + }, + api_key: { + type: "apiKey", + name: "Authorization", + in: "header", + }, + }; + + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createSecuritySchemes( + mockServerless.service.custom.documentation.securitySchemes + ); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.be.an("object"); + expect(definitionGenerator.openAPI.components).to.have.property( + "securitySchemes" + ); + expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an( + "object" + ); + expect( + definitionGenerator.openAPI.components.securitySchemes + ).to.have.property("oAuth2_key"); + expect( + definitionGenerator.openAPI.components.securitySchemes + ).to.have.property("api_key"); + }); }); + }); - describe('createTags', () => { - it('should add tags to the openAPI object correctly', function() { - mockServerless.service.custom.documentation.tags = [{name: 'tag1'}] + describe("createTags", () => { + it("should add tags to the openAPI object correctly", function () { + mockServerless.service.custom.documentation.tags = [{ name: "tag1" }]; - const definitionGenerator = new DefinitionGenerator(mockServerless) - definitionGenerator.createTags() + const definitionGenerator = new DefinitionGenerator(mockServerless); + definitionGenerator.createTags(); - expect(definitionGenerator.openAPI).to.be.an('object') - expect(definitionGenerator.openAPI.tags).to.be.an('array') - expect(definitionGenerator.openAPI.tags[0].name).to.be.equal('tag1') - }); + expect(definitionGenerator.openAPI).to.be.an("object"); + expect(definitionGenerator.openAPI.tags).to.be.an("array"); + expect(definitionGenerator.openAPI.tags[0].name).to.be.equal("tag1"); + }); - it('should not add tags when they are not defined', function() { - const definitionGenerator = new DefinitionGenerator(mockServerless) - expect(() => { - definitionGenerator.createTags() - }).to.throw() - }); + it("should not add tags when they are not defined", function () { + const definitionGenerator = new DefinitionGenerator(mockServerless); + expect(() => { + definitionGenerator.createTags(); + }).to.throw(); }); + }); }); From 538a077a278b69bd74b63aef73b6446c507dfd3a Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Mon, 17 Jun 2024 10:22:14 +0100 Subject: [PATCH 2/6] add test rules --- test/helpers/redocly.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 test/helpers/redocly.json diff --git a/test/helpers/redocly.json b/test/helpers/redocly.json new file mode 100644 index 0000000..1c64f6c --- /dev/null +++ b/test/helpers/redocly.json @@ -0,0 +1,4 @@ +{ + "spec": "error", + "operation-2xx-response": "warn" +} From df0ba6c15b0748b31ad5385b5e4b01c966ad0842 Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Mon, 17 Jun 2024 10:25:15 +0100 Subject: [PATCH 3/6] use rules provided by the user --- src/definitionGenerator.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/definitionGenerator.js b/src/definitionGenerator.js index 3c10c30..2945813 100644 --- a/src/definitionGenerator.js +++ b/src/definitionGenerator.js @@ -69,6 +69,19 @@ class DefinitionGenerator { }, }; + try { + this.REDOCLY_RULES = require(path.resolve("options", "redocly.json")); + } catch (err) { + this.REDOCLY_RULES = { + spec: "error", + "path-parameters-defined": "error", + "operation-2xx-response": "error", + "operation-4xx-response": "error", + "operation-operationId-unique": "error", + "path-declaration-must-exist": "error", + }; + } + try { this.refParserOptions = require(path.resolve("options", "ref-parser.js")); } catch (err) { @@ -1003,16 +1016,7 @@ class DefinitionGenerator { async validate() { const config = await createConfig({ apis: {}, - // styleguide: { - rules: { - spec: "error", - "path-parameters-defined": "error", - "operation-2xx-response": "error", - "operation-4xx-response": "error", - "operation-operationId-unique": "error", - "path-declaration-must-exist": "error", - }, - // }, + rules: this.REDOCLY_RULES, }); const apiDesc = stringifyYaml(this.openAPI); From 0dc3b55d7fb0bd5974c0d18063298fbb22f5e5fa Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Mon, 17 Jun 2024 10:51:57 +0100 Subject: [PATCH 4/6] make sure we're removing the resolve cache --- test/unit/definitionGenerator.spec.js | 6 ++++++ test/unit/openAPIGenerator.spec.js | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/test/unit/definitionGenerator.spec.js b/test/unit/definitionGenerator.spec.js index 6038ace..f496e2a 100644 --- a/test/unit/definitionGenerator.spec.js +++ b/test/unit/definitionGenerator.spec.js @@ -13,11 +13,17 @@ describe("DefinitionGenerator", () => { const v4 = new RegExp( /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i ); + beforeEach(function () { mockServerless = JSON.parse(JSON.stringify(serverlessMock)); Object.assign(mockServerless.service.custom.documentation, modelsDocument); }); + after(function () { + delete require + .cache[require.resolve(`${path.resolve("options")}/redocly.json`)]; + }); + describe("constructor", () => { it("should return a definitionGenerator", function () { const expected = new DefinitionGenerator(mockServerless, {}); diff --git a/test/unit/openAPIGenerator.spec.js b/test/unit/openAPIGenerator.spec.js index dbe98b6..287a8b7 100644 --- a/test/unit/openAPIGenerator.spec.js +++ b/test/unit/openAPIGenerator.spec.js @@ -1,6 +1,8 @@ "use strict"; const fs = require("fs"); +const path = require("path"); + const PostmanGenerator = require("openapi-to-postmanv2"); const sinon = require("sinon"); const expect = require("chai").expect; @@ -14,6 +16,7 @@ const OpenAPIGenerator = require("../../src/openAPIGenerator"); describe("OpenAPIGenerator", () => { let sls, logOutput; + beforeEach(function () { sls = { service: { @@ -58,6 +61,11 @@ describe("OpenAPIGenerator", () => { }; }); + after(function () { + delete require + .cache[require.resolve(`${path.resolve("options")}/redocly.json`)]; + }); + describe("generationAndValidation", () => { it("should correctly generate a valid openAPI document", async function () { const succSpy = sinon.spy(logOutput.log, "success"); @@ -168,9 +176,11 @@ describe("OpenAPIGenerator", () => { const errSpy = sinon.spy(logOutput.log, "error"); Object.assign(sls.service, basicDocumentation); + const getAllFuncsStub = sinon .stub(sls.service, "getAllFunctions") .returns(["createUser"]); + const basicInvalidFunction = JSON.parse( JSON.stringify(basicValidFunction) ); From bf93125632f84c90e8b07149f30ca32048727d79 Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Mon, 17 Jun 2024 10:59:17 +0100 Subject: [PATCH 5/6] instructions for configuring redocly rules --- README.md | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2aa9701..e02cf8e 100644 --- a/README.md +++ b/README.md @@ -942,16 +942,31 @@ This will set the `Cache-Control` Response Header to have a value of "no-store" Validation for the OpenAPI Description is now (as of 0.0.90) done by [Redocly](https://redocly.com/). This is a slightly less opinionated validator for an OpenAPI Description, it should result in less errors around "YAML Anchors". It's also a maintained library, and has support for OpenAPI 3.1.0 which I hope to be able to support very soon. +I am making use of https://www.npmjs.com/package/@redocly/openapi-core, which I have been warned is likely to change. If you notice anything going wrong with validation of your OpenAPI Description, feel free to open an issue here. I make active use of this library, so will hopefully come across those issues too. + +### Rules + I have configured the validator to use these Rules: -* [spec](https://redocly.com/docs/cli/rules/spec/) -* [path-parameters-defined](https://redocly.com/docs/cli/rules/path-parameters-defined/) -* [operation-2xx-response](https://redocly.com/docs/cli/rules/operation-2xx-response/) -* [operation-4xx-response](https://redocly.com/docs/cli/rules/operation-4xx-response/) -* [operation-operationId-unique](https://redocly.com/docs/cli/rules/operation-operationid-unique/) -* [path-declaration-must-exist](https://redocly.com/docs/cli/rules/path-declaration-must-exist/) +- [spec](https://redocly.com/docs/cli/rules/spec/) +- [path-parameters-defined](https://redocly.com/docs/cli/rules/path-parameters-defined/) +- [operation-2xx-response](https://redocly.com/docs/cli/rules/operation-2xx-response/) +- [operation-4xx-response](https://redocly.com/docs/cli/rules/operation-4xx-response/) +- [operation-operationId-unique](https://redocly.com/docs/cli/rules/operation-operationid-unique/) +- [path-declaration-must-exist](https://redocly.com/docs/cli/rules/path-declaration-must-exist/) -I am making use of https://www.npmjs.com/package/@redocly/openapi-core, which I have been warned is likely to change. If you notice anything going wrong with validation of your OpenAPI Description, feel free to open an issue here. I make active use of this library, so will hopefully come across those issues too. +However, you can configure your own rules from the [ruleset available on the Redocly site](https://redocly.com/docs/cli/rules/built-in-rules/). To do this, you will need to create a `redocly.json` file within an `options` folder. The file should look like: + +```json +{ + "spec": "error", + "path-parameters-defined": "error", + "operation-2xx-response": "error", + "operation-4xx-response": "error", + "operation-operationId-unique": "error", + "path-declaration-must-exist": "error" +} +``` ## Example configuration From a7f784ab00b5055c3d7e23c7307ac033327f9636 Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Mon, 17 Jun 2024 10:59:30 +0100 Subject: [PATCH 6/6] 0.0.100 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9cd5634..b2b5c2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "serverless-openapi-documenter", - "version": "0.0.97", + "version": "0.0.100", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 4aeacdc..07c311d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless-openapi-documenter", - "version": "0.0.97", + "version": "0.0.100", "description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config", "main": "index.js", "keywords": [