diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index 0fb5cafa..f441a5d0 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -83,7 +83,6 @@ export default class Operation extends PureComponent { let operation = operationProps.getIn(["op"]) let responses = operation.get("responses") - let produces = operation.get("produces") let parameters = getList(operation, ["parameters"]) let operationScheme = specSelectors.operationScheme(path, method) let isShownKey = ["operations", tag, operationId] @@ -216,7 +215,7 @@ export default class Operation extends PureComponent { specSelectors={ specSelectors } oas3Actions={oas3Actions} specActions={ specActions } - produces={ produces } + produces={specSelectors.producesOptionsFor([path, method]) } producesValue={ specSelectors.currentProducesFor([path, method]) } specPath={specPath.push("responses")} path={ path } diff --git a/src/core/components/parameter-row.jsx b/src/core/components/parameter-row.jsx index 31b38f93..713df170 100644 --- a/src/core/components/parameter-row.jsx +++ b/src/core/components/parameter-row.jsx @@ -129,7 +129,7 @@ export default class ParameterRow extends Component { : { let url = state.get("url") let matchResult = url.match(/^([a-z][a-z0-9+\-.]*):/) diff --git a/test/core/plugins/spec/selectors.js b/test/core/plugins/spec/selectors.js index 412407b2..2bb603ab 100644 --- a/test/core/plugins/spec/selectors.js +++ b/test/core/plugins/spec/selectors.js @@ -7,7 +7,7 @@ import { contentTypeValues, operationScheme, specJsonWithResolvedSubtrees, - operationConsumes + producesOptionsFor, } from "corePlugins/spec/selectors" import Petstore from "./assets/petstore.json" @@ -15,7 +15,8 @@ import { operationWithMeta, parameterWithMeta, parameterWithMetaByIdentity, - parameterInclusionSettingFor + parameterInclusionSettingFor, + consumesOptionsFor } from "../../../../src/core/plugins/spec/selectors" describe("spec plugin - selectors", function(){ @@ -253,34 +254,6 @@ describe("spec plugin - selectors", function(){ }) - describe("operationConsumes", function(){ - it("should return the operationConsumes for an operation", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: { - consumes: [ - "application/xml", - "application/something-else" - ] - } - } - } - } - }) - - // When - let contentTypes = operationConsumes(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS()).toEqual([ - "application/xml", - "application/something-else" - ]) - }) - }) - describe("operationScheme", function(){ it("should return the correct scheme for a remote spec that doesn't specify a scheme", function(){ @@ -751,4 +724,264 @@ describe("spec plugin - selectors", function(){ expect(result).toEqual(true) }) }) + describe("producesOptionsFor", function() { + it("should return an operation produces value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + produces: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should return a path item produces value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + produces: [ + "path-item/one", + "path-item/two", + ] + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) + it("should return a global produces value", function () { + const state = fromJS({ + json: { + produces: [ + "global/one", + "global/two", + ], + paths: { + "/": { + "get": { + description: "my operation" + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "global/one", + "global/two", + ]) + }) + it("should favor an operation produces value over a path-item value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + produces: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation", + produces: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should favor a path-item produces value over a global value", function () { + const state = fromJS({ + json: { + produces: [ + "global/one", + "global/two", + ], + paths: { + "/": { + produces: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation" + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) + }) + describe("consumesOptionsFor", function() { + it("should return an operation consumes value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should return a path item consumes value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + consumes: [ + "path-item/one", + "path-item/two", + ] + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) + it("should return a global consumes value", function () { + const state = fromJS({ + json: { + consumes: [ + "global/one", + "global/two", + ], + paths: { + "/": { + "get": { + description: "my operation" + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "global/one", + "global/two", + ]) + }) + it("should favor an operation consumes value over a path-item value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + consumes: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should favor a path-item consumes value over a global value", function () { + const state = fromJS({ + json: { + consumes: [ + "global/one", + "global/two", + ], + paths: { + "/": { + consumes: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation" + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) + }) }) diff --git a/test/e2e-cypress/static/documents/bugs/5043/status.yaml b/test/e2e-cypress/static/documents/bugs/5043/status.yaml new file mode 100644 index 00000000..52d8c374 --- /dev/null +++ b/test/e2e-cypress/static/documents/bugs/5043/status.yaml @@ -0,0 +1,17 @@ +--- +paths: + findByStatus: + get: + tags: + - "pet" + summary: "Finds Pets by status" + description: "Multiple status values can be provided with comma separated strings" + operationId: "findPetsByStatus" + parameters: + - name: "status" + in: "body" + schema: + type: string + responses: + 200: + description: ok \ No newline at end of file diff --git a/test/e2e-cypress/static/documents/bugs/5043/swagger.yaml b/test/e2e-cypress/static/documents/bugs/5043/swagger.yaml new file mode 100644 index 00000000..7adabae7 --- /dev/null +++ b/test/e2e-cypress/static/documents/bugs/5043/swagger.yaml @@ -0,0 +1,44 @@ +swagger: "2.0" +info: + description: "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters." + version: "1.0.0" + title: "Swagger Petstore" + 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" +host: "petstore.swagger.io" +basePath: "/v2" +produces: + - application/json + - application/xml + - text/csv +consumes: + - application/json + - application/xml + - text/csv +schemes: +- "https" +- "http" +paths: + /pet: + post: + tags: + - "pet" + summary: "Add a new pet to the store" + description: "" + operationId: "addPet" + parameters: + - in: "body" + name: "body" + description: "Pet object that needs to be added to the store" + required: true + schema: + $ref: "#/definitions/Pet" + responses: + 405: + description: "Invalid input" + /pet/findByStatus: + $ref: "status.yaml#/paths/findByStatus" \ No newline at end of file diff --git a/test/e2e-cypress/tests/bugs/5043.js b/test/e2e-cypress/tests/bugs/5043.js new file mode 100644 index 00000000..d0f2361c --- /dev/null +++ b/test/e2e-cypress/tests/bugs/5043.js @@ -0,0 +1,32 @@ +import repeat from "lodash/repeat" + +describe("#5043: path-level $ref path items should inherit global consumes/produces", () => { + it("should render consumes options correctly", () => { + cy + .visit("/?url=/documents/bugs/5043/swagger.yaml") + .get("#operations-pet-findPetsByStatus") + .click() + .get(".try-out__btn") + .click() + .get(".content-type") + .contains("application/json") + .get(".content-type") + .contains("application/xml") + .get(".content-type") + .contains("text/csv") + }) + it("should render produces options correctly", () => { + cy + .visit("/?url=/documents/bugs/5043/swagger.yaml") + .get("#operations-pet-findPetsByStatus") + .click() + .get(".try-out__btn") + .click() + .get(".body-param-content-type select") + .contains("application/json") + .get(".body-param-content-type select") + .contains("application/xml") + .get(".body-param-content-type select") + .contains("text/csv") + }) +}) \ No newline at end of file