diff --git a/packages/ai/cypress/specs/Button.cy.tsx b/packages/ai/cypress/specs/Button.cy.tsx index b7106c704e2c..4c35e774fa66 100644 --- a/packages/ai/cypress/specs/Button.cy.tsx +++ b/packages/ai/cypress/specs/Button.cy.tsx @@ -12,3 +12,73 @@ describe("Initial rendering", () => { ); }); }); + +describe("Accessibility", () => { + it("should set correct tooltip to right text button", () => { + cy.mount( + + ); + + cy.get("[ui5-ai-button]") + .ui5AIButtonCheckAttributeInTextButton("tooltip", "Generate with Artificial Intelligence"); + }); + + it("should set correct aria-haspopup to SplitButton root element", () => { + cy.mount( + + ); + + cy.get("[ui5-ai-button]") + .ui5AIButtonCheckAttributeSplitButtonRoot("aria-haspopup", "menu"); + }); + + it("should set correct aria-roledescription to SplitButton root element", () => { + cy.mount( + + ); + + cy.get("[ui5-ai-button]") + .ui5AIButtonCheckAttributeSplitButtonRoot("aria-roledescription", "Open Menu"); + }); + + it("should set correct aria-haspopup to arrow button if shown", () => { + cy.mount( + + ); + + cy.get("[ui5-ai-button]") + .ui5AIButtonCheckAttributeInArrowButton("aria-haspopup", "menu"); + }); + + it("should set correct aria attributes with default values when not provided", () => { + cy.mount( + + ); + + cy.get("[ui5-ai-button]") + .as("button"); + + cy.get("@button") + .ui5AIButtonCheckAttributeSplitButtonRoot("aria-haspopup", "false"); + + cy.get("@button") + .ui5AIButtonCheckAttributeSplitButtonRoot("aria-roledescription", "Split Button"); + + cy.get("@button") + .ui5AIButtonCheckAttributeInArrowButton("aria-haspopup", "menu"); + + cy.get("@button") + .ui5AIButtonCheckAttributeInArrowButton("aria-expanded", "false"); + }); +}); diff --git a/packages/ai/cypress/support/commands.ts b/packages/ai/cypress/support/commands.ts index 3d44a956b147..9570783f6a8d 100644 --- a/packages/ai/cypress/support/commands.ts +++ b/packages/ai/cypress/support/commands.ts @@ -37,4 +37,15 @@ // } import "@ui5/cypress-internal/commands.js"; -import "../../../main/cypress/support/commands.js"; \ No newline at end of file +import "../../../main/cypress/support/commands.js"; +import "./commands/Button.commands.js"; + +declare global { + namespace Cypress { + interface Chainable { + ui5AIButtonCheckAttributeInTextButton(attrName: string, attrValue: string): Chainable + ui5AIButtonCheckAttributeInArrowButton(attrName: string, attrValue: string): Chainable + ui5AIButtonCheckAttributeSplitButtonRoot(attrName: string, attrValue: string): Chainable + } + } +} \ No newline at end of file diff --git a/packages/ai/cypress/support/commands/Button.commands.ts b/packages/ai/cypress/support/commands/Button.commands.ts new file mode 100644 index 000000000000..0ad6e783c346 --- /dev/null +++ b/packages/ai/cypress/support/commands/Button.commands.ts @@ -0,0 +1,33 @@ +import Button from "../../../src/Button.js"; + +Cypress.Commands.add("ui5AIButtonCheckAttributeInTextButton", { prevSubject: true }, (subject: JQuery - {!this._hideArrowButton && - - } - {this.accInfo.root.description} {this.accInfo.root.keyboardHint} {this.accessibleName} - {this.textButtonAccText} + {!this._hideArrowButton && ( + <> + + {this.accInfo.keyboardHint} {this.accessibleName} + {this._computedAccessibilityAttributes?.root?.title || this.textButtonAccText} + + )} ); } diff --git a/packages/website/docs/_samples/ai/Button/ButtonMenu/main.js b/packages/website/docs/_samples/ai/Button/ButtonMenu/main.js index a88dd22465da..5517380b1143 100644 --- a/packages/website/docs/_samples/ai/Button/ButtonMenu/main.js +++ b/packages/website/docs/_samples/ai/Button/ButtonMenu/main.js @@ -8,27 +8,38 @@ var generationId; function startGeneration(button) { console.warn("startGeneration"); - generationId = setTimeout(function() { + generationId = setTimeout(function () { console.warn("Generation completed"); button.state = "revise"; + button.accessibilityAttributes = { + root: { + hasPopup: "menu", + roleDescription: "Menu Button" + } + }; }, 3000); } -function stopGeneration() { +function stopGeneration(button) { console.warn("stopGeneration"); clearTimeout(generationId); + button.accessibilityAttributes = { + root: { + hasPopup: "false" + } + }; } function aiButtonClickHandler(evt) { var button = evt.target; - switch(button.state) { + switch (button.state) { case "generate": button.state = "generating"; startGeneration(button); break; case "generating": button.state = "generate"; - stopGeneration(); + stopGeneration(button); break; case "revise": menu.opener = button; @@ -39,7 +50,7 @@ function aiButtonClickHandler(evt) { myAiButton.addEventListener("click", aiButtonClickHandler); -menu.addEventListener("item-click", function(evt) { +menu.addEventListener("item-click", function (evt) { var button = menu.opener; if (evt.detail.text === "Regenerate") { button.state = "generating"; diff --git a/packages/website/docs/_samples/ai/Button/ButtonSplitMenu/main.js b/packages/website/docs/_samples/ai/Button/ButtonSplitMenu/main.js index 45033b36faf7..987bf497fc78 100644 --- a/packages/website/docs/_samples/ai/Button/ButtonSplitMenu/main.js +++ b/packages/website/docs/_samples/ai/Button/ButtonSplitMenu/main.js @@ -9,21 +9,31 @@ var prevTriggerState = "generate"; function startGeneration(button) { console.warn("startGeneration"); - generationId = setTimeout(function() { + generationId = setTimeout(function () { console.warn("Generation completed"); button.state = "regenerate"; + button.accessibilityAttributes = { + root: { + hasPopup: "menu" + } + }; }, 3000); } -function stopGeneration() { +function stopGeneration(button) { console.warn("stopGeneration"); clearTimeout(generationId); + button.accessibilityAttributes = { + root: { + hasPopup: "false" + } + }; } function aiButtonClickHandler(evt) { var button = evt.target; - switch(button.state) { + switch (button.state) { case "": case "generate": prevTriggerState = "generate"; @@ -32,7 +42,7 @@ function aiButtonClickHandler(evt) { break; case "generating": button.state = prevTriggerState; - stopGeneration(); + stopGeneration(button); break; case "regenerate": menu.open = false; diff --git a/packages/website/docs/_samples/patterns/AIRegenerate/Basic/main.js b/packages/website/docs/_samples/patterns/AIRegenerate/Basic/main.js index c843e6aa6b55..981222044cca 100644 --- a/packages/website/docs/_samples/patterns/AIRegenerate/Basic/main.js +++ b/packages/website/docs/_samples/patterns/AIRegenerate/Basic/main.js @@ -30,6 +30,11 @@ const toggleDialog = (dialog, isOpen) => { }; dialogCloser.addEventListener("click", () => toggleDialog(dialog, false)); +myAiButton.accessibilityAttributes = { + root: { + hasPopup: "dialog" + } +}; myAiButton.addEventListener("click", () => { if (myAiButton.state === "generating") { @@ -89,6 +94,11 @@ const setBusyIndicator = (isActive) => { const resetAfterGeneration = (button) => { setBusyIndicator(false); button.state = "regenerate"; + button.accessibilityAttributes = { + root: { + hasPopup: "false" + } + }; }; const stopTextGeneration = () => {