From 711152e2f6ff3b469ed1676303f4e1fec35ce698 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:43:08 +0000 Subject: [PATCH 1/4] Initial plan From a3b2f12c14762f5796b413b5fd275a5469c2af7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:52:29 +0000 Subject: [PATCH 2/4] Fix SegmentedButton ARIA attributes - conditional aria-multiselectable and add aria-orientation Co-authored-by: ilhan007 <15702139+ilhan007@users.noreply.github.com> --- packages/main/src/SegmentedButtonTemplate.tsx | 3 +- packages/main/test/pages/SegmentedButton.html | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/main/src/SegmentedButtonTemplate.tsx b/packages/main/src/SegmentedButtonTemplate.tsx index ff8d44aa7cd7..dd931e4e61bb 100644 --- a/packages/main/src/SegmentedButtonTemplate.tsx +++ b/packages/main/src/SegmentedButtonTemplate.tsx @@ -10,7 +10,8 @@ export default function SegmentedButtonTemplate(this: SegmentedButton) { onKeyDown={this._onkeydown} onKeyUp={this._onkeyup} onFocusIn={this._onfocusin} - aria-multiselectable="true" + aria-multiselectable={this.selectionMode === "Multiple" ? "true" : "false"} + aria-orientation="horizontal" aria-description={this.ariaDescriptionText} aria-label={this.ariaLabelText} aria-roledescription={this.ariaRoleDescription} diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index 3aaa5a4e88dc..a6ac615a6c37 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -212,6 +212,36 @@

Accessibility

segButtonProg.items[0].selected = true; }); + // Test ARIA attributes + function testARIAAttributes() { + console.log('Testing ARIA attributes...'); + + // Test Single mode (default) + const singleModeButton = document.getElementById('segButton1'); + if (singleModeButton) { + const singleUl = singleModeButton.shadowRoot.querySelector('ul[role="listbox"]'); + console.log('Single mode button:', { + selectionMode: singleModeButton.selectionMode, + 'aria-multiselectable': singleUl.getAttribute('aria-multiselectable'), + 'aria-orientation': singleUl.getAttribute('aria-orientation') + }); + } + + // Test Multiple mode + const multipleModeButton = document.getElementById('segButtonMulti'); + if (multipleModeButton) { + const multipleUl = multipleModeButton.shadowRoot.querySelector('ul[role="listbox"]'); + console.log('Multiple mode button:', { + selectionMode: multipleModeButton.selectionMode, + 'aria-multiselectable': multipleUl.getAttribute('aria-multiselectable'), + 'aria-orientation': multipleUl.getAttribute('aria-orientation') + }); + } + } + + // Wait for components to load and then test + setTimeout(testARIAAttributes, 1000); + From 971d167418512dd0399bf57417397dcc34fa473b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:58:17 +0000 Subject: [PATCH 3/4] Add unit test for SegmentedButton ARIA attribute validation Co-authored-by: ilhan007 <15702139+ilhan007@users.noreply.github.com> --- .../main/test/unit/SegmentedButton.test.js | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 packages/main/test/unit/SegmentedButton.test.js diff --git a/packages/main/test/unit/SegmentedButton.test.js b/packages/main/test/unit/SegmentedButton.test.js new file mode 100644 index 000000000000..07ba55052769 --- /dev/null +++ b/packages/main/test/unit/SegmentedButton.test.js @@ -0,0 +1,68 @@ +import { expect, test } from 'vitest' +import "@ui5/webcomponents/dist/SegmentedButton.js"; + +test('SegmentedButton should have correct ARIA attributes for Single mode', async () => { + const segmentedButton = document.createElement("ui5-segmented-button"); + segmentedButton.innerHTML = ` + Option 1 + Option 2 + `; + document.body.appendChild(segmentedButton); + + // Ensure it's in Single mode (default) + expect(segmentedButton.selectionMode).toBe("Single"); + + // Wait for rendering + await new Promise(resolve => setTimeout(resolve, 100)); + + const listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); + expect(listbox).toBeTruthy(); + expect(listbox.getAttribute('aria-multiselectable')).toBe('false'); + expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); +}); + +test('SegmentedButton should have correct ARIA attributes for Multiple mode', async () => { + const segmentedButton = document.createElement("ui5-segmented-button"); + segmentedButton.selectionMode = "Multiple"; + segmentedButton.innerHTML = ` + Option A + Option B + `; + document.body.appendChild(segmentedButton); + + // Ensure it's in Multiple mode + expect(segmentedButton.selectionMode).toBe("Multiple"); + + // Wait for rendering + await new Promise(resolve => setTimeout(resolve, 100)); + + const listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); + expect(listbox).toBeTruthy(); + expect(listbox.getAttribute('aria-multiselectable')).toBe('true'); + expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); +}); + +test('SegmentedButton ARIA attributes should change when selectionMode changes', async () => { + const segmentedButton = document.createElement("ui5-segmented-button"); + segmentedButton.innerHTML = ` + Option X + Option Y + `; + document.body.appendChild(segmentedButton); + + // Start with Single mode (default) + expect(segmentedButton.selectionMode).toBe("Single"); + await new Promise(resolve => setTimeout(resolve, 100)); + + let listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); + expect(listbox.getAttribute('aria-multiselectable')).toBe('false'); + expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); + + // Change to Multiple mode + segmentedButton.selectionMode = "Multiple"; + await new Promise(resolve => setTimeout(resolve, 100)); + + listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); + expect(listbox.getAttribute('aria-multiselectable')).toBe('true'); + expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); +}); \ No newline at end of file From d610581b7b4286d25c3406dcbef089a39dc46b8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Sep 2025 06:28:46 +0000 Subject: [PATCH 4/4] Remove HTML test code and unit test, add focused Cypress test for aria-multiselectable Co-authored-by: ilhan007 <15702139+ilhan007@users.noreply.github.com> --- .../main/cypress/specs/SegmentedButton.cy.tsx | 31 +++++++++ packages/main/test/pages/SegmentedButton.html | 30 -------- .../main/test/unit/SegmentedButton.test.js | 68 ------------------- 3 files changed, 31 insertions(+), 98 deletions(-) delete mode 100644 packages/main/test/unit/SegmentedButton.test.js diff --git a/packages/main/cypress/specs/SegmentedButton.cy.tsx b/packages/main/cypress/specs/SegmentedButton.cy.tsx index d33943af1955..e3d428062da0 100644 --- a/packages/main/cypress/specs/SegmentedButton.cy.tsx +++ b/packages/main/cypress/specs/SegmentedButton.cy.tsx @@ -376,6 +376,37 @@ describe("SegmentedButton Accessibility", () => { .find(".ui5-segmented-button-root") .should("have.attr", "aria-description", `${DESCRIPTION} ${SegmentedButton.i18nBundle.getText(SEGMENTEDBUTTON_ARIA_DESCRIBEDBY)}`); }); + + it("segmented button should have correct aria-multiselectable", () => { + cy.mount( + <> + + First + Second + + + First + Second + + + ); + + // Test Single mode (default) should have aria-multiselectable="false" + cy.get("[ui5-segmented-button]") + .first() + .shadow() + .find("ul[role='listbox']") + .should("have.attr", "aria-multiselectable", "false") + .should("have.attr", "aria-orientation", "horizontal"); + + // Test Multiple mode should have aria-multiselectable="true" + cy.get("[ui5-segmented-button]") + .last() + .shadow() + .find("ul[role='listbox']") + .should("have.attr", "aria-multiselectable", "true") + .should("have.attr", "aria-orientation", "horizontal"); + }); }); diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index a6ac615a6c37..3aaa5a4e88dc 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -212,36 +212,6 @@

