From ceecfede53d3bc5a9e5611d27feb7ca1aef43c7e Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Fri, 11 Apr 2025 14:38:57 +0200 Subject: [PATCH 1/2] feat(oas31): display file upload input when contentMediaType or contentEncoding is present Refs #9278 --- src/core/plugins/oas31/oas3-extensions/fn.js | 29 +++++++- .../oas31-request-body-upload-file.cy.js | 70 +++++++++++++++++++ .../oas31-request-body-upload-file.yaml | 42 +++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/src/core/plugins/oas31/oas3-extensions/fn.js b/src/core/plugins/oas31/oas3-extensions/fn.js index f032e228247..bd5a78e9e8a 100644 --- a/src/core/plugins/oas31/oas3-extensions/fn.js +++ b/src/core/plugins/oas31/oas3-extensions/fn.js @@ -1,12 +1,39 @@ /** * @prettier */ +import { Map } from "immutable" +import isPlainObject from "lodash/isPlainObject" export const makeIsFileUploadIntended = (getSystem) => { const isFileUploadIntended = (schema, mediaType = null) => { const { fn } = getSystem() - return fn.isFileUploadIntendedOAS30(schema, mediaType) + const isFileUploadIntendedOAS30 = fn.isFileUploadIntendedOAS30( + schema, + mediaType + ) + + if (isFileUploadIntendedOAS30) { + return true + } + + const isSchemaImmutable = Map.isMap(schema) + + if (!isSchemaImmutable && !isPlainObject(schema)) { + return false + } + + const contentMediaType = isSchemaImmutable + ? schema.get("contentMediaType") + : schema.contentMediaType + const contentEncoding = isSchemaImmutable + ? schema.get("contentEncoding") + : schema.contentEncoding + + return ( + (contentMediaType && typeof contentMediaType === "string") || + (contentEncoding && typeof contentEncoding === "string") + ) } return isFileUploadIntended diff --git a/test/e2e-cypress/e2e/features/plugins/oas31/oas31-request-body-upload-file.cy.js b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-request-body-upload-file.cy.js index 4d1f9a254aa..56541204969 100644 --- a/test/e2e-cypress/e2e/features/plugins/oas31/oas31-request-body-upload-file.cy.js +++ b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-request-body-upload-file.cy.js @@ -199,6 +199,50 @@ describe("OpenAPI 3.1 Request Body upload file button", () => { }) }) + describe("schema contentMediaType is a non-empty string", () => { + beforeEach(() => { + cy.get("#operations-default-uploadSchemaContentMediaType").click() + }) + + it("should display description with the correct content type", () => { + cy.get( + ".opblock-section-request-body .opblock-description-wrapper i" + ).should( + "have.text", + "Example values are not available for application/x-custom media types." + ) + }) + + it("should display a file upload button", () => { + cy.get(".try-out__btn").click() + cy.get( + ".opblock-section-request-body .opblock-description-wrapper input" + ).should("have.prop", "type", "file") + }) + }) + + describe("schema contentEncoding is a non-empty string", () => { + beforeEach(() => { + cy.get("#operations-default-uploadSchemaContentEncoding").click() + }) + + it("should display description with the correct content type", () => { + cy.get( + ".opblock-section-request-body .opblock-description-wrapper i" + ).should( + "have.text", + "Example values are not available for application/x-custom media types." + ) + }) + + it("should display a file upload button", () => { + cy.get(".try-out__btn").click() + cy.get( + ".opblock-section-request-body .opblock-description-wrapper input" + ).should("have.prop", "type", "file") + }) + }) + describe("multipart/form-data object property with schema type string and format binary", () => { beforeEach(() => { cy.get("#operations-default-uploadPropertySchemaFormatBinary").click() @@ -254,4 +298,30 @@ describe("OpenAPI 3.1 Request Body upload file button", () => { ).should("have.prop", "type", "file") }) }) + + describe("multipart/form-data object property schema has contentMediaType with non-empty string", () => { + beforeEach(() => { + cy.get("#operations-default-uploadPropertySchemaContentMediaType").click() + }) + + it("should display a file upload button", () => { + cy.get(".try-out__btn").click() + cy.get( + ".opblock-section-request-body .opblock-description-wrapper input" + ).should("have.prop", "type", "file") + }) + }) + + describe("multipart/form-data object property schema has contentEncoding with non-empty string", () => { + beforeEach(() => { + cy.get("#operations-default-uploadPropertySchemaContentEncoding").click() + }) + + it("should display a file upload button", () => { + cy.get(".try-out__btn").click() + cy.get( + ".opblock-section-request-body .opblock-description-wrapper input" + ).should("have.prop", "type", "file") + }) + }) }) diff --git a/test/e2e-cypress/static/documents/features/oas31-request-body-upload-file.yaml b/test/e2e-cypress/static/documents/features/oas31-request-body-upload-file.yaml index 85c04608eef..ffbf658c17e 100644 --- a/test/e2e-cypress/static/documents/features/oas31-request-body-upload-file.yaml +++ b/test/e2e-cypress/static/documents/features/oas31-request-body-upload-file.yaml @@ -12,10 +12,14 @@ info: * schema type is `string` and format is `binary` (no matter what content type) * schema union type includes `string` and format is `byte` (no matter what content type) * schema union type includes `string` and format is `binary` (no matter what content type) + * schema `contentMediaType` is present and is a non-empty `string` + * schema `contentEncoding` is present and is a non-empty `string` * multipart/form-data object property schema type is `string` and format is `byte` * multipart/form-data object property schema type is `string` and format is `binary` * multipart/form-data object property schema union type includes `string` and format is `byte` * multipart/form-data object property schema union type includes `string` and format is `binary` + * multipart/form-data object property schema `contentMediaType` is present and is a non-empty `string` + * multipart/form-data object property schema `contentEncoding` is present and is a non-empty `string` version: "1.0.0" paths: /upload-application-octet-stream: @@ -96,6 +100,22 @@ paths: - object - string format: byte + /upload-schema-contentMediaType: + post: + operationId: uploadSchemaContentMediaType + requestBody: + content: + application/x-custom: + schema: + contentMediaType: application/x-custom + /upload-schema-contentEncoding: + post: + operationId: uploadSchemaContentEncoding + requestBody: + content: + application/x-custom: + schema: + contentEncoding: base64 /upload-property-schema-format-binary: post: operationId: uploadPropertySchemaFormatBinary @@ -148,3 +168,25 @@ paths: - object - string format: byte + /upload-property-schema-contentMediaType: + post: + operationId: uploadPropertySchemaContentMediaType + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + contentMediaType: application/x-custom + /upload-property-schema-contentEncoding: + post: + operationId: uploadPropertySchemaContentEncoding + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + contentEncoding: base64 From 18dbae61f274014aace9a8841de5118d8f68f3e6 Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Fri, 11 Apr 2025 15:32:29 +0200 Subject: [PATCH 2/2] refactor: explicitly check for empty string and add a comment --- src/core/plugins/oas31/oas3-extensions/fn.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core/plugins/oas31/oas3-extensions/fn.js b/src/core/plugins/oas31/oas3-extensions/fn.js index bd5a78e9e8a..db7d801704a 100644 --- a/src/core/plugins/oas31/oas3-extensions/fn.js +++ b/src/core/plugins/oas31/oas3-extensions/fn.js @@ -8,6 +8,12 @@ export const makeIsFileUploadIntended = (getSystem) => { const isFileUploadIntended = (schema, mediaType = null) => { const { fn } = getSystem() + /** + * Return `true` early if the media type indicates a file upload + * or if a combination of type: `string` and format: `binary/byte` is detected. + * This ensures support for empty Media Type Objects, + * as the schema check is performed later. + */ const isFileUploadIntendedOAS30 = fn.isFileUploadIntendedOAS30( schema, mediaType @@ -31,8 +37,8 @@ export const makeIsFileUploadIntended = (getSystem) => { : schema.contentEncoding return ( - (contentMediaType && typeof contentMediaType === "string") || - (contentEncoding && typeof contentEncoding === "string") + (typeof contentMediaType === "string" && contentMediaType !== "") || + (typeof contentEncoding === "string" && contentEncoding !== "") ) }