diff --git a/src/core/plugins/oas3/components/request-body.jsx b/src/core/plugins/oas3/components/request-body.jsx index 9b652ca8f33..749f861f0e6 100644 --- a/src/core/plugins/oas3/components/request-body.jsx +++ b/src/core/plugins/oas3/components/request-body.jsx @@ -150,39 +150,53 @@ const RequestBody = ({ { - Map.isMap(bodyProperties) && bodyProperties.entrySeq().map(([key, prop]) => { - if (prop.get("readOnly")) return + Map.isMap(bodyProperties) && bodyProperties.entrySeq().map(([key, schema]) => { + if (schema.get("readOnly")) return + + const schemaWithoutKeywords = schema.filter((v, k) => k !== "oneOf" + && k !== "anyOf" + && k !== "$$ref" + ) - let commonExt = showCommonExtensions ? getCommonExtensions(prop) : null + if (schemaWithoutKeywords.size === 0) { + const oneOf = schema.get("oneOf") + const anyOf = schema.get("anyOf") + const nestedSchema = List.isList(oneOf) + ? oneOf.get(0) + : List.isList(anyOf) + ? anyOf.get(0) + : null + + if (Map.isMap(nestedSchema)) { + schema = nestedSchema + } + } + + let commonExt = showCommonExtensions ? getCommonExtensions(schema) : null const required = schemaForMediaType.get("required", List()).includes(key) - const type = prop.get("type") - const format = prop.get("format") - const description = prop.get("description") + const type = schema.get("type") + const format = schema.get("format") + const description = schema.get("description") const currentValue = requestBodyValue.getIn([key, "value"]) const currentErrors = requestBodyValue.getIn([key, "errors"]) || requestBodyErrors const included = requestBodyInclusionSetting.get(key) || false - const useInitialValFromSchemaSamples = prop.has("default") - || prop.has("example") - || prop.hasIn(["items", "example"]) - || prop.hasIn(["items", "default"]) - const useInitialValFromEnum = prop.has("enum") && (prop.get("enum").size === 1 || required) - const useInitialValue = useInitialValFromSchemaSamples || useInitialValFromEnum - - let initialValue = "" - if (type === "array" && !useInitialValue) { - initialValue = [] + let initialValue = fn.getSampleSchema(schema, false, { + includeWriteOnly: true + }) + + if (initialValue === false) { + initialValue = "false" } - if (type === "object" || useInitialValue) { - // TODO: what about example or examples from requestBody could be passed as exampleOverride - initialValue = fn.getSampleSchema(prop, false, { - includeWriteOnly: true - }) + + if (initialValue === 0) { + initialValue = "0" } if (typeof initialValue !== "string" && type === "object") { initialValue = stringify(initialValue) } + if (typeof initialValue === "string" && type === "array") { initialValue = JSON.parse(initialValue) } @@ -201,7 +215,7 @@ const RequestBody = ({ {!showCommonExtensions || !commonExt.size ? null : commonExt.entrySeq().map(([key, v]) => )}
- { prop.get("deprecated") ? "deprecated": null } + { schema.get("deprecated") ? "deprecated": null }
@@ -210,7 +224,7 @@ const RequestBody = ({ { .get(".try-out__btn") .click() // Request Body + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .json-schema-form-item-remove") + .click() .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input") .should("be.checked") + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description select") + .select("--") .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description .parameter__empty_value_toggle input") .should("be.checked") }) @@ -49,6 +53,8 @@ describe("OpenAPI 3.0 Allow Empty Values in Request Body", () => { .get(".try-out__btn") .click() // Request Body + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .json-schema-form-item-remove") + .click() .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input") .should("be.checked") .uncheck() @@ -67,9 +73,11 @@ describe("OpenAPI 3.0 Allow Empty Values in Request Body", () => { // Expand Try It Out .get(".try-out__btn") .click() - // add item to pass required validation - .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button") + // Remove example values + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .json-schema-form-item-remove") .click() + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description select") + .select("--") // Execute .get(".execute.opblock-control__btn") .click() @@ -92,11 +100,11 @@ describe("OpenAPI 3.0 Allow Empty Values in Request Body", () => { .get(".try-out__btn") .click() // Request Body + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .json-schema-form-item-remove") + .click() .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input") .uncheck() // add item to pass required validation - .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button") - .click() .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) input") .clear() // Execute @@ -122,15 +130,14 @@ describe("OpenAPI 3.0 Allow Empty Values in Request Body", () => { .get(".try-out__btn") .click() // Request Body + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .json-schema-form-item-remove") + .click() .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input") .uncheck() + .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description select") + .select("--") .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description .parameter__empty_value_toggle input") .uncheck() - // add item to pass required validation - .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button") - .click() - .get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) input") - .clear() // Execute .get(".execute.opblock-control__btn") .click() diff --git a/test/e2e-cypress/e2e/features/oas3-request-body-required.cy.js b/test/e2e-cypress/e2e/features/oas3-request-body-required.cy.js index 7fdd705ffa3..4da95e67f3c 100644 --- a/test/e2e-cypress/e2e/features/oas3-request-body-required.cy.js +++ b/test/e2e-cypress/e2e/features/oas3-request-body-required.cy.js @@ -26,6 +26,7 @@ describe("OpenAPI 3.0 Validation for Required Request Body and Request Body Fiel .get( ".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(1) > .parameters-col_description input" ) + .clear() .should("not.have.class", "invalid") // Execute .get(".execute.opblock-control__btn") @@ -163,11 +164,6 @@ describe("OpenAPI 3.0 Validation for Required Request Body and Request Body Fiel // Expand Try It Out .get(".try-out__btn") .click() - // add item to get input - .get( - ".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button" - ) - .click() // Execute .get(".execute.opblock-control__btn") .click() @@ -217,15 +213,6 @@ describe("OpenAPI 3.0 Validation for Required Request Body and Request Body Fiel ".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input" ) .should("not.have.class", "invalid") - // add item to get input, just an extra confirmation of non-invalid class - .get( - ".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button" - ) - .click() - .get( - ".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description input" - ) - .should("not.have.class", "invalid") }) it("after application/x-www-form-urlencoded 'invalid' error, on switch content type to application/json, SHOULD be free of errors", () => { cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml") diff --git a/test/e2e-cypress/e2e/features/plugins/oas3/one-of-any-of-example.cy.js b/test/e2e-cypress/e2e/features/plugins/oas3/one-of-any-of-example.cy.js new file mode 100644 index 00000000000..357121ac146 --- /dev/null +++ b/test/e2e-cypress/e2e/features/plugins/oas3/one-of-any-of-example.cy.js @@ -0,0 +1,28 @@ +/** + * @prettier + */ + +describe("OpenAPI 3.0 oneOf and anyOf example", () => { + it("should show example values for multipart/form-data and application/x-www-form-urlencoded content types", () => { + cy.visit("/?url=/documents/features/oas3-one-of-any-of-example.yaml").then( + () => { + cy.contains("/documentsWithCombineOneOf") + .click() + .get(".try-out__btn") + .click() + .get("textarea") + .contains("documentDate") + .should("exist") + cy.contains("/documentsWithCombineOneOf").click() + cy.contains("/documentsWithCombineAnyOf") + .click() + .get(".try-out__btn") + .contains("Try it out") + .click() + .get("textarea") + .contains("documentDate") + .should("exist") + } + ) + }) +}) diff --git a/test/e2e-cypress/static/documents/features/oas3-one-of-any-of-example.yaml b/test/e2e-cypress/static/documents/features/oas3-one-of-any-of-example.yaml new file mode 100644 index 00000000000..9adbbd9c5ba --- /dev/null +++ b/test/e2e-cypress/static/documents/features/oas3-one-of-any-of-example.yaml @@ -0,0 +1,197 @@ +openapi: 3.0.3 +info: + title: Example app + description: This is my test applicaiton + version: 1.0.0 + contact: + name: John Doe + email: jonhdoe@contact.com +servers: + - url: https://dev.app.com/appApplicationName + description: DEV +paths: + /documentsWithCombineOneOf: + post: + description: '' + summary: Add a document - KO + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/ModelPostDocumentOneOfCombineModelFile' + operationId: testOneOf + security: + - Basic: [] + tags: [] + responses: + '200': + $ref: '#/components/responses/Default' + /documentsWithCombineAnyOf: + post: + description: '' + summary: Add a document - KO + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ModelPostDocumentAnyOfCombineModelFile' + operationId: testAnyOf + security: + - Basic: [] + tags: [] + responses: + '200': + $ref: '#/components/responses/Default' +components: + schemas: + AbstractModelPostDocument: + type: object + properties: + title: + type: string + default: '' + maxLength: 64 + example: MyDocument.pdf' + category: + type: string + pattern: '' + type: + type: string + description: Type depends on category + issuingApplicationId: + type: string + enum: + - App1 + - App2 + - App3 + - App4 + documentDate: + type: string + description: >- + Creation date of the document. Example : For ID card, it is the + issuing date of the card. + format: date + sharedWith: + type: array + items: + type: string + enum: + - CustomerPortal + - PartnerPortal + uniqueItems: true + minItems: 0 + maxItems: 2 + required: + - title + - category + - type + - documentDate + - file + ModelPostDocumentPolicy: + allOf: + - $ref: '#/components/schemas/AbstractModelPostDocument' + - type: object + properties: + policyNumber: + type: string + description: Policy Number + example: '132456' + minLength: 1 + maxLength: 36 + pattern: '' + description: Metadata for policy documents + required: + - policyNumber + ModelPostDocumentCustomer: + allOf: + - $ref: '#/components/schemas/AbstractModelPostDocument' + - type: object + properties: + customerNumber: + type: number + description: Customer Number + exclusiveMinimum: true + minimum: 0 + exclusiveMaximum: true + maximum: 99999999999999 + organisationName: + type: string + enum: + - Organisation1 + - Organisation2 + - Organisation3 + description: Organisation Name + required: + - organisationName + - customerNumber + description: Metadata for Customer Documents + ModelPostDocumentInvoice: + allOf: + - $ref: '#/components/schemas/AbstractModelPostDocument' + - type: object + properties: + invoiceNumber: + type: string + description: Invoice Number + example: '132456' + minLength: 1 + maxLength: 36 + pattern: '' + amount: + type: number + example: 1234.56 + description: Invoice Amount + description: Metadata for invoice documents + required: + - amount + - invoiceNumber + ModelPostDocumentOneOf: + oneOf: + - $ref: '#/components/schemas/ModelPostDocumentPolicy' + - $ref: '#/components/schemas/ModelPostDocumentCustomer' + - $ref: '#/components/schemas/ModelPostDocumentInvoice' + ModelFile: + type: object + properties: + content: + type: string + format: binary + required: + - content + ModelPostDocumentOneOfCombineModelFile: + allOf: + - $ref: '#/components/schemas/ModelFile' + - type: object + properties: + metadata: + $ref: '#/components/schemas/ModelPostDocumentOneOf' + required: + - metadata + ModelPostDocumentAnyOf: + anyOf: + - $ref: '#/components/schemas/ModelPostDocumentPolicy' + - $ref: '#/components/schemas/ModelPostDocumentCustomer' + - $ref: '#/components/schemas/ModelPostDocumentInvoice' + ModelPostDocumentAnyOfCombineModelFile: + allOf: + - $ref: '#/components/schemas/ModelFile' + - type: object + properties: + metadata: + $ref: '#/components/schemas/ModelPostDocumentAnyOf' + required: + - metadata + securitySchemes: + Basic: + type: http + scheme: basic + responses: + Default: + description: Not needed + headers: {} + content: + application/json: + schema: + type: string + description: not needed +tags: []