diff --git a/e2e/suites/search/search-sorting.test.ts b/e2e/suites/search/search-sorting.test.ts index c9ba7177b..6109fb8b0 100644 --- a/e2e/suites/search/search-sorting.test.ts +++ b/e2e/suites/search/search-sorting.test.ts @@ -89,109 +89,93 @@ describe('Search sorting', () => { it('[C277722] Sorting options are displayed', async () => { expect(await page.sortingPicker.isSortOrderButtonDisplayed()).toBe(true, 'Sort order button not displayed'); - expect(await page.sortingPicker.isSortByOptionDisplayed()).toBe(true, 'Sort options not displayed'); - expect(await page.sortingPicker.getSortOrder()).toBe('DESC', 'Incorrect default sort order'); - expect(await page.sortingPicker.getSelectedSortByOption()).toBe('Relevance', 'Incorrect selected sort option'); await page.sortingPicker.clickSortByDropdown(); const expectedOptions = ['Relevance', 'Filename', 'Title', 'Modified date', 'Modifier', 'Created date', 'Size', 'Type']; - expect(await page.sortingPicker.getSortByOptionsList()).toEqual(expectedOptions, 'Incorrect sort options list'); + const optionListed = await page.sortingPicker.getSortByOptionsList(); + expect(optionListed).toEqual(expectedOptions, 'Incorrect sort options list'); }); it('[C277728] Sort by Name', async () => { - await page.sortingPicker.sortBy('Filename'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Filename', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); - await page.sortingPicker.sortBy('Filename'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Filename', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); }); it('[C277740] Sort by Type', async () => { - await page.sortingPicker.sortBy('Type'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Type', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); - await page.sortingPicker.sortBy('Type'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Type', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); }); it('[C277738] Sort by Size', async () => { - await page.sortingPicker.sortBy('Size'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Size', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); - await page.sortingPicker.sortBy('Size'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Size', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); }); it('[C277734] Sort by Created date', async () => { - await page.sortingPicker.sortBy('Created date'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Created date', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); - await page.sortingPicker.sortBy('Created date'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Created date', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); }); it('[C277736] Sort by Modified date', async () => { - await page.sortingPicker.sortBy('Modified date'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Modified date', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); - await page.sortingPicker.sortBy('Modified date'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Modified date', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); }); it('[C277727] Sort by Relevance', async () => { - await page.sortingPicker.sortBy('Relevance'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Relevance', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); - await page.sortingPicker.sortBy('Relevance'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Relevance', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); }); it('[C277732] Sort by Modifier', async () => { - await page.sortingPicker.sortBy('Modifier'); - await page.sortingPicker.setSortOrderASC(); + await page.sortingPicker.sortBy('Modifier', 'asc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); - await page.sortingPicker.sortBy('Modifier'); - await page.sortingPicker.setSortOrderDESC(); + await page.sortingPicker.sortBy('Modifier', 'desc'); expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); diff --git a/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts b/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts index cfda75751..7bfdfc716 100755 --- a/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts +++ b/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts @@ -32,13 +32,13 @@ export type SortByType = 'Relevance' | 'Title' | 'Filename' | 'Modified date' | export type SortOrderType = 'ASC' | 'DESC' | ''; export class SearchSortingPicker extends Component { - sortOrderButton = this.byCss('button[mat-icon-button]'); - sortByDropdownCollapsed = this.byCss('.mat-select'); - sortByDropdownExpanded = browser.element(by.css('.mat-select-panel')); - sortByList = this.sortByDropdownExpanded.all(by.css('.mat-option .mat-option-text')); + actionMenu = browser.element(by.css('aca-search-action-menu > button')); + sortOrderButton = browser.element(by.css('#aca-button-sorting-menu')); + sortByDropdownExpanded = browser.element.all(by.css('.mat-menu-panel')).get(1); + sortByList = this.sortByDropdownExpanded.all(by.css('button')); constructor(ancestor?: string) { - super('adf-search-sorting-picker', ancestor); + super('aca-button-action-menu', ancestor); } async waitForSortByDropdownToExpand(): Promise { @@ -50,35 +50,20 @@ export class SearchSortingPicker extends Component { } async isSortOrderButtonDisplayed(): Promise { - return isPresentAndDisplayed(this.sortOrderButton); - } - - async getSortOrder(): Promise { - const orderArrow = await this.sortOrderButton.getText(); - - if (orderArrow.includes('upward')) { - return 'ASC'; - } else if (orderArrow.includes('downward')) { - return 'DESC'; - } else { - return ''; - } + return isPresentAndDisplayed(this.actionMenu); } async isSortByOptionDisplayed(): Promise { - return isPresentAndDisplayed(this.sortByDropdownCollapsed); + return isPresentAndDisplayed(this.sortOrderButton); } async isSortByDropdownExpanded(): Promise { return isPresentAndDisplayed(this.sortByDropdownExpanded); } - async getSelectedSortByOption(): Promise { - return this.sortByDropdownCollapsed.getText(); - } - async clickSortByDropdown(): Promise { - await BrowserActions.click(this.sortByDropdownCollapsed); + await BrowserActions.click(this.actionMenu); + await BrowserActions.click(this.sortOrderButton); await this.waitForSortByDropdownToExpand(); } @@ -88,23 +73,14 @@ export class SearchSortingPicker extends Component { }); } - async sortBy(option: SortByType): Promise { + async sortBy(option: SortByType, direction: string): Promise { if (!(await this.isSortByDropdownExpanded())) { await this.clickSortByDropdown(); } - const elem = browser.element(by.cssContainingText('.mat-option .mat-option-text', option)); + const elem = browser.element(by.cssContainingText('.mat-menu-item', option)); + const optionId = await elem.getAttribute('id'); await BrowserActions.click(elem); - } - - async setSortOrderASC(): Promise { - if ((await this.getSortOrder()) !== 'ASC') { - await BrowserActions.click(this.sortOrderButton); - } - } - - async setSortOrderDESC(): Promise { - if ((await this.getSortOrder()) !== 'DESC') { - await BrowserActions.click(this.sortOrderButton); - } + const directionSortElement = browser.element(by.id(`${optionId}-${direction.toLocaleLowerCase()}`)); + await BrowserActions.click(directionSortElement); } } diff --git a/src/app/components/search/search-action-menu/search-action-menu.component.html b/src/app/components/search/search-action-menu/search-action-menu.component.html new file mode 100644 index 000000000..0ce03dcd7 --- /dev/null +++ b/src/app/components/search/search-action-menu/search-action-menu.component.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/app/components/search/search-action-menu/search-action-menu.component.spec.ts b/src/app/components/search/search-action-menu/search-action-menu.component.spec.ts new file mode 100644 index 000000000..dafd2167f --- /dev/null +++ b/src/app/components/search/search-action-menu/search-action-menu.component.spec.ts @@ -0,0 +1,137 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SearchQueryBuilderService } from '@alfresco/adf-content-services'; +import { SearchSortingDefinition } from '@alfresco/adf-content-services/lib/search/models/search-sorting-definition.interface'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AppTestingModule } from '../../../testing/app-testing.module'; +import { SearchActionMenuComponent } from './search-action-menu.component'; + +const mockSortingData: SearchSortingDefinition[] = [ + { + ascending: false, + field: 'fieldA', + key: 'keyA', + label: 'LabelA', + type: 'A' + }, + { + ascending: true, + field: 'fieldB', + key: 'keyB', + label: 'Zorro', + type: 'Z' + } +]; + +describe('SearchActionMenuComponent', () => { + let fixture: ComponentFixture; + let component: SearchActionMenuComponent; + let queryService: SearchQueryBuilderService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule], + declarations: [SearchActionMenuComponent], + providers: [SearchQueryBuilderService] + }); + + fixture = TestBed.createComponent(SearchActionMenuComponent); + queryService = TestBed.inject(SearchQueryBuilderService); + component = fixture.componentInstance; + }); + + it('should emit sortingSelected event when asc sorting option is selected', async () => { + spyOn(queryService, 'getSortingOptions').and.returnValue(mockSortingData); + const expectedOption: SearchSortingDefinition = { + ascending: true, + field: 'fieldA', + key: 'keyA', + label: 'LabelA', + type: 'A' + }; + spyOn(component.sortingSelected, 'emit').and.callThrough(); + fixture.detectChanges(); + await fixture.whenStable(); + + const actionMenuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#aca-button-action-menu'); + actionMenuButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + const sortingMenuButton: HTMLButtonElement = document.querySelector('#aca-button-sorting-menu'); + sortingMenuButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + const fieldAMenuButton: HTMLButtonElement = document.querySelector('#keyA-sorting-option'); + fieldAMenuButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + const directionButton: HTMLButtonElement = document.querySelector('#keyA-sorting-option-asc'); + directionButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(component.sortingSelected.emit).toHaveBeenCalledWith(expectedOption); + }); + + it('should emit sortingSelected event when desc sorting option is selected', async () => { + spyOn(queryService, 'getSortingOptions').and.returnValue(mockSortingData); + const expectedOption: SearchSortingDefinition = { + ascending: false, + field: 'fieldB', + key: 'keyB', + label: 'Zorro', + type: 'Z' + }; + spyOn(component.sortingSelected, 'emit').and.callThrough(); + fixture.detectChanges(); + await fixture.whenStable(); + + const actionMenuButton: HTMLButtonElement = fixture.nativeElement.querySelector('#aca-button-action-menu'); + actionMenuButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + const sortingMenuButton: HTMLButtonElement = document.querySelector('#aca-button-sorting-menu'); + sortingMenuButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + const fieldAMenuButton: HTMLButtonElement = document.querySelector('#keyB-sorting-option'); + fieldAMenuButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + const directionButton: HTMLButtonElement = document.querySelector('#keyB-sorting-option-desc'); + directionButton.dispatchEvent(new Event('click')); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(component.sortingSelected.emit).toHaveBeenCalledWith(expectedOption); + }); +}); diff --git a/src/app/components/search/search-action-menu/search-action-menu.component.ts b/src/app/components/search/search-action-menu/search-action-menu.component.ts new file mode 100644 index 000000000..f1a3a0a0b --- /dev/null +++ b/src/app/components/search/search-action-menu/search-action-menu.component.ts @@ -0,0 +1,57 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SearchQueryBuilderService } from '@alfresco/adf-content-services'; +import { SearchSortingDefinition } from '@alfresco/adf-content-services/lib/search/models/search-sorting-definition.interface'; +import { Component, OnInit, Output, ViewEncapsulation, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'aca-search-action-menu', + templateUrl: './search-action-menu.component.html', + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-search-input' } +}) +export class SearchActionMenuComponent implements OnInit { + @Output() + sortingSelected: EventEmitter = new EventEmitter(); + + options: SearchSortingDefinition[] = []; + + constructor(private queryBuilder: SearchQueryBuilderService) {} + + ngOnInit(): void { + this.options = this.queryBuilder.getSortingOptions(); + } + + onAscSortingClicked(option: SearchSortingDefinition) { + option.ascending = true; + this.sortingSelected.emit(option); + } + + onDescSortingClicked(option: SearchSortingDefinition) { + option.ascending = false; + this.sortingSelected.emit(option); + } +} diff --git a/src/app/components/search/search-results.module.ts b/src/app/components/search/search-results.module.ts index 25c43dd8d..86afd0412 100644 --- a/src/app/components/search/search-results.module.ts +++ b/src/app/components/search/search-results.module.ts @@ -37,6 +37,7 @@ import { AppCommonModule } from '../common/common.module'; import { DirectivesModule } from '../../directives/directives.module'; import { AppLayoutModule } from '../layout/layout.module'; import { ContextMenuModule } from '../context-menu/context-menu.module'; +import { SearchActionMenuComponent } from './search-action-menu/search-action-menu.component'; @NgModule({ imports: [ @@ -51,7 +52,7 @@ import { ContextMenuModule } from '../context-menu/context-menu.module'; ContextMenuModule, LockedByModule ], - declarations: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent], - exports: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent] + declarations: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent], + exports: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent] }) export class AppSearchResultsModule {} diff --git a/src/app/components/search/search-results/search-results.component.html b/src/app/components/search/search-results/search-results.component.html index 30739b242..3de04bb59 100644 --- a/src/app/components/search/search-results/search-results.component.html +++ b/src/app/components/search/search-results/search-results.component.html @@ -26,8 +26,9 @@ - - + +
+