[MM-61598]: Fix ARIA roles, states, and properties are valid in user profile image and @user buttons (#29692)

* [MA-26]: Fix ARIA roles, states, and properties are valid in user profile image and @user buttons

* [MA-26]: Remove irrelevant e2e tests

* [MA-26]: Remove nested interactive elements

* [MA-26]: Updated mention-link styles

* Minor change

---------

Co-authored-by: ayush-chauhan233 <ayush.chauhan@brightscout.com>
Этот коммит содержится в:
Saurabh Sharma
2025-02-03 00:20:01 +05:30
коммит произвёл GitHub
родитель 8fdb9ad358
Коммит 28dbc3cabb
11 изменённых файлов: 333 добавлений и 348 удалений

Просмотреть файл

@@ -156,8 +156,6 @@ describe('Verify Accessibility keyboard usability across different regions in th
cy.get(region).should('have.attr', 'role', 'application');
});
cy.get('.search__form').should('have.attr', 'role', 'search');
cy.get(`#post_${postId}`).children('.post__content').eq(0).should('have.attr', 'role', 'application');
cy.get(`#rhsPost_${postId}`).children('.post__content').eq(0).should('have.attr', 'role', 'application');
});
});
});

Просмотреть файл

@@ -162,7 +162,7 @@ describe('Verify Accessibility Support in Post', () => {
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).within(() => {
// * Verify focus is on profile image
cy.get('.status-wrapper button').first().should('be.focused');
cy.get('button.status-wrapper').first().should('be.focused');
cy.focused().tab();
// * Verify focus is on the username

Просмотреть файл

@@ -8,13 +8,11 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match d
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -27,7 +25,6 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match d
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -69,13 +66,11 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -88,7 +83,6 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -125,13 +119,11 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -144,7 +136,6 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -179,13 +170,11 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -198,7 +187,6 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>

Просмотреть файл

@@ -28,13 +28,11 @@ exports[`SystemUserDetail should match default snapshot 1`] = `
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -47,7 +45,6 @@ exports[`SystemUserDetail should match default snapshot 1`] = `
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -240,13 +237,11 @@ exports[`SystemUserDetail should match snapshot if MFA is enabled 1`] = `
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -259,7 +254,6 @@ exports[`SystemUserDetail should match snapshot if MFA is enabled 1`] = `
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -452,13 +446,11 @@ exports[`SystemUserDetail should not show manage user settings button when user
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -471,7 +463,6 @@ exports[`SystemUserDetail should not show manage user settings button when user
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -664,13 +655,11 @@ exports[`SystemUserDetail should show manage user settings button as activated 1
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -683,7 +672,6 @@ exports[`SystemUserDetail should show manage user settings button as activated 1
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -881,13 +869,11 @@ exports[`SystemUserDetail should show manage user settings button as disabled wh
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -900,7 +886,6 @@ exports[`SystemUserDetail should show manage user settings button as disabled wh
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>
@@ -1093,13 +1078,11 @@ exports[`SystemUserDetail should show the activate user button as disabled when
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<span
class="profile-icon "
@@ -1112,7 +1095,6 @@ exports[`SystemUserDetail should show the activate user button as disabled when
/>
</span>
</button>
</span>
<div
class="AdminUserCard__user-info"
>

Просмотреть файл

@@ -96,16 +96,15 @@ exports[`components/AtMention should match snapshot when mentioning current user
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc1/image"
triggerComponentClass="mention--highlight"
triggerComponentAs="button"
triggerComponentClass="style--none mention--highlight"
userId="abc1"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@First Last
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -115,16 +114,15 @@ exports[`components/AtMention should match snapshot when mentioning user 1`] = `
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Nick
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -134,16 +132,15 @@ exports[`components/AtMention should match snapshot when mentioning user contain
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc3/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc3"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Dot Matrix
</a>
</span>
</ProfilePopoverController>
.
</Fragment>
@@ -154,16 +151,15 @@ exports[`components/AtMention should match snapshot when mentioning user contain
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc3/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc3"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Dot Matrix
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -173,16 +169,15 @@ exports[`components/AtMention should match snapshot when mentioning user followe
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Nick
</a>
</span>
</ProfilePopoverController>
...
</Fragment>
@@ -193,16 +188,15 @@ exports[`components/AtMention should match snapshot when mentioning user with di
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@user1
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -212,16 +206,15 @@ exports[`components/AtMention should match snapshot when mentioning user with mi
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Nick
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;

Просмотреть файл

@@ -60,20 +60,19 @@ const AtMention = (props: Props) => {
return (
<>
<ProfilePopover
triggerComponentClass={classNames({'mention--highlight': highlightMention})}
triggerComponentClass={classNames('style--none', {'mention--highlight': highlightMention})}
userId={user.id}
src={Client4.getProfilePictureUrl(user.id, user.last_picture_update)}
channelId={props.channelId}
returnFocus={returnFocus}
triggerComponentAs='button'
>
<a
<span
ref={ref}
className='mention-link'
role='button'
tabIndex={0}
>
{'@' + userDisplayName}
</a>
</span>
</ProfilePopover>
{userMentionNameSuffix}
</>

Просмотреть файл

@@ -40,27 +40,34 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
>
<RoundButton
className="style--none"
size="md"
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
size="md"
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<span
className="profile-icon "
@@ -79,8 +86,6 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe
/>
</Avatar>
</span>
</button>
</RoundButton>
<Memo(StatusIcon)
status="status"
>
@@ -113,7 +118,7 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>
@@ -267,27 +272,34 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = `
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
>
<RoundButton
className="style--none"
size="md"
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
size="md"
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<span
className="profile-icon "
@@ -306,8 +318,6 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = `
/>
</Avatar>
</span>
</button>
</RoundButton>
<Memo(StatusIcon)
status="status"
>
@@ -340,7 +350,7 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = `
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>
@@ -500,27 +510,34 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
>
<RoundButton
className="style--none"
size="md"
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
size="md"
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<span
className="profile-icon "
@@ -539,8 +556,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1
/>
</Avatar>
</span>
</button>
</RoundButton>
<Memo(StatusIcon)
status="status"
>
@@ -573,7 +588,7 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>
@@ -790,27 +805,34 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
>
<RoundButton
className="style--none"
size="md"
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
size="md"
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<span
className="profile-icon "
@@ -829,8 +851,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_
/>
</Avatar>
</span>
</button>
</RoundButton>
<Memo(StatusIcon)
status="status"
>
@@ -863,7 +883,7 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>

Просмотреть файл

@@ -566,7 +566,6 @@ function PostComponent(props: Props) {
channelId={post.channel_id}
/>
<div
role='application'
className={`post__content ${props.center ? 'center' : ''}`}
data-testid='postContent'
>

Просмотреть файл

@@ -39,12 +39,16 @@ exports[`components/ProfilePicture should match snapshot, no user specified, ove
exports[`components/ProfilePicture should match snapshot, profile and src, default props 1`] = `
<ProfilePopoverController
src="http://example.com/image.png"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="uid"
>
<RoundButton
className="style--none"
size="md"
>
<span
className="profile-icon "
@@ -53,7 +57,6 @@ exports[`components/ProfilePicture should match snapshot, profile and src, defau
url="http://example.com/emoji.png"
/>
</span>
</RoundButton>
<Memo(StatusIcon)
status="away"
/>

Просмотреть файл

@@ -3,7 +3,6 @@
import classNames from 'classnames';
import React from 'react';
import styled from 'styled-components';
import ProfilePopover from 'components/profile_popover';
import StatusIcon from 'components/status_icon';
@@ -42,7 +41,7 @@ function ProfilePicture(props: Props) {
if (props.userId) {
return (
<ProfilePopover
triggerComponentClass={classNames('status-wrapper', props.wrapperClass)}
triggerComponentClass={classNames('status-wrapper style--none', props.wrapperClass)}
userId={props.userId}
src={profileSrc}
username={props.username}
@@ -51,12 +50,14 @@ function ProfilePicture(props: Props) {
overwriteIcon={props.overwriteIcon}
overwriteName={props.overwriteName}
fromWebhook={props.fromWebhook}
triggerComponentAs='button'
triggerComponentStyle={{
borderRadius: '50%',
width: `${getAvatarWidth(props?.size ?? 'md')}px`,
height: `${getAvatarWidth(props?.size ?? 'md')}px`,
}}
>
<>
<RoundButton
className='style--none'
size={props?.size ?? 'md'}
>
<span className={profileIconClass}>
<Avatar
username={props.username}
@@ -64,7 +65,6 @@ function ProfilePicture(props: Props) {
url={props.src}
/>
</span>
</RoundButton>
<StatusIcon status={props.status}/>
</>
</ProfilePopover>
@@ -93,10 +93,4 @@ function ProfilePicture(props: Props) {
);
}
const RoundButton = styled.button<{size: TAvatarSizeToken}>`
border-radius: 50%;
width: ${(p) => getAvatarWidth(p.size)}px;
height: ${(p) => getAvatarWidth(p.size)}px;
`;
export default ProfilePicture;

Просмотреть файл

@@ -21,6 +21,15 @@ del .group-mention-link:focus {
color: variables.$white;
}
.mention-link {
color: var(--link-color);
&:hover,
&:focus {
text-decoration: underline;
}
}
.badge {
display: inline-block;
min-width: 10px;