Accessibility

segButtonProg.items[0].selected = true; }); - // Test ARIA attributes - function testARIAAttributes() { - console.log('Testing ARIA attributes...'); - - // Test Single mode (default) - const singleModeButton = document.getElementById('segButton1'); - if (singleModeButton) { - const singleUl = singleModeButton.shadowRoot.querySelector('ul[role="listbox"]'); - console.log('Single mode button:', { - selectionMode: singleModeButton.selectionMode, - 'aria-multiselectable': singleUl.getAttribute('aria-multiselectable'), - 'aria-orientation': singleUl.getAttribute('aria-orientation') - }); - } - - // Test Multiple mode - const multipleModeButton = document.getElementById('segButtonMulti'); - if (multipleModeButton) { - const multipleUl = multipleModeButton.shadowRoot.querySelector('ul[role="listbox"]'); - console.log('Multiple mode button:', { - selectionMode: multipleModeButton.selectionMode, - 'aria-multiselectable': multipleUl.getAttribute('aria-multiselectable'), - 'aria-orientation': multipleUl.getAttribute('aria-orientation') - }); - } - } - - // Wait for components to load and then test - setTimeout(testARIAAttributes, 1000); - diff --git a/packages/main/test/unit/SegmentedButton.test.js b/packages/main/test/unit/SegmentedButton.test.js deleted file mode 100644 index 07ba55052769..000000000000 --- a/packages/main/test/unit/SegmentedButton.test.js +++ /dev/null @@ -1,68 +0,0 @@ -import { expect, test } from 'vitest' -import "@ui5/webcomponents/dist/SegmentedButton.js"; - -test('SegmentedButton should have correct ARIA attributes for Single mode', async () => { - const segmentedButton = document.createElement("ui5-segmented-button"); - segmentedButton.innerHTML = ` - Option 1 - Option 2 - `; - document.body.appendChild(segmentedButton); - - // Ensure it's in Single mode (default) - expect(segmentedButton.selectionMode).toBe("Single"); - - // Wait for rendering - await new Promise(resolve => setTimeout(resolve, 100)); - - const listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); - expect(listbox).toBeTruthy(); - expect(listbox.getAttribute('aria-multiselectable')).toBe('false'); - expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); -}); - -test('SegmentedButton should have correct ARIA attributes for Multiple mode', async () => { - const segmentedButton = document.createElement("ui5-segmented-button"); - segmentedButton.selectionMode = "Multiple"; - segmentedButton.innerHTML = ` - Option A - Option B - `; - document.body.appendChild(segmentedButton); - - // Ensure it's in Multiple mode - expect(segmentedButton.selectionMode).toBe("Multiple"); - - // Wait for rendering - await new Promise(resolve => setTimeout(resolve, 100)); - - const listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); - expect(listbox).toBeTruthy(); - expect(listbox.getAttribute('aria-multiselectable')).toBe('true'); - expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); -}); - -test('SegmentedButton ARIA attributes should change when selectionMode changes', async () => { - const segmentedButton = document.createElement("ui5-segmented-button"); - segmentedButton.innerHTML = ` - Option X - Option Y - `; - document.body.appendChild(segmentedButton); - - // Start with Single mode (default) - expect(segmentedButton.selectionMode).toBe("Single"); - await new Promise(resolve => setTimeout(resolve, 100)); - - let listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); - expect(listbox.getAttribute('aria-multiselectable')).toBe('false'); - expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); - - // Change to Multiple mode - segmentedButton.selectionMode = "Multiple"; - await new Promise(resolve => setTimeout(resolve, 100)); - - listbox = segmentedButton.shadowRoot.querySelector('ul[role="listbox"]'); - expect(listbox.getAttribute('aria-multiselectable')).toBe('true'); - expect(listbox.getAttribute('aria-orientation')).toBe('horizontal'); -}); \ No newline at end of file