[ACS-3497] - Fix accessibility issues in ACA personal files (#7833)

This commit is contained in:
MichalKinas
2022-09-21 16:08:57 +02:00
committed by GitHub
parent 3180ad3fe0
commit c5ee606cb4
15 changed files with 40 additions and 40 deletions

View File

@@ -72,7 +72,7 @@
role="navigation"
[attr.aria-label]="'BREADCRUMB.ARIA-LABEL.BREADCRUMB' | translate"
>
<div class="adf-breadcrumb-item adf-active" role="listitem">
<div class="adf-breadcrumb-item adf-active" role="group">
<div class="adf-breadcrumb-item-current" role="heading" aria-level="2">
{{ root | translate }}
</div>

View File

@@ -63,7 +63,7 @@ describe('UserIconColumnComponent', () => {
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[id="user-initials-image"]').textContent).toContain('fu');
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('fu');
});
it('should render person value from node', () => {
@@ -80,7 +80,7 @@ describe('UserIconColumnComponent', () => {
} as NodeEntry;
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[id="user-initials-image"]').textContent).toContain('FU');
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('FU');
});
});

View File

@@ -2,7 +2,7 @@
class="adf-filter">
<button mat-icon-button
[matMenuTriggerFor]="filter"
id="filter-menu-button"
data-automation-id="filter-menu-button"
#menuTrigger="matMenuTrigger"
(click)="$event.stopPropagation()"
(menuOpened)="onMenuOpen()"
@@ -22,6 +22,7 @@
class="adf-filter-menu"
(closed)="onClosed()">
<div #filterContainer
role="menuitem"
(keydown.tab)="$event.stopPropagation();">
<div (click)="$event.stopPropagation()"
class="adf-filter-container">

View File

@@ -86,7 +86,7 @@ describe('SearchFilterContainerComponent', () => {
});
it('should set/update the active filter after the Apply button is clicked', async () => {
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#filter-menu-button');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]');
menuButton.click();
fixture.detectChanges();
await fixture.whenStable();
@@ -113,7 +113,7 @@ describe('SearchFilterContainerComponent', () => {
it('should remove active filter after the Clear button is clicked', async () => {
queryBuilder.setActiveFilter('name', 'searchText');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#filter-menu-button');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]');
menuButton.click();
fixture.detectChanges();
await fixture.whenStable();
@@ -133,7 +133,7 @@ describe('SearchFilterContainerComponent', () => {
component.filterChange.subscribe(() => {
eventRaised = true;
});
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#filter-menu-button');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]');
menuButton.click();
fixture.detectChanges();
@@ -154,7 +154,7 @@ describe('SearchFilterContainerComponent', () => {
it('should set up a focus trap on the filter when the menu is opened', async () => {
expect(component.focusTrap).toBeUndefined();
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#filter-menu-button');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]');
menuButton.click();
fixture.detectChanges();
@@ -164,7 +164,7 @@ describe('SearchFilterContainerComponent', () => {
});
it('should focus the input element when the menu is opened', async () => {
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#filter-menu-button');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]');
menuButton.click();
fixture.detectChanges();
@@ -176,7 +176,7 @@ describe('SearchFilterContainerComponent', () => {
});
it('should focus the menu trigger when the menu is closed', async () => {
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#filter-menu-button');
const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]');
menuButton.click();
fixture.detectChanges();
@@ -188,7 +188,7 @@ describe('SearchFilterContainerComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const matMenuButton = fixture.debugElement.query(By.css('#filter-menu-button'));
const matMenuButton = fixture.debugElement.query(By.css('[data-automation-id="filter-menu-button"]'));
expect(document.activeElement).toBe(matMenuButton.nativeElement);
});
});

View File

@@ -67,7 +67,6 @@ describe('DateCellComponent', () => {
const tooltipValue = dateCellValue.attributes['title'].value;
expect(dateCellValue.textContent.trim()).toEqual('Jul 14, 2022');
expect(dateCellValue.attributes['aria-label'].value).toEqual('Jul 14, 2022');
expect(tooltipValue).toEqual('Jul 14, 2022, 11:50:45 AM');
});
});

View File

@@ -45,7 +45,6 @@ import { takeUntil } from 'rxjs/operators';
</ng-container>
<ng-template #defaultCell>
<span
[attr.aria-label]="value$ | async"
[title]="tooltip"
class="adf-datatable-cell-value"
>{{ value$ | async }}</span>

View File

@@ -31,7 +31,6 @@ import { takeUntil } from 'rxjs/operators';
template: `
<ng-container>
<span
[attr.aria-label]="value$ | async | adfTimeAgo: currentLocale"
title="{{ tooltip | adfLocalizedDate: 'medium' }}"
class="adf-datatable-cell-value"
*ngIf="format === 'timeAgo'; else standard_date">
@@ -41,8 +40,7 @@ import { takeUntil } from 'rxjs/operators';
<ng-template #standard_date>
<span
class="adf-datatable-cell-value"
title="{{ tooltip | adfLocalizedDate: tooltipDateFormat }}"
[attr.aria-label]="value$ | async | adfLocalizedDate: format">
title="{{ tooltip | adfLocalizedDate: tooltipDateFormat }}">
{{ value$ | async | adfLocalizedDate: format }}
</span>
</ng-template>

View File

@@ -25,7 +25,6 @@ import { AlfrescoApiService } from '../../../services/alfresco-api.service';
<ng-container *ngIf="(value$ | async | adfFileSize) as fileSize">
<span
[title]="tooltip"
[attr.aria-label]="fileSize"
>{{ fileSize }}</span
>
</ng-container>

View File

@@ -25,7 +25,8 @@
"TITLE": "Notifications",
"MARK_AS_READ": "Mark all as read",
"SYSTEM": "System",
"LOAD_MORE": "Load more"
"LOAD_MORE": "Load more",
"OPEN_HISTORY": "Open notification history"
},
"FORM": {
"START_FORM": {

View File

@@ -1,6 +1,8 @@
<div (keyup)="onKeyPress($event)">
<button mat-button
[matMenuTriggerFor]="menu"
[attr.aria-label]="'NOTIFICATIONS.OPEN_HISTORY' | translate"
title="{{ 'NOTIFICATIONS.OPEN_HISTORY' | translate }}"
class="adf-notification-history-menu_button"
id="adf-notification-history-open-button"
(menuOpened)="onMenuOpened()">
@@ -17,7 +19,7 @@
<div class="adf-notification-history-list"
(click)="$event.stopPropagation()">
<div mat-subheader>
<div mat-subheader role="menuitem">
<span>{{ 'NOTIFICATIONS.TITLE' | translate }}</span>
<button (click)="markAsRead()"
id="adf-notification-history-mark-as-read"
@@ -30,7 +32,7 @@
<mat-divider></mat-divider>
<mat-list>
<mat-list role="menuitem">
<ng-container *ngIf="notifications.length; else empty_list_template">
<mat-list-item *ngFor="let notification of paginatedNotifications"
class="adf-notification-history-menu-item"
@@ -54,7 +56,7 @@
<ng-template #empty_list_template>
<mat-list-item id="adf-notification-history-component-no-message"
class="adf-notification-history-menu-no-message">
<h4 mat-line>{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}</h4>
<p mat-line>{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}</p>
</mat-list-item>
</ng-template>
</mat-list>
@@ -62,6 +64,7 @@
<mat-divider></mat-divider>
<div class="adf-notification-history-load-more"
role="menuitem"
*ngIf="hasMoreNotifications()">
<button mat-button
(click)="loadMore()">

View File

@@ -64,28 +64,28 @@ describe('UserInitialPipe', () => {
fakeUser.firstName = 'FAKE-NAME';
fakeUser.lastName = 'FAKE-SURNAME';
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">FF</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">FF</div>');
});
it('should apply the style class passed in input', () => {
fakeUser.firstName = 'FAKE-NAME';
fakeUser.lastName = 'FAKE-SURNAME';
const result = pipe.transform(fakeUser, 'fake-class-to-check');
expect(result).toBe('<div id="user-initials-image" class="fake-class-to-check">FF</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="fake-class-to-check">FF</div>');
});
it('should return a single letter into div when lastName is undefined', () => {
fakeUser.firstName = 'FAKE-NAME';
fakeUser.lastName = undefined;
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">F</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">F</div>');
});
it('should return a single letter into div when firstname is null', () => {
fakeUser.firstName = undefined;
fakeUser.lastName = 'FAKE-SURNAME';
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">F</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">F</div>');
});
it('should return a single letter into div when only username is defined', () => {
@@ -93,7 +93,7 @@ describe('UserInitialPipe', () => {
fakeUser.lastName = undefined;
fakeUser.username = 'USERNAME-FAKE';
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">U</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">U</div>');
});
it('should return a single letter into div of firstName when only firstName and username is defined', () => {
@@ -101,7 +101,7 @@ describe('UserInitialPipe', () => {
fakeUser.lastName = undefined;
fakeUser.username = 'USERNAME-FAKE';
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">F</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">F</div>');
});
it('should return two letter into div of username and lastName when firstName is undefined', () => {
@@ -109,7 +109,7 @@ describe('UserInitialPipe', () => {
fakeUser.lastName = 'FAKE-SURNAME';
fakeUser.username = 'USERNAME-FAKE';
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">UF</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">UF</div>');
});
it('should return a div with the user initials when firstName, lastName and username is defined', () => {
@@ -117,7 +117,7 @@ describe('UserInitialPipe', () => {
fakeUser.lastName = 'FAKE-SURNAME';
fakeUser.username = 'USERNAME-FAKE';
const result = pipe.transform(fakeUser);
expect(result).toBe('<div id="user-initials-image" class="">FF</div>');
expect(result).toBe('<div data-automation-id="user-initials-image" class="">FF</div>');
});
it('should return an empty string when user is null', () => {

View File

@@ -31,7 +31,7 @@ export class InitialUsernamePipe implements PipeTransform {
let safeHtml: SafeHtml = '';
if (user) {
const initialResult = this.getInitialUserName(user.firstName || user.displayName || user.username, user.lastName, delimiter);
safeHtml = this.sanitized.bypassSecurityTrustHtml(`<div id="user-initials-image" class="${className}">${initialResult}</div>`);
safeHtml = this.sanitized.bypassSecurityTrustHtml(`<div data-automation-id="user-initials-image" class="${className}">${initialResult}</div>`);
}
return safeHtml;
}

View File

@@ -55,9 +55,9 @@
</button>
<mat-menu #menu="matMenu" id="user-profile-lists" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
[overlapTrigger]="false" class="adf-userinfo-menu">
<mat-tab-group id="tab-group-env" (click)="stopClosing($event)" selectedIndex="0"
<mat-tab-group id="tab-group-env" (click)="stopClosing($event)" selectedIndex="0" role="menuitem"
class="adf-userinfo-tab" [class.adf-hide-tab]="!(bpmUser$ | async) || !(ecmUser$ | async)">
<mat-tab id="ecm-panel" label="{{ 'USER_PROFILE.TAB.CS' | translate }}"
<mat-tab id="ecm-panel" label="{{ 'USER_PROFILE.TAB.CS' | translate }}" role="dialog"
*ngIf="mode==='CONTENT' || mode==='ALL'">
<mat-card class="adf-userinfo-card" *ngIf="ecmUser$ | async as ecmUser">
<mat-card-header class="adf-userinfo-card-header"
@@ -94,7 +94,7 @@
</mat-card-content>
</mat-card>
</mat-tab>
<mat-tab id="bpm-panel" label="{{ 'USER_PROFILE.TAB.PS' | translate }}"
<mat-tab id="bpm-panel" label="{{ 'USER_PROFILE.TAB.PS' | translate }}" role="dialog"
*ngIf="mode==='PROCESS' || mode==='ALL'">
<mat-card class="adf-userinfo-card" *ngIf="bpmUser$ | async as bpmUser">
<mat-card-header class="adf-userinfo-card-header"
@@ -126,7 +126,7 @@
</mat-card-content>
</mat-card>
</mat-tab>
<mat-tab id="identity-panel" *ngIf="mode==='SSO'">
<mat-tab id="identity-panel" role="dialog" *ngIf="mode==='SSO'">
<mat-card class="adf-userinfo-card" *ngIf="identityUser$ | async as identityUser">
<mat-card-header class="adf-userinfo-card-header"
[style.background-image]="'url(' + bpmBackgroundImage + ')'">

View File

@@ -258,7 +258,7 @@ describe('User info component', () => {
});
it('should show N/A when the job title is null', () => {
const imageButton = element.querySelector<HTMLButtonElement>('#user-initials-image');
const imageButton = element.querySelector<HTMLButtonElement>('[data-automation-id="user-initials-image"]');
imageButton.click();
fixture.detectChanges();
expect(element.querySelector('#userinfo_container')).not.toBeNull();
@@ -269,7 +269,7 @@ describe('User info component', () => {
});
it('should not show the tabs', () => {
const imageButton = element.querySelector<HTMLButtonElement>('#user-initials-image');
const imageButton = element.querySelector<HTMLButtonElement>('[data-automation-id="user-initials-image"]');
imageButton.click();
fixture.detectChanges();
const tabHeader = fixture.debugElement.query(By.css('#tab-group-env'));
@@ -285,7 +285,7 @@ describe('User info component', () => {
lastName: 'Adams',
email: 'wilbur@app.com'
});
expect(expected).toBe('<div id="user-initials-image" class="">WA</div>');
expect(expected).toBe('<div data-automation-id="user-initials-image" class="">WA</div>');
component.ecmUser$.subscribe((response: EcmUserModel) => {
expect(response).toBeDefined();
expect(response.avatarId).toBeNull();
@@ -421,7 +421,7 @@ describe('User info component', () => {
await whenFixtureReady();
expect(element.querySelector('#userinfo_container')).toBeDefined();
expect(element.querySelector('#user-initials-image').textContent).toContain('ff');
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('ff');
});
it('should show the tabs for the env', async () => {
@@ -462,7 +462,7 @@ describe('User info component', () => {
it('should show the identity user initials if is not ecm user', async () => {
await whenFixtureReady();
expect(element.querySelector('#userinfo_container')).toBeDefined();
expect(element.querySelector('#user-initials-image').textContent).toContain('ff');
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('ff');
});
it('should able to fetch identity userInfo', (done) => {

View File

@@ -34,7 +34,7 @@ export class UserInfoPage {
processTenant = $('.detail-profile');
apsImage = $('img[id="bpm-user-detail-image"]');
acsImage = $('img[id="ecm-user-detail-image"]');
initialImage = $$('div[id="user-initials-image"]').first();
initialImage = $$('div[data-automation-id="user-initials-image"]').first();
userInfoSsoHeaderTitle = this.dialog.$('div[id="identity-username"]');
userInfoSsoTitle = $('.adf-userinfo__detail-title');
ssoEmail = $('#identity-email');