From 369be9cfcf00473af5844065e9815115fa77ef25 Mon Sep 17 00:00:00 2001 From: lane-wetmore Date: Wed, 25 Jun 2025 10:27:27 -0500 Subject: [PATCH] UI: A11y fix for disabled swagger interarctive (#31079) * update disabled fields to be readonly * add tests for a11y fix --- .../addon/components/swagger-ui.js | 9 +++++++ ui/mirage/factories/open-api-explorer.js | 24 +++++++++++++++++++ .../open-api-explorer/swagger-ui-test.js | 19 +++++++++++---- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/ui/lib/open-api-explorer/addon/components/swagger-ui.js b/ui/lib/open-api-explorer/addon/components/swagger-ui.js index 26167cc1f2..ccda39b012 100644 --- a/ui/lib/open-api-explorer/addon/components/swagger-ui.js +++ b/ui/lib/open-api-explorer/addon/components/swagger-ui.js @@ -130,12 +130,14 @@ export default class SwaggerUiComponent extends Component { this.observer = new MutationObserver(() => { this.updateCaretTabIndex(); this.updateCopyToClipboard(); + this.updateDisabledFields(); this.updateTryItOutButtonDescription(); }); this.observer.observe(container, { childList: true, subtree: true }); // Run once on initial load this.updateCaretTabIndex(); this.updateCopyToClipboard(); + this.updateDisabledFields(); this.updateTryItOutButtonDescription(); } } @@ -162,6 +164,13 @@ export default class SwaggerUiComponent extends Component { }); } + updateDisabledFields() { + document.querySelectorAll('.parameters :disabled').forEach((el) => { + el.removeAttribute('disabled'); + el.setAttribute('readonly', true); + }); + } + updateTryItOutButtonDescription() { document.querySelectorAll('.try-out button').forEach((el) => { const warning = diff --git a/ui/mirage/factories/open-api-explorer.js b/ui/mirage/factories/open-api-explorer.js index 57dbfbaf2e..c5ce5f92bc 100644 --- a/ui/mirage/factories/open-api-explorer.js +++ b/ui/mirage/factories/open-api-explorer.js @@ -36,6 +36,30 @@ export default Factory.extend({ }, }, }, + 'auth/token/roles/{role_name}': { + description: '', + get: { + summary: '', + tags: ['auth'], + operationId: 'token-read-role', + parameters: [ + { + name: 'role_name', + required: true, + in: 'path', + schema: { + type: 'string', + }, + description: 'Name of the role', + }, + ], + responses: { + 200: { + description: 'OK', + }, + }, + }, + }, '/secret/data/{path}': { description: 'Location of a secret.', post: { diff --git a/ui/tests/integration/components/open-api-explorer/swagger-ui-test.js b/ui/tests/integration/components/open-api-explorer/swagger-ui-test.js index 2775bc9a66..5a6e6dd6d5 100644 --- a/ui/tests/integration/components/open-api-explorer/swagger-ui-test.js +++ b/ui/tests/integration/components/open-api-explorer/swagger-ui-test.js @@ -16,7 +16,7 @@ import { camelize } from '@ember/string'; const SELECTORS = { container: '[data-test-swagger-ui]', searchInput: 'input.operation-filter-input', - apiPathBlock: '.opblock-post', + apiPathBlock: '.opblock', operationId: '.opblock-summary-operation-id', controlArrowButton: '.opblock-control-arrow', copyButton: '.copy-to-clipboard', @@ -66,7 +66,7 @@ module('Integration | Component | open-api-explorer | swagger-ui', function (hoo setNativeInputValue('token'); assert.dom(SELECTORS.searchInput).hasValue('token', 'search input has value'); - assert.dom(SELECTORS.apiPathBlock).exists({ count: 1 }, 'renders filtered api paths'); + assert.dom(SELECTORS.apiPathBlock).exists({ count: 2 }, 'renders filtered api paths'); }); test('it should render camelized operation ids', async function (assert) { @@ -105,8 +105,13 @@ module('Integration | Component | open-api-explorer | swagger-ui', function (hoo }); assert.dom(SELECTORS.copyButton).hasAttribute('tabindex', '0'); - await click(SELECTORS.controlArrowButton); + const controlArrowButton = document.querySelectorAll(SELECTORS.controlArrowButton)[1]; + await click(controlArrowButton); await waitFor(SELECTORS.tryItOutButton); + + const input = document.querySelector('.parameters input:read-only'); + assert.dom(input).exists('parameter input is readonly'); + assert .dom(SELECTORS.tryItOutButton) .hasAttribute( @@ -122,7 +127,7 @@ module('Integration | Component | open-api-explorer | swagger-ui', function (hoo await this.renderComponent(); - setNativeInputValue('secret'); + setNativeInputValue('token'); await waitUntil(() => { return document.querySelector(SELECTORS.controlArrowButton).getAttribute('tabindex') === '0'; @@ -134,8 +139,12 @@ module('Integration | Component | open-api-explorer | swagger-ui', function (hoo }); assert.dom(SELECTORS.copyButton).hasAttribute('tabindex', '0'); - await click(SELECTORS.controlArrowButton); + const controlArrowButton = document.querySelectorAll(SELECTORS.controlArrowButton)[1]; + await click(controlArrowButton); await waitFor(SELECTORS.tryItOutButton); + + const input = document.querySelector('.parameters input:read-only'); + assert.dom(input).exists('parameter input is readonly'); assert .dom(SELECTORS.tryItOutButton) .hasAttribute(