From e2be707d7ca739106c7ee5a6a6db2cb0643b3c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Gorej?= Date: Wed, 6 Mar 2024 14:20:45 +0100 Subject: [PATCH] fix(oas31): render responses with empty content field (#9664) Refs #9199 --- src/core/components/response.jsx | 22 ++--- .../json-schema-2020-12-samples/fn/main.js | 3 + src/core/plugins/oas31/after-load.js | 4 + .../oas31/oas31-response-empty-content.cy.js | 21 +++++ .../oas31-response-empty-media-type.cy.js | 21 +++++ .../oas31/oas31-response-no-content.cy.js | 21 +++++ .../configs/oas31-response-no-content.yaml | 3 + .../oas31-response-empty-content.yaml | 91 ++++++++++++++++++ .../oas31-response-empty-media-type.yaml | 92 +++++++++++++++++++ .../features/oas31-response-no-content.yaml | 91 ++++++++++++++++++ 10 files changed, 356 insertions(+), 13 deletions(-) create mode 100644 test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-content.cy.js create mode 100644 test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-media-type.cy.js create mode 100644 test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-no-content.cy.js create mode 100644 test/e2e-cypress/static/configs/oas31-response-no-content.yaml create mode 100644 test/e2e-cypress/static/documents/features/oas31-response-empty-content.yaml create mode 100644 test/e2e-cypress/static/documents/features/oas31-response-empty-media-type.yaml create mode 100644 test/e2e-cypress/static/documents/features/oas31-response-no-content.yaml diff --git a/src/core/components/response.jsx b/src/core/components/response.jsx index 5c529afc..7835f632 100644 --- a/src/core/components/response.jsx +++ b/src/core/components/response.jsx @@ -8,20 +8,16 @@ import { getKnownSyntaxHighlighterLanguage } from "core/utils/jsonParse" const getExampleComponent = ( sampleResponse, HighlightCode, getConfigs ) => { - if ( - sampleResponse !== undefined && - sampleResponse !== null - ) { - let language = null - let testValueForJson = getKnownSyntaxHighlighterLanguage(sampleResponse) - if (testValueForJson) { - language = "json" - } - return
+ if (sampleResponse == null) return null + + const testValueForJson = getKnownSyntaxHighlighterLanguage(sampleResponse) + const language = testValueForJson ? "json" : null + + return ( +
- } - return null + ) } export default class Response extends React.Component { @@ -171,7 +167,7 @@ export default class Response extends React.Component { shouldOverrideSchemaExample ? mediaTypeExample : undefined ) - let example = getExampleComponent( sampleResponse, HighlightCode, getConfigs ) + const example = getExampleComponent( sampleResponse, HighlightCode, getConfigs ) return ( diff --git a/src/core/plugins/json-schema-2020-12-samples/fn/main.js b/src/core/plugins/json-schema-2020-12-samples/fn/main.js index b923fbcd..c3f186f8 100644 --- a/src/core/plugins/json-schema-2020-12-samples/fn/main.js +++ b/src/core/plugins/json-schema-2020-12-samples/fn/main.js @@ -21,6 +21,9 @@ export const sampleFromSchemaGeneric = ( exampleOverride = undefined, respectXML = false ) => { + // there is nothing to generate schema from + if (schema == null && exampleOverride === undefined) return undefined + if (typeof schema?.toJS === "function") schema = schema.toJS() schema = typeCast(schema) diff --git a/src/core/plugins/oas31/after-load.js b/src/core/plugins/oas31/after-load.js index 51b4b619..7c34220c 100644 --- a/src/core/plugins/oas31/after-load.js +++ b/src/core/plugins/oas31/after-load.js @@ -27,6 +27,10 @@ function afterLoad({ fn, getSystem }) { createXMLExample: fn.jsonSchema202012.createXMLExample, memoizedSampleFromSchema: fn.jsonSchema202012.memoizedSampleFromSchema, memoizedCreateXMLExample: fn.jsonSchema202012.memoizedCreateXMLExample, + getJsonSampleSchema: fn.jsonSchema202012.getJsonSampleSchema, + getYamlSampleSchema: fn.jsonSchema202012.getYamlSampleSchema, + getXmlSampleSchema: fn.jsonSchema202012.getXmlSampleSchema, + getSampleSchema: fn.jsonSchema202012.getSampleSchema, }, getSystem() ) diff --git a/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-content.cy.js b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-content.cy.js new file mode 100644 index 00000000..449f37ed --- /dev/null +++ b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-content.cy.js @@ -0,0 +1,21 @@ +/** + * @prettier + */ + +describe("OpenAPI 3.1.0 response with empty content", () => { + it("should render a response", () => { + cy.visit( + "/?configUrl=/configs/oas31-response-no-content.yaml&url=/documents/features/oas31-response-empty-content.yaml" + ) + .get("#operations-Enterprise-get_enterprise_detail") + .click() + .get( + "#operations-Enterprise-get_enterprise_detail [data-code=404] .response-col_description__inner" + ) + .contains("No enterprise matching the requested ID could be found.") + .get( + "#operations-Enterprise-get_enterprise_detail [data-code=404] .model-example" + ) + .should("not.exist") + }) +}) diff --git a/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-media-type.cy.js b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-media-type.cy.js new file mode 100644 index 00000000..7539b9e2 --- /dev/null +++ b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-empty-media-type.cy.js @@ -0,0 +1,21 @@ +/** + * @prettier + */ + +describe("OpenAPI 3.1.0 response with empty Media Type Object", () => { + it("should render a response", () => { + cy.visit( + "/?configUrl=/configs/oas31-response-no-content.yaml&url=/documents/features/oas31-response-empty-media-type.yaml" + ) + .get("#operations-Enterprise-get_enterprise_detail") + .click() + .get( + "#operations-Enterprise-get_enterprise_detail [data-code=404] .response-col_description__inner" + ) + .contains("No enterprise matching the requested ID could be found.") + .get( + "#operations-Enterprise-get_enterprise_detail [data-code=404] .model-example" + ) + .should("not.exist") + }) +}) diff --git a/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-no-content.cy.js b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-no-content.cy.js new file mode 100644 index 00000000..35aaa328 --- /dev/null +++ b/test/e2e-cypress/e2e/features/plugins/oas31/oas31-response-no-content.cy.js @@ -0,0 +1,21 @@ +/** + * @prettier + */ + +describe("OpenAPI 3.1.0 response without content", () => { + it("should render a response", () => { + cy.visit( + "/?configUrl=/configs/oas31-response-no-content.yaml&url=/documents/features/oas31-response-no-content.yaml" + ) + .get("#operations-Enterprise-get_enterprise_detail") + .click() + .get( + "#operations-Enterprise-get_enterprise_detail [data-code=404] .response-col_description__inner" + ) + .contains("No enterprise matching the requested ID could be found.") + .get( + "#operations-Enterprise-get_enterprise_detail [data-code=404] .model-example" + ) + .should("not.exist") + }) +}) diff --git a/test/e2e-cypress/static/configs/oas31-response-no-content.yaml b/test/e2e-cypress/static/configs/oas31-response-no-content.yaml new file mode 100644 index 00000000..841b91d1 --- /dev/null +++ b/test/e2e-cypress/static/configs/oas31-response-no-content.yaml @@ -0,0 +1,3 @@ +defaultModelRendering: "model" +defaultModelExpandDepth: 0 +defaultModelsExpandDepth: -1 diff --git a/test/e2e-cypress/static/documents/features/oas31-response-empty-content.yaml b/test/e2e-cypress/static/documents/features/oas31-response-empty-content.yaml new file mode 100644 index 00000000..f6c9e12c --- /dev/null +++ b/test/e2e-cypress/static/documents/features/oas31-response-empty-content.yaml @@ -0,0 +1,91 @@ +openapi: '3.1.0' + +info: + title: Our API + description: extended description of Our API + version: 0.1.0 + +servers: + - url: http://localhost + description: included for completeness; not our actual url + +tags: + - name: Enterprise + description: Operations with Enterprise ID + +paths: + /v0/enterprise/{id}: + get: + tags: + - Enterprise + summary: Get detailed info about an enterprise. + description: | + Returns detailed information for the specified Enterprise ID. + + This operation may *only* be performed by a **platform admin** or a + client with sufficient permissions. + operationId: get_enterprise_detail + parameters: + - $ref: '#/components/parameters/traceIDHeader' + - $ref: '#/components/parameters/enterpriseIDPath' + responses: + 404: + description: No enterprise matching the requested ID could be found. + content: {} +components: + parameters: + enterpriseIDPath: + $ref: '#/components/parameters/idInPath' + description: The Enterprise ID used to perform this request. + example: "12422" + + idInPath: + name: id + in: path + required: true + schema: + type: string + + traceIDHeader: + name: X-Trace-Id + in: header + description: Optional UUID for log tracing + required: false + schema: + type: string + + schemas: + EnterpriseDetailResponse: + title: Enterprise Detail Response + type: object + properties: + id: + type: string + description: Unique ID for this enterprise. + example: "3121" + mfa_enforced: + type: boolean + description: Indicates whether MFA is enforced for this enterprise. + example: true + modules: + type: array + description: List of modules this enterprise is authorized to access. + items: + type: string + example: [ + human_resources, + project_management + ] + name: + type: string + description: The name of the enterprise. + example: Kathy's Plumbing + status: + type: string + description: Inidicates current status of this enterprise. + enum: + - offline + - online + - pending_deletion + - unknown + example: online diff --git a/test/e2e-cypress/static/documents/features/oas31-response-empty-media-type.yaml b/test/e2e-cypress/static/documents/features/oas31-response-empty-media-type.yaml new file mode 100644 index 00000000..10293c3b --- /dev/null +++ b/test/e2e-cypress/static/documents/features/oas31-response-empty-media-type.yaml @@ -0,0 +1,92 @@ +openapi: '3.1.0' + +info: + title: Our API + description: extended description of Our API + version: 0.1.0 + +servers: + - url: http://localhost + description: included for completeness; not our actual url + +tags: + - name: Enterprise + description: Operations with Enterprise ID + +paths: + /v0/enterprise/{id}: + get: + tags: + - Enterprise + summary: Get detailed info about an enterprise. + description: | + Returns detailed information for the specified Enterprise ID. + + This operation may *only* be performed by a **platform admin** or a + client with sufficient permissions. + operationId: get_enterprise_detail + parameters: + - $ref: '#/components/parameters/traceIDHeader' + - $ref: '#/components/parameters/enterpriseIDPath' + responses: + 404: + description: No enterprise matching the requested ID could be found. + content: + application/json: {} +components: + parameters: + enterpriseIDPath: + $ref: '#/components/parameters/idInPath' + description: The Enterprise ID used to perform this request. + example: "12422" + + idInPath: + name: id + in: path + required: true + schema: + type: string + + traceIDHeader: + name: X-Trace-Id + in: header + description: Optional UUID for log tracing + required: false + schema: + type: string + + schemas: + EnterpriseDetailResponse: + title: Enterprise Detail Response + type: object + properties: + id: + type: string + description: Unique ID for this enterprise. + example: "3121" + mfa_enforced: + type: boolean + description: Indicates whether MFA is enforced for this enterprise. + example: true + modules: + type: array + description: List of modules this enterprise is authorized to access. + items: + type: string + example: [ + human_resources, + project_management + ] + name: + type: string + description: The name of the enterprise. + example: Kathy's Plumbing + status: + type: string + description: Inidicates current status of this enterprise. + enum: + - offline + - online + - pending_deletion + - unknown + example: online diff --git a/test/e2e-cypress/static/documents/features/oas31-response-no-content.yaml b/test/e2e-cypress/static/documents/features/oas31-response-no-content.yaml new file mode 100644 index 00000000..53643afb --- /dev/null +++ b/test/e2e-cypress/static/documents/features/oas31-response-no-content.yaml @@ -0,0 +1,91 @@ +openapi: '3.1.0' + +info: + title: Our API + description: extended description of Our API + version: 0.1.0 + +servers: + - url: http://localhost + description: included for completeness; not our actual url + +tags: + - name: Enterprise + description: Operations with Enterprise ID + +paths: + /v0/enterprise/{id}: + get: + tags: + - Enterprise + summary: Get detailed info about an enterprise. + description: | + Returns detailed information for the specified Enterprise ID. + + This operation may *only* be performed by a **platform admin** or a + client with sufficient permissions. + operationId: get_enterprise_detail + parameters: + - $ref: '#/components/parameters/traceIDHeader' + - $ref: '#/components/parameters/enterpriseIDPath' + responses: + 404: + description: No enterprise matching the requested ID could be found. + +components: + parameters: + enterpriseIDPath: + $ref: '#/components/parameters/idInPath' + description: The Enterprise ID used to perform this request. + example: "12422" + + idInPath: + name: id + in: path + required: true + schema: + type: string + + traceIDHeader: + name: X-Trace-Id + in: header + description: Optional UUID for log tracing + required: false + schema: + type: string + + schemas: + EnterpriseDetailResponse: + title: Enterprise Detail Response + type: object + properties: + id: + type: string + description: Unique ID for this enterprise. + example: "3121" + mfa_enforced: + type: boolean + description: Indicates whether MFA is enforced for this enterprise. + example: true + modules: + type: array + description: List of modules this enterprise is authorized to access. + items: + type: string + example: [ + human_resources, + project_management + ] + name: + type: string + description: The name of the enterprise. + example: Kathy's Plumbing + status: + type: string + description: Inidicates current status of this enterprise. + enum: + - offline + - online + - pending_deletion + - unknown + example: online