Skip to content
68 changes: 67 additions & 1 deletion packages/main/cypress/specs/Avatar.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,72 @@ describe("Accessibility", () => {
.should("have.attr", "aria-label", expectedLabel);
});

it("should return correct accessibilityInfo object when avatar is interactive", () => {
const INITIALS = "JD";
const hasPopup = "menu";
const customLabel = "John Doe Avatar";

cy.mount(
<Avatar
id="interactive-info"
initials={INITIALS}
interactive
accessibleName={customLabel}
accessibilityAttributes={{hasPopup}}
></Avatar>
);

cy.get("#interactive-info").then($avatar => {
const avatar = $avatar[0] as any;

// Check accessibilityInfo properties
expect(avatar.accessibilityInfo).to.exist;
expect(avatar.accessibilityInfo.role).to.equal("button");
// Type contains the i18n text
expect(avatar.accessibilityInfo.type).to.equal("Menu");
expect(avatar.accessibilityInfo.description).to.equal(customLabel);
});
});

it("should return correct accessibilityInfo object when avatar is not interactive", () => {
cy.mount(
<Avatar
id="non-interactive-info"
initials="JD"
></Avatar>
);

cy.get("#non-interactive-info").then($avatar => {
const avatar = $avatar[0] as any;

// Check that accessibilityInfo is undefined
expect(avatar.accessibilityInfo).to.exist;
expect(avatar.accessibilityInfo.role).to.equal("img");
expect(avatar.accessibilityInfo.type).to.equal("");
expect(avatar.accessibilityInfo.description).to.equal("Avatar JD");
});
});

it("should use default label for accessibilityInfo description when no custom label is provided", () => {
const INITIALS = "AB";

cy.mount(
<Avatar
id="default-label-info"
initials={INITIALS}
interactive
></Avatar>
);

cy.get("#default-label-info").then($avatar => {
const avatar = $avatar[0] as any;

// Check that accessibilityInfo uses the default label format that includes initials
expect(avatar.accessibilityInfo).to.exist;
expect(avatar.accessibilityInfo.description).to.equal(`Avatar ${INITIALS}`);
});
});

it("checks if accessible-name is correctly passed to the icon", () => {
const ACCESSIBLE_NAME = "Supplier Icon";
const ICON_NAME = "supplier";
Expand Down Expand Up @@ -500,4 +566,4 @@ describe("Avatar Rendering and Interaction", () => {
cy.get("@clickStub")
.should("have.been.calledOnce");
});
});
});
37 changes: 35 additions & 2 deletions packages/main/src/Avatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import type { AccessibilityAttributes } from "@ui5/webcomponents-base/dist/types.js";
import type { AccessibilityAttributes, AriaRole } from "@ui5/webcomponents-base/dist/types.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import type { ITabbable } from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js";
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
Expand All @@ -17,7 +17,14 @@ import type { IAvatarGroupItem } from "./AvatarGroup.js";
// Template
import AvatarTemplate from "./AvatarTemplate.js";

import { AVATAR_TOOLTIP } from "./generated/i18n/i18n-defaults.js";
import {
AVATAR_TOOLTIP,
ARIA_HASPOPUP_DIALOG,
ARIA_HASPOPUP_GRID,
ARIA_HASPOPUP_LISTBOX,
ARIA_HASPOPUP_MENU,
ARIA_HASPOPUP_TREE,
} from "./generated/i18n/i18n-defaults.js";

// Styles
import AvatarCss from "./generated/themes/Avatar.css.js";
Expand Down Expand Up @@ -493,6 +500,32 @@ class Avatar extends UI5Element implements ITabbable, IAvatarGroupItem {
}
this._imageLoadError = true;
}

_getAriaTypeDescription() {
switch (this._ariaHasPopup) {
case "dialog":
return Avatar.i18nBundle.getText(ARIA_HASPOPUP_DIALOG);
case "grid":
return Avatar.i18nBundle.getText(ARIA_HASPOPUP_GRID);
case "listbox":
return Avatar.i18nBundle.getText(ARIA_HASPOPUP_LISTBOX);
case "menu":
return Avatar.i18nBundle.getText(ARIA_HASPOPUP_MENU);
case "tree":
return Avatar.i18nBundle.getText(ARIA_HASPOPUP_TREE);
default:
return "";
}
}

get accessibilityInfo() {
return {
role: this._role as AriaRole,
type: this._getAriaTypeDescription(),
description: this.accessibleNameText,
disabled: this.disabled,
};
}
}

Avatar.define();
Expand Down
15 changes: 15 additions & 0 deletions packages/main/src/i18n/messagebundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ ARIA_ROLEDESCRIPTION_CARD_HEADER=Card Header
#XBUT: Card Header aria-roledescription interactive text
ARIA_ROLEDESCRIPTION_INTERACTIVE_CARD_HEADER=Interactive Card Header

#XACT: ARIA hasPopup description for dialog popup type
ARIA_HASPOPUP_DIALOG=Dialog

#XACT: ARIA hasPopup description for grid popup type
ARIA_HASPOPUP_GRID=Grid

#XACT: ARIA hasPopup description for listbox popup type
ARIA_HASPOPUP_LISTBOX=Listbox

#XACT: ARIA hasPopup description for menu popup type
ARIA_HASPOPUP_MENU=Menu

#XACT: ARIA hasPopup description for tree popup type
ARIA_HASPOPUP_TREE=Tree

#XACT: ARIA announcement for the Avatar default tooltip
AVATAR_TOOLTIP=Avatar

Expand Down
Loading