Skip to content

Commit 82b9b18

Browse files
authored
[ACS-10518]: Search input keyboard navigation accessibility fixes (#11270)
* [ACS-10518]: add permissions panel clear button updates * [ACS-10518]: adds content-node-selector panel clear button updates * [ACS-10518]: adds no-pointer class * [ACS-10518]: adds no-pointer * [ACS-10518]: minor fixes * [ACS-10518]: fixes padding * [ACS-10518]: unit tests refactor * [ACS-10518]: minor fixes
1 parent 5016eff commit 82b9b18

File tree

5 files changed

+81
-37
lines changed

5 files changed

+81
-37
lines changed

lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component-search.spec.ts

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
18+
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
1919
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
2020
import { By } from '@angular/platform-browser';
2121
import { Node, NodeEntry, NodePaging, RequestScope, ResultSetPaging, SiteEntry, SitePaging, SitePagingList } from '@alfresco/js-api';
@@ -30,6 +30,7 @@ import { SearchQueryBuilderService } from '../../search';
3030
import { mockSearchRequest } from '../../mock/search-query.mock';
3131
import { SitesService } from '../../common/services/sites.service';
3232
import { NodesApiService } from '../../common/services/nodes-api.service';
33+
import { UnitTestingUtils } from '../../../../../core/src/lib/testing/unit-testing-utils';
3334

3435
const fakeResultSetPaging: ResultSetPaging = {
3536
list: {
@@ -60,15 +61,18 @@ describe('ContentNodeSelectorPanelComponent', () => {
6061
const fakeNodeEntry = new Node({ id: 'fakeId' });
6162
const nodeEntryEvent = new NodeEntryEvent(fakeNodeEntry);
6263
let searchQueryBuilderService: SearchQueryBuilderService;
64+
let testingUtils: UnitTestingUtils;
6365

64-
const typeToSearchBox = (searchTerm = 'string-to-search') => {
65-
const searchInput = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-input"]'));
66+
const typeToSearchBox = (searchTerm = 'string-to-search'): void => {
67+
const searchInput = testingUtils.getByCSS('[data-automation-id="content-node-selector-search-input"]');
6668
searchInput.nativeElement.value = searchTerm;
6769
component.searchInput.setValue(searchTerm);
6870
fixture.detectChanges();
6971
};
7072

71-
const triggerSearchResults = (searchResults: ResultSetPaging) => {
73+
const getSearchIcon = (type: string): DebugElement => testingUtils.getByCSS(`[data-automation-id="content-node-selector-search-${type}"]`);
74+
75+
const triggerSearchResults = (searchResults: ResultSetPaging): void => {
7276
const service = fixture.debugElement.injector.get(SearchQueryBuilderService);
7377
service.executed.next(searchResults);
7478
};
@@ -92,6 +96,8 @@ describe('ContentNodeSelectorPanelComponent', () => {
9296
searchQueryBuilderService = fixture.debugElement.injector.get(SearchQueryBuilderService);
9397
searchQueryBuilderService.resetToDefaults();
9498

99+
testingUtils = new UnitTestingUtils(fixture.debugElement);
100+
95101
spyOn(nodeService, 'getNode').and.returnValue(
96102
of(
97103
new Node({
@@ -196,7 +202,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
196202
spyOn(component, 'clearSearch');
197203

198204
fixture.detectChanges();
199-
const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
205+
const clearIcon = getSearchIcon('clear');
200206
clearIcon.nativeElement.click();
201207

202208
fixture.detectChanges();
@@ -357,8 +363,8 @@ describe('ContentNodeSelectorPanelComponent', () => {
357363
fixture.detectChanges();
358364
tick(debounceSearch);
359365

360-
const searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]'));
361-
const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
366+
const searchIcon = getSearchIcon('icon');
367+
const clearIcon = getSearchIcon('clear');
362368

363369
expect(searchIcon).not.toBeNull();
364370
expect(clearIcon).toBeNull();
@@ -371,13 +377,26 @@ describe('ContentNodeSelectorPanelComponent', () => {
371377

372378
fixture.detectChanges();
373379

374-
const searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]'));
375-
const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
380+
const searchIcon = getSearchIcon('icon');
381+
const clearIcon = getSearchIcon('clear');
376382

377383
expect(searchIcon).toBeNull();
378384
expect(clearIcon).not.toBeNull();
379385
}));
380386

387+
it('should call clear method on the X (clear) button click', fakeAsync(() => {
388+
fixture.detectChanges();
389+
typeToSearchBox('123');
390+
tick(debounceSearch);
391+
392+
fixture.detectChanges();
393+
394+
spyOn(component, 'clear');
395+
const clearButton = getSearchIcon('clear');
396+
clearButton.nativeElement.click();
397+
expect(component.clear).toHaveBeenCalled();
398+
}));
399+
381400
it('should clear the search field, nodes and chosenNode when clicking on the X (clear) icon', async () => {
382401
component.chosenNode = [entry];
383402

@@ -553,7 +572,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
553572
}));
554573

555574
it('should show the current folder content instead of search results if search was not performed', async () => {
556-
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
575+
const documentList = testingUtils.getByDirective(DocumentListComponent);
557576
expect(documentList).not.toBeNull();
558577
expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku');
559578
});
@@ -565,7 +584,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
565584

566585
fixture.detectChanges();
567586

568-
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
587+
const documentList = testingUtils.getByDirective(DocumentListComponent);
569588
expect(documentList).not.toBeNull();
570589
expect(
571590
documentList.componentInstance.rowFilter({
@@ -593,7 +612,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
593612

594613
fixture.detectChanges();
595614

596-
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
615+
const documentList = testingUtils.getByDirective(DocumentListComponent);
597616
expect(documentList).not.toBeNull();
598617
expect(documentList.componentInstance.rowFilter).toBeTruthy();
599618

@@ -607,7 +626,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
607626

608627
fixture.detectChanges();
609628

610-
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
629+
const documentList = testingUtils.getByDirective(DocumentListComponent);
611630
expect(documentList).not.toBeNull();
612631
expect(documentList.componentInstance.imageResolver).toBe(resolver);
613632
});
@@ -619,7 +638,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
619638
triggerSearchResults(fakeResultSetPaging);
620639

621640
fixture.detectChanges();
622-
const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
641+
const documentList = testingUtils.getByCSS('[data-automation-id="content-node-selector-document-list"]');
623642
expect(documentList).not.toBeNull();
624643
expect(component.hasValidQuery).toEqual(true);
625644
expect(documentList.componentInstance.currentFolderId).toBeNull();
@@ -664,12 +683,12 @@ describe('ContentNodeSelectorPanelComponent', () => {
664683
fixture.detectChanges();
665684

666685
fixture.whenStable().then(() => {
667-
const clearButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
686+
const clearButton = getSearchIcon('clear');
668687
expect(clearButton).not.toBeNull();
669688
clearButton.triggerEventHandler('click', {});
670689
fixture.detectChanges();
671690

672-
const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
691+
const documentList = testingUtils.getByCSS('[data-automation-id="content-node-selector-document-list"]');
673692
expect(documentList).not.toBeNull();
674693
expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku');
675694
done();
@@ -696,13 +715,13 @@ describe('ContentNodeSelectorPanelComponent', () => {
696715
component.siteChanged({ entry: { guid: 'Kame-Sennin Muten Roshi' } } as SiteEntry);
697716
fixture.detectChanges();
698717

699-
let documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
718+
let documentList = testingUtils.getByCSS('[data-automation-id="content-node-selector-document-list"]');
700719
expect(documentList.componentInstance.currentFolderId).toBe('Kame-Sennin Muten Roshi');
701720

702721
component.siteChanged({ entry: { guid: undefined } } as SiteEntry);
703722
fixture.detectChanges();
704723

705-
documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
724+
documentList = testingUtils.getByCSS('[data-automation-id="content-node-selector-document-list"]');
706725
expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku');
707726

708727
done();
@@ -711,7 +730,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
711730
describe('Pagination "Load more" button', () => {
712731
it('should NOT be shown by default', () => {
713732
fixture.detectChanges();
714-
const pagination = fixture.debugElement.query(By.css('[data-automation-id="adf-infinite-pagination-button"]'));
733+
const pagination = testingUtils.getByCSS('[data-automation-id="adf-infinite-pagination-button"]');
715734
expect(pagination).toBeNull();
716735
});
717736

lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component.html

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,26 @@
1313
adf-auto-focus
1414
data-automation-id="content-node-selector-search-input">
1515

16-
<mat-icon *ngIf="searchTerm.length > 0"
17-
matSuffix (click)="clear()"
18-
class="adf-content-node-selector-content-input-icon"
19-
data-automation-id="content-node-selector-search-clear">clear
20-
</mat-icon>
16+
<button
17+
matSuffix
18+
mat-icon-button
19+
*ngIf="searchTerm.length > 0"
20+
data-automation-id="content-node-selector-search-clear"
21+
class="adf-content-node-selector-search-clear-button"
22+
(click)="clear()"
23+
[attr.aria-label]="'COMMON.CLEAR' | translate"
24+
[attr.title]="'COMMON.CLEAR' | translate"
25+
>
26+
<mat-icon class="adf-content-node-selector-content-input-icon">clear</mat-icon>
27+
</button>
2128

22-
<mat-icon *ngIf="searchTerm.length === 0"
29+
<mat-icon
30+
*ngIf="searchTerm.length === 0"
2331
matSuffix
2432
class="adf-content-node-selector-content-input-icon"
25-
data-automation-id="content-node-selector-search-icon">search
33+
data-automation-id="content-node-selector-search-icon"
34+
>search
2635
</mat-icon>
27-
2836
</mat-form-field>
2937
<adf-sites-dropdown
3038
*ngIf="showDropdownSiteList"

lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component.scss

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,29 @@ h2.adf-search-results-label {
7575
width: 100%;
7676
margin-bottom: 8px;
7777

78-
.adf-content-node-selector-content-input-icon {
78+
.adf-content-node-selector-content-input-icon:is(mat-icon) {
7979
color: var(--adf-theme-foreground-icon-color-054);
80-
cursor: pointer;
8180
padding: 0 0 8px;
8281
width: 1em;
8382
height: 1em;
8483
font-size: 20px;
84+
}
8585

86-
&:hover {
87-
color: var(--adf-theme-foreground-base-color);
86+
.adf-content-node-selector-search-clear-button {
87+
padding: 0;
88+
width: 20px;
89+
height: 28px;
90+
91+
&:focus {
92+
outline-offset: -1.5px;
93+
}
94+
95+
.adf-content-node-selector-content-input-icon:is(mat-icon) {
96+
cursor: pointer;
97+
98+
&:hover {
99+
color: var(--adf-theme-foreground-base-color);
100+
}
88101
}
89102
}
90103

lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-panel.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
class="adf-permission-search-input-clear-button"
2020
(click)="clearSearch()"
2121
[attr.aria-label]="'COMMON.CLEAR' | translate"
22-
[attr.title]="'COMMON.CLEAR' | translate">
22+
[attr.title]="'COMMON.CLEAR' | translate"
23+
>
2324
<mat-icon class="adf-permission-search-icon">clear</mat-icon>
2425
</button>
2526

lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-panel.component.scss

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,21 @@ $search-result-height: calc(100% - 60px);
8080
width: 1em;
8181
height: 1em;
8282
font-size: 20px;
83-
cursor: pointer;
84-
85-
&:hover {
86-
color: var(--adf-theme-foreground-base-color);
87-
}
8883
}
8984

9085
.adf-permission-search-input-clear-button {
9186
padding: 0;
9287
width: 20px;
9388
height: 32px;
9489
margin-right: 1.5px;
90+
91+
.adf-permission-search-icon:is(mat-icon) {
92+
cursor: pointer;
93+
94+
&:hover {
95+
color: var(--adf-theme-foreground-base-color);
96+
}
97+
}
9598
}
9699
}
97100
}

0 commit comments

Comments
 (0)