From 93fd0bec6c14bc9c0d45f99d8dd86c0d72124bda Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 3 Nov 2023 10:05:34 +0000 Subject: [PATCH] [ACS-6140] reduce access to internal material classes (#9053) * cleanup login (demo shell) * cleanup e2e from useless calls * [ci:force] cleanup e2e from useless calls * [ci:force] cleanup e2e from useless calls * [ci:force] improved uploader selectors * [ci:force] remove useless selectors when automation id provided * [ci:force] improved tests and selectors * [ci:force] improved tests and selectors * [ci:force] improved tests and selectors * [ci:force] improved tests and selectors * [ci:force] improved tests and selectors * [ci:force] improved tests and selectors * [ci:force] switch edit task filter to angular harness * [ci:force] switch edit process filter to angular harness * [ci:force] switch search chip list to angular harness * [ci:force] switch search panel to angular harness * [ci:force] switch search radio to angular harness * [ci:force] switch search text to angular harness * [ci:force] search logical filter * [ci:force] search form component * [ci:force] search filter container * [ci:force] fix viewer test * [ci:force] search facet chip harness * [ci:force] search facet chip harness * [ci:force] dropdown breadcrumb * [ci:force] search check list * [ci:force] folder dialog * [ci:force] search filter component * [ci:force] json cell * [ci:force] amount widget * [ci:force] checkbox widget * [ci:force] multiline-text widget * [ci:force] number widget * [ci:force] text widget * [ci:force] card view array item * add permission dialog * permission container component * permission list component * card view components * search widget chip * search facet chip * edit service task filter * card view components * sites dropdown * share dialog * header component * datetime widget * remove comments --- .../app/components/login/login.component.html | 2 +- .../app/components/login/login.component.scss | 3 +- .../upload/uploader-component.e2e.ts | 4 - e2e/core/pages/dialog/upload-dialog.page.ts | 14 +- e2e/core/pages/dialog/upload-toggles.page.ts | 20 +- e2e/core/pages/metadata-view.page.ts | 4 +- .../pages/task-details.page.ts | 2 +- e2e/search/pages/search-bar.page.ts | 3 +- e2e/search/pages/search-filters.page.ts | 46 +- .../dropdown-breadcrumb.component.spec.ts | 11 +- .../content-metadata.component.spec.ts | 4 +- .../content-node-selector.component.spec.ts | 147 ++--- .../content-node-share.dialog.spec.ts | 98 ++-- .../src/lib/dialogs/folder.dialog.html | 2 +- .../src/lib/dialogs/folder.dialog.spec.ts | 69 +-- .../add-permission-dialog.component.spec.ts | 97 ++-- .../permission-container.component.spec.ts | 35 +- .../permission-list.component.spec.ts | 62 ++- .../user-icon-column.component.spec.ts | 34 +- .../search-check-list.component.spec.ts | 71 ++- .../search-chip-list.component.spec.ts | 73 ++- .../search-date-range.component.spec.ts | 36 +- ...search-facet-chip-tabbed.component.spec.ts | 88 +-- .../search-facet-chip.component.html | 2 +- .../search-facet-chip.component.spec.ts | 110 ++-- .../search-widget-chip.component.html | 2 +- .../search-widget-chip.component.spec.ts | 60 ++- .../search-filter-container.component.spec.ts | 131 ++--- .../search-filter.component.spec.ts | 338 ++++++------ .../search-form/search-form.component.spec.ts | 63 ++- .../search-logical-filter.component.html | 2 +- .../search-logical-filter.component.spec.ts | 11 +- .../search-panel.component.spec.ts | 70 ++- .../search-radio.component.spec.ts | 59 +- .../search-text/search-text.component.spec.ts | 25 +- .../sites-dropdown.component.spec.ts | 172 +++--- .../file-uploading-dialog.component.html | 1 + .../file-uploading-list-row.component.spec.ts | 22 +- .../alfresco-viewer.component.spec.ts | 41 +- .../card-view-arrayitem.component.spec.ts | 68 ++- .../card-view-dateitem.component.spec.ts | 48 +- .../card-view-selectitem.component.spec.ts | 109 ++-- .../card-view-textitem.component.spec.ts | 60 +-- .../card-view/card-view.component.spec.ts | 186 ++++--- .../json-cell/json-cell.component.spec.ts | 28 +- .../widgets/amount/amount.widget.spec.ts | 167 +++--- .../widgets/checkbox/checkbox.widget.spec.ts | 75 +-- .../date-time/date-time.widget.spec.ts | 67 +-- .../multiline-text.widget.spec.ts | 63 +-- .../widgets/number/number.widget.spec.ts | 66 +-- .../widgets/text/text.widget.spec.ts | 184 +++---- .../header/header.component.spec.ts | 38 +- .../data-table/data-table.widget.spec.ts | 67 ++- ...dit-process-filter-cloud.component.spec.ts | 451 +++++++--------- ...base-edit-task-filter-cloud.component.html | 2 +- ...ervice-task-filter-cloud.component.spec.ts | 472 +++++++--------- .../edit-task-filter-cloud.component.spec.ts | 503 +++++++++--------- .../task-filters/task-filters-cloud.module.ts | 13 +- .../task-form/task-form.component.spec.ts | 202 ++++--- .../components/task-header.component.spec.ts | 57 +- .../pages/search/date-range-filter.page.ts | 18 +- .../pages/search/number-range-filter.page.ts | 17 +- 62 files changed, 2335 insertions(+), 2660 deletions(-) diff --git a/demo-shell/src/app/components/login/login.component.html b/demo-shell/src/app/components/login/login.component.html index aa1dfa8a5c..65bd4e60ef 100644 --- a/demo-shell/src/app/components/login/login.component.html +++ b/demo-shell/src/app/components/login/login.component.html @@ -1,4 +1,4 @@ - + settings diff --git a/demo-shell/src/app/components/login/login.component.scss b/demo-shell/src/app/components/login/login.component.scss index be6b5db41e..093c81fef6 100644 --- a/demo-shell/src/app/components/login/login.component.scss +++ b/demo-shell/src/app/components/login/login.component.scss @@ -1,6 +1,7 @@ -.app-setting-button.mat-fab { +.app-setting-button { position: absolute; right: 10px; top: 10px; z-index: 1; + color: white; } diff --git a/e2e/content-services/upload/uploader-component.e2e.ts b/e2e/content-services/upload/uploader-component.e2e.ts index 8cb8d80332..2e6d94a5b0 100644 --- a/e2e/content-services/upload/uploader-component.e2e.ts +++ b/e2e/content-services/upload/uploader-component.e2e.ts @@ -139,7 +139,6 @@ describe('Upload component', () => { it('[C260172] Should be possible to enable versioning', async () => { await uploadToggles.enableVersioning(); - await uploadToggles.checkVersioningToggleIsEnabled(); await contentServicesPage.uploadFile(pdfFileModel.location); await contentServicesPage.checkContentIsDisplayed(pdfFileModel.name); @@ -164,7 +163,6 @@ describe('Upload component', () => { await contentServicesPage.goToDocumentList(); await uploadToggles.enableMaxSize(); - await uploadToggles.checkMaxSizeToggleIsEnabled(); await uploadToggles.addMaxSize('400'); await contentServicesPage.uploadFile(fileWithSpecificSize.location); @@ -190,7 +188,6 @@ describe('Upload component', () => { it('[C272796] Should be possible to set max size to 0', async () => { await contentServicesPage.goToDocumentList(); await uploadToggles.enableMaxSize(); - await uploadToggles.checkMaxSizeToggleIsEnabled(); await uploadToggles.addMaxSize('0'); await contentServicesPage.uploadFile(fileWithSpecificSize.location); // await expect(await contentServicesPage.getErrorMessage()).toEqual('File ' + fileWithSpecificSize.name + ' is larger than the allowed file size'); @@ -207,7 +204,6 @@ describe('Upload component', () => { it('[C272797] Should be possible to set max size to 1', async () => { await uploadToggles.enableMaxSize(); - await uploadToggles.checkMaxSizeToggleIsEnabled(); await browser.sleep(1000); await uploadToggles.addMaxSize('1'); await uploadToggles.disableMaxSize(); diff --git a/e2e/core/pages/dialog/upload-dialog.page.ts b/e2e/core/pages/dialog/upload-dialog.page.ts index f98e3169e2..a70bcc8efb 100644 --- a/e2e/core/pages/dialog/upload-dialog.page.ts +++ b/e2e/core/pages/dialog/upload-dialog.page.ts @@ -19,21 +19,19 @@ import { by, browser, ElementFinder, $, $$ } from 'protractor'; import { BrowserVisibility, BrowserActions } from '@alfresco/adf-testing'; export class UploadDialogPage { - - closeButton = $('footer[class*="upload-dialog__actions"] button[id="adf-upload-dialog-close"]'); + closeButton = $('#adf-upload-dialog-close'); dialog = $('div[id="upload-dialog"]'); minimizedDialog = $('div[class*="upload-dialog--minimized"]'); - uploadedStatusIcon = 'mat-icon[class*="status--done"]'; + uploadedStatusIcon = '.adf-file-uploading-row__status--done'; cancelledStatusIcon = 'div[class*="status--cancelled"]'; errorStatusIcon = 'div[class*="status--error"] mat-icon'; rowByRowName = by.xpath('ancestor::adf-file-uploading-list-row'); title = $('span[class*="upload-dialog__title"]'); - minimizeButton = $('mat-icon[title="Minimize"]'); - maximizeButton = $('mat-icon[title="Maximize"]'); + toggleMinimizeButton = $(`[data-automation-id='adf-upload-dialog__toggle-minimize']`); async clickOnCloseButton(): Promise { await this.checkCloseButtonIsDisplayed(); - await BrowserActions.clickExecuteScript('footer[class*="upload-dialog__actions"] button[id="adf-upload-dialog-close"]'); + await BrowserActions.click(this.closeButton); } async checkCloseButtonIsDisplayed(): Promise { @@ -107,11 +105,11 @@ export class UploadDialogPage { } async minimizeUploadDialog(): Promise { - await BrowserActions.click(this.minimizeButton); + await BrowserActions.click(this.toggleMinimizeButton); } async maximizeUploadDialog(): Promise { - await BrowserActions.click(this.maximizeButton); + await BrowserActions.click(this.toggleMinimizeButton); } async displayTooltip(): Promise { diff --git a/e2e/core/pages/dialog/upload-toggles.page.ts b/e2e/core/pages/dialog/upload-toggles.page.ts index b4916c6928..90057197b3 100644 --- a/e2e/core/pages/dialog/upload-toggles.page.ts +++ b/e2e/core/pages/dialog/upload-toggles.page.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { $, browser } from 'protractor'; +import { $ } from 'protractor'; import { BrowserActions, BrowserVisibility, TogglePage } from '@alfresco/adf-testing'; export class UploadTogglesPage { @@ -25,16 +25,14 @@ export class UploadTogglesPage { extensionFilterToggle = $('#adf-extension-filter-upload-switch'); maxSizeToggle = $('#adf-max-size-filter-upload-switch'); versioningToggle = $('#adf-version-upload-switch'); - extensionAcceptedField = $('input[data-automation-id="accepted-files-type"]'); - maxSizeField = $('input[data-automation-id="max-files-size"]'); + extensionAcceptedField = $('[data-automation-id="accepted-files-type"]'); + maxSizeField = $('[data-automation-id="max-files-size"]'); async enableMultipleFileUpload(): Promise { - await browser.executeScript('arguments[0].scrollIntoView()', this.multipleFileUploadToggle); await this.togglePage.enableToggle(this.multipleFileUploadToggle); } async disableMultipleFileUpload(): Promise { - await browser.executeScript('arguments[0].scrollIntoView()', this.multipleFileUploadToggle); await this.togglePage.disableToggle(this.multipleFileUploadToggle); } @@ -42,23 +40,11 @@ export class UploadTogglesPage { await this.togglePage.enableToggle(this.uploadFolderToggle); } - async checkMaxSizeToggleIsEnabled(): Promise { - const enabledToggle = $('mat-slide-toggle[id="adf-max-size-filter-upload-switch"][class*="mat-checked"]'); - await BrowserVisibility.waitUntilElementIsVisible(enabledToggle); - } - - async checkVersioningToggleIsEnabled(): Promise { - const enabledToggle = $('mat-slide-toggle[id="adf-version-upload-switch"][class*="mat-checked"]'); - await BrowserVisibility.waitUntilElementIsVisible(enabledToggle); - } - async enableExtensionFilter(): Promise { - await browser.executeScript('arguments[0].scrollIntoView()', this.extensionFilterToggle); await this.togglePage.enableToggle(this.extensionFilterToggle); } async disableExtensionFilter(): Promise { - await browser.executeScript('arguments[0].scrollIntoView()', this.extensionFilterToggle); await this.togglePage.disableToggle(this.extensionFilterToggle); } diff --git a/e2e/core/pages/metadata-view.page.ts b/e2e/core/pages/metadata-view.page.ts index 7edf5cc0f2..03c67b4724 100644 --- a/e2e/core/pages/metadata-view.page.ts +++ b/e2e/core/pages/metadata-view.page.ts @@ -46,9 +46,9 @@ export class MetadataViewPage { resetMetadataButton = $(`[data-automation-id='reset-metadata']`); private getMetadataGroupLocator = async (groupName: string): Promise => - $(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"]`); + $(`[data-automation-id="adf-metadata-group-${groupName}"]`); private getExpandedMetadataGroupLocator = async (groupName: string): Promise => - $(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"] > mat-expansion-panel-header`); + $(`[data-automation-id="adf-metadata-group-${groupName}"] > mat-expansion-panel-header`); async getTitle(): Promise { return BrowserActions.getText(this.title); diff --git a/e2e/process-services/pages/task-details.page.ts b/e2e/process-services/pages/task-details.page.ts index 38b8abf71e..20cf9ad5c8 100644 --- a/e2e/process-services/pages/task-details.page.ts +++ b/e2e/process-services/pages/task-details.page.ts @@ -73,7 +73,7 @@ export class TaskDetailsPage { } async checkDueDatePickerButtonIsNotDisplayed(): Promise { - const dueDatePickerButton = $('mat-datetimepicker-toggle[data-automation-id="datepickertoggle-dueDate"]'); + const dueDatePickerButton = $('[data-automation-id="datepickertoggle-dueDate"]'); await BrowserVisibility.waitUntilElementIsNotVisible(dueDatePickerButton); } diff --git a/e2e/search/pages/search-bar.page.ts b/e2e/search/pages/search-bar.page.ts index 87f6ad24e8..7c8c8a824a 100644 --- a/e2e/search/pages/search-bar.page.ts +++ b/e2e/search/pages/search-bar.page.ts @@ -19,7 +19,6 @@ import { ElementFinder, protractor, $ } from 'protractor'; import { BrowserVisibility, BrowserActions, TestElement } from '@alfresco/adf-testing'; export class SearchBarPage { - searchIcon = $(`button[class*='adf-search-button']`); searchBar = $(`adf-search-control input`); searchBarExpanded: TestElement = TestElement.byCss(`adf-search-control mat-form-field[class*="mat-focused"] input`); @@ -29,7 +28,7 @@ export class SearchBarPage { highlightName = `.adf-highlight`; searchBarPage = $(`mat-list[id='autocomplete-search-result-list']`); - getRowByRowName = (name: string): ElementFinder => $(`mat-list-item[data-automation-id='autocomplete_for_${name}']`); + getRowByRowName = (name: string): ElementFinder => $(`[data-automation-id='autocomplete_for_${name}']`); async clickOnSearchIcon(): Promise { await BrowserActions.click(this.searchIcon); diff --git a/e2e/search/pages/search-filters.page.ts b/e2e/search/pages/search-filters.page.ts index c6d393e2dd..dab086f950 100644 --- a/e2e/search/pages/search-filters.page.ts +++ b/e2e/search/pages/search-filters.page.ts @@ -15,29 +15,38 @@ * limitations under the License. */ -import { BrowserVisibility, DateRangeFilterPage, NumberRangeFilterPage, SearchCategoriesPage, SearchCheckListPage, SearchRadioPage, SearchSliderPage, SearchTextPage } from '@alfresco/adf-testing'; +import { + BrowserVisibility, + DateRangeFilterPage, + NumberRangeFilterPage, + SearchCategoriesPage, + SearchCheckListPage, + SearchRadioPage, + SearchSliderPage, + SearchTextPage +} from '@alfresco/adf-testing'; import { $, by } from 'protractor'; export class SearchFiltersPage { - searchCategoriesPage: SearchCategoriesPage = new SearchCategoriesPage(); searchFilters = $('adf-search-filter'); - fileTypeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.TYPE"]'); - creatorFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FILTER.PEOPLE"]'); - fileSizeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.SIZE"]'); - nameFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Name"]'); - checkListFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Check List"]'); - createdDateRangeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Created Date (range)"]'); - typeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Type"]'); - sizeRangeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Content Size (range)"]'); - sizeSliderFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Content Size"]'); - facetQueriesDefaultGroup = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FACET_QUERIES.MY_FACET_QUERIES"],' + - 'mat-expansion-panel[data-automation-id="expansion-panel-My facet queries"]'); - facetQueriesTypeGroup = $('mat-expansion-panel[data-automation-id="expansion-panel-Type facet queries"]'); - facetQueriesSizeGroup = $('mat-expansion-panel[data-automation-id="expansion-panel-Size facet queries"]'); - facetIntervalsByCreated = $('mat-expansion-panel[data-automation-id="expansion-panel-The Created"]'); - facetIntervalsByModified = $('mat-expansion-panel[data-automation-id="expansion-panel-TheModified"]'); + fileTypeFilter = $('[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.TYPE"]'); + creatorFilter = $('[data-automation-id="expansion-panel-SEARCH.FILTER.PEOPLE"]'); + fileSizeFilter = $('[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.SIZE"]'); + nameFilter = $('[data-automation-id="expansion-panel-Name"]'); + checkListFilter = $('[data-automation-id="expansion-panel-Check List"]'); + createdDateRangeFilter = $('[data-automation-id="expansion-panel-Created Date (range)"]'); + typeFilter = $('[data-automation-id="expansion-panel-Type"]'); + sizeRangeFilter = $('[data-automation-id="expansion-panel-Content Size (range)"]'); + sizeSliderFilter = $('[data-automation-id="expansion-panel-Content Size"]'); + facetQueriesDefaultGroup = $( + '[data-automation-id="expansion-panel-SEARCH.FACET_QUERIES.MY_FACET_QUERIES"],' + '[data-automation-id="expansion-panel-My facet queries"]' + ); + facetQueriesTypeGroup = $('[data-automation-id="expansion-panel-Type facet queries"]'); + facetQueriesSizeGroup = $('[data-automation-id="expansion-panel-Size facet queries"]'); + facetIntervalsByCreated = $('[data-automation-id="expansion-panel-The Created"]'); + facetIntervalsByModified = $('[data-automation-id="expansion-panel-TheModified"]'); async checkSearchFiltersIsDisplayed(): Promise { await BrowserVisibility.waitUntilElementIsVisible(this.searchFilters); @@ -72,7 +81,7 @@ export class SearchFiltersPage { } async checkCustomFacetFieldLabelIsDisplayed(fieldLabel: string): Promise { - await BrowserVisibility.waitUntilElementIsVisible($(`mat-expansion-panel[data-automation-id="expansion-panel-${fieldLabel}"]`)); + await BrowserVisibility.waitUntilElementIsVisible($(`[data-automation-id="expansion-panel-${fieldLabel}"]`)); } sizeSliderFilterPage(): SearchSliderPage { @@ -234,5 +243,4 @@ export class SearchFiltersPage { async checkFileTypeFacetLabelIsNotDisplayed(fileType: string | RegExp): Promise { await BrowserVisibility.waitUntilElementIsNotVisible(this.fileTypeFilter.element(by.cssContainingText('.adf-facet-label', fileType))); } - } diff --git a/lib/content-services/src/lib/breadcrumb/dropdown-breadcrumb.component.spec.ts b/lib/content-services/src/lib/breadcrumb/dropdown-breadcrumb.component.spec.ts index 1552ed7084..11dafe52fc 100644 --- a/lib/content-services/src/lib/breadcrumb/dropdown-breadcrumb.component.spec.ts +++ b/lib/content-services/src/lib/breadcrumb/dropdown-breadcrumb.component.spec.ts @@ -26,7 +26,6 @@ import { of } from 'rxjs'; import { TranslateModule } from '@ngx-translate/core'; describe('DropdownBreadcrumb', () => { - let component: DropdownBreadcrumbComponent; let fixture: ComponentFixture; let documentList: DocumentListComponent; @@ -34,10 +33,7 @@ describe('DropdownBreadcrumb', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], + imports: [TranslateModule.forRoot(), ContentTestingModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [{ provide: DocumentListService, useValue: documentListService }] }); @@ -64,7 +60,7 @@ describe('DropdownBreadcrumb', () => { }; const clickOnTheFirstOption = () => { - const option: any = document.querySelector('[id^="mat-option"]'); + const option: any = document.querySelector(`[data-automation-class="dropdown-breadcrumb-path-option"]`); option.click(); }; @@ -75,7 +71,6 @@ describe('DropdownBreadcrumb', () => { triggerComponentChange(fakeNodeWithCreatePermissionInstance); fixture.whenStable().then(() => { - openSelect(); const currentFolder = fixture.debugElement.query(By.css('[data-automation-id="current-folder"]')); @@ -99,7 +94,6 @@ describe('DropdownBreadcrumb', () => { triggerComponentChange(fakeNodeWithCreatePermissionInstance); fixture.whenStable().then(() => { - openSelect(); const path = fixture.debugElement.query(By.css('[data-automation-id="dropdown-breadcrumb-path"]')); @@ -110,7 +104,6 @@ describe('DropdownBreadcrumb', () => { }); }); - it('should update document list when clicking on an option', async () => { component.target = documentList; const fakeNodeWithCreatePermissionInstance = JSON.parse(JSON.stringify(fakeNodeWithCreatePermission)); diff --git a/lib/content-services/src/lib/content-metadata/components/content-metadata/content-metadata.component.spec.ts b/lib/content-services/src/lib/content-metadata/components/content-metadata/content-metadata.component.spec.ts index 9bb10750b3..65847fe4b8 100644 --- a/lib/content-services/src/lib/content-metadata/components/content-metadata/content-metadata.component.spec.ts +++ b/lib/content-services/src/lib/content-metadata/components/content-metadata/content-metadata.component.spec.ts @@ -607,7 +607,7 @@ describe('ContentMetadataComponent', () => { it('should hide metadata fields if displayDefaultProperties is set to false', () => { component.displayDefaultProperties = false; fixture.detectChanges(); - const metadataContainer = fixture.debugElement.query(By.css('mat-expansion-panel[data-automation-id="adf-metadata-group-properties"]')); + const metadataContainer = fixture.debugElement.query(By.css('[data-automation-id="adf-metadata-group-properties"]')); fixture.detectChanges(); expect(metadataContainer).toBeNull(); }); @@ -615,7 +615,7 @@ describe('ContentMetadataComponent', () => { it('should display metadata fields if displayDefaultProperties is set to true', () => { component.displayDefaultProperties = true; fixture.detectChanges(); - const metadataContainer = fixture.debugElement.query(By.css('mat-expansion-panel[data-automation-id="adf-metadata-group-properties"]')); + const metadataContainer = fixture.debugElement.query(By.css('[data-automation-id="adf-metadata-group-properties"]')); fixture.detectChanges(); expect(metadataContainer).toBeDefined(); }); diff --git a/lib/content-services/src/lib/content-node-selector/content-node-selector.component.spec.ts b/lib/content-services/src/lib/content-node-selector/content-node-selector.component.spec.ts index 96800a1992..ad4fff2902 100644 --- a/lib/content-services/src/lib/content-node-selector/content-node-selector.component.spec.ts +++ b/lib/content-services/src/lib/content-node-selector/content-node-selector.component.spec.ts @@ -24,7 +24,6 @@ import { By } from '@angular/platform-browser'; import { FileModel } from '../common/models/file.model'; import { FileUploadEvent } from '../common/events/file.event'; import { UploadService } from '../common/services/upload.service'; - import { of } from 'rxjs'; import { ContentTestingModule } from '../testing/content.testing.module'; import { DocumentListService } from '../document-list/services/document-list.service'; @@ -58,12 +57,7 @@ describe('ContentNodeSelectorComponent', () => { }; TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule, - MatDialogModule, - UploadModule - ], + imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule, UploadModule], providers: [ { provide: MAT_DIALOG_DATA, useValue: data }, { @@ -118,6 +112,8 @@ describe('ContentNodeSelectorComponent', () => { fixture.destroy(); }); + const getTabInfoButton = () => fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]')); + const enableLocalUpload = () => { component.data.showLocalUploadButton = true; component.hasAllowableOperations = true; @@ -125,15 +121,16 @@ describe('ContentNodeSelectorComponent', () => { component.isLoading = false; }; + const getTabLabel = (idx: number) => fixture.debugElement.queryAll(By.css('.mat-tab-label'))[idx]; + const selectTabByIndex = (tabIndex: number) => { - const uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[tabIndex]; + const uploadFromLocalTab = getTabLabel(tabIndex); const attributes = uploadFromLocalTab.nativeNode.attributes as NamedNodeMap; const tabPositionInSet = Number(attributes.getNamedItem('aria-posinset').value) - 1; component.onTabSelectionChange(tabPositionInSet); }; describe('Data injecting with the "Material dialog way"', () => { - it('should show the INJECTED title', () => { const titleElement = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-title"]')); expect(titleElement).not.toBeNull(); @@ -149,101 +146,105 @@ describe('ContentNodeSelectorComponent', () => { it('should pass through the injected currentFolderId to the documentList', () => { const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); - expect(documentList).not.toBeNull('Document list should be shown'); + expect(documentList).not.toBeNull(); expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku'); }); it('should pass through the injected rowFilter to the documentList', () => { const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); - expect(documentList).not.toBeNull('Document list should be shown'); - expect(documentList.componentInstance.rowFilter({ - node: { - entry: new Node({ - name: 'impossible-name', - id: 'name' - }) - } - })) - .toBe(data.rowFilter({ + expect(documentList).not.toBeNull(); + expect( + documentList.componentInstance.rowFilter({ node: { entry: new Node({ name: 'impossible-name', id: 'name' }) } - })); + }) + ).toBe( + data.rowFilter({ + node: { + entry: new Node({ + name: 'impossible-name', + id: 'name' + }) + } + }) + ); }); it('should pass through the injected imageResolver to the documentList', () => { const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); - expect(documentList).not.toBeNull('Document list should be shown'); + expect(documentList).not.toBeNull(); expect(documentList.componentInstance.imageResolver).toBe(data.imageResolver); }); - }); + }); describe('Cancel button', () => { + const getCancelButton = () => fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-cancel"]')); + it('should not be shown if dialogRef is NOT injected', () => { const closeButton = fixture.debugElement.query(By.css('[content-node-selector-actions-cancel]')); expect(closeButton).toBeNull(); }); it('should close the dialog', () => { - let cancelButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-cancel"]')); + let cancelButton = getCancelButton(); cancelButton.triggerEventHandler('click', {}); expect(dialog.close).toHaveBeenCalled(); fixture.detectChanges(); - cancelButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-cancel"]')); + cancelButton = getCancelButton(); expect(cancelButton).not.toBeNull(); }); }); describe('Action button for the chosen node', () => { + const getActionButton = () => + fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'))?.nativeElement as HTMLButtonElement; it('should be disabled by default', () => { fixture.detectChanges(); - const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(actionButton.nativeElement.disabled).toBeTruthy(); + const actionButton = getActionButton(); + expect(actionButton.disabled).toBeTruthy(); }); it('should be enabled when a node is chosen', () => { component.onSelect([new Node({ id: 'fake' })]); fixture.detectChanges(); - const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(actionButton.nativeElement.disabled).toBeFalsy(); + const actionButton = getActionButton(); + expect(actionButton.disabled).toBeFalsy(); }); it('should be disabled when no node chosen', () => { component.onSelect([new Node({ id: 'fake' })]); fixture.detectChanges(); - const actionButtonWithNodeSelected = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - - expect(actionButtonWithNodeSelected.nativeElement.disabled).toBe(false); + const actionButtonWithNodeSelected = getActionButton(); + expect(actionButtonWithNodeSelected.disabled).toBe(false); component.onSelect([]); fixture.detectChanges(); - const actionButtonWithoutNodeSelected = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - - expect(actionButtonWithoutNodeSelected.nativeElement.disabled).toBe(true); + const actionButtonWithoutNodeSelected = getActionButton(); + expect(actionButtonWithoutNodeSelected.disabled).toBe(true); }); - it('should close the dialog when action button is clicked', async () => { + it('should close the dialog when action button is clicked', () => { component.onSelect([new Node({ id: 'fake' })]); fixture.detectChanges(); - const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - await actionButton.nativeElement.click(); + const actionButton = getActionButton(); + actionButton.click(); expect(dialog.close).toHaveBeenCalled(); }); }); describe('Title', () => { - it('should be updated when a site is chosen', () => { const fakeSiteTitle = 'My fake site'; const contentNodePanel = fixture.debugElement.query(By.directive(ContentNodeSelectorPanelComponent)); @@ -253,17 +254,18 @@ describe('ContentNodeSelectorComponent', () => { const titleElement = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-title"]')); expect(titleElement).not.toBeNull(); expect(titleElement.nativeElement.innerText).toBe('NODE_SELECTOR.CHOOSE_ITEM'); - }); - }); + }); + }); describe('Upload button', () => { + const getUploadButton = () => fixture.debugElement.query(By.css('adf-upload-button button'))?.nativeElement as HTMLButtonElement; it('Should not be able to upload a file whilst a search is still running', () => { enableLocalUpload(); fixture.detectChanges(); - let infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]')); - let uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1]; + let infoMatIcon = getTabInfoButton(); + let uploadFromLocalTab = getTabLabel(1); expect(uploadFromLocalTab.nativeElement.getAttribute('aria-disabled')).toBe('false'); expect(infoMatIcon).toBeFalsy(); @@ -271,8 +273,8 @@ describe('ContentNodeSelectorComponent', () => { component.showingSearch = true; fixture.detectChanges(); - uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1]; - infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]')); + uploadFromLocalTab = getTabLabel(1); + infoMatIcon = getTabInfoButton(); expect(uploadFromLocalTab.nativeElement.getAttribute('aria-disabled')).toBe('true'); expect(infoMatIcon).toBeTruthy(); @@ -281,8 +283,8 @@ describe('ContentNodeSelectorComponent', () => { component.showingSearch = false; fixture.detectChanges(); - uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1]; - infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]')); + uploadFromLocalTab = getTabLabel(1); + infoMatIcon = getTabInfoButton(); expect(uploadFromLocalTab.nativeElement.getAttribute('aria-disabled')).toBe('false'); expect(infoMatIcon).toBeFalsy(); @@ -305,10 +307,10 @@ describe('ContentNodeSelectorComponent', () => { component.hasAllowableOperations = true; fixture.detectChanges(); - const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button')); + const adfUploadButton = getUploadButton(); expect(adfUploadButton).not.toBeNull(); - expect(adfUploadButton.nativeElement.disabled).toBe(true); + expect(adfUploadButton.disabled).toBe(true); }); it('should be able to enable UploadButton if showingSearch set to false', () => { @@ -317,10 +319,10 @@ describe('ContentNodeSelectorComponent', () => { component.hasAllowableOperations = true; fixture.detectChanges(); - const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button')); + const adfUploadButton = getUploadButton(); expect(adfUploadButton).not.toBeNull(); - expect(adfUploadButton.nativeElement.disabled).toBe(false); + expect(adfUploadButton.disabled).toBe(false); }); it('should be able to show warning message while searching', () => { @@ -330,7 +332,7 @@ describe('ContentNodeSelectorComponent', () => { selectTabByIndex(1); fixture.detectChanges(); - const infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]')); + const infoMatIcon = getTabInfoButton(); const iconTooltipMessage = infoMatIcon.attributes['ng-reflect-message']; const expectedMessage = 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE'; @@ -354,10 +356,10 @@ describe('ContentNodeSelectorComponent', () => { selectTabByIndex(1); fixture.detectChanges(); - const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button')); + const adfUploadButton = getUploadButton(); expect(adfUploadButton).not.toBeNull(); - expect(adfUploadButton.nativeElement.disabled).toBe(true); + expect(adfUploadButton.disabled).toBe(true); }); it('should be able to enable UploadButton if user has allowable operations', () => { @@ -365,10 +367,10 @@ describe('ContentNodeSelectorComponent', () => { component.hasAllowableOperations = true; fixture.detectChanges(); - const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button')); + const adfUploadButton = getUploadButton(); expect(adfUploadButton).not.toBeNull(); - expect(adfUploadButton.nativeElement.disabled).toBe(false); + expect(adfUploadButton.disabled).toBe(false); }); it('should not be able to show warning message if user has allowable operations', () => { @@ -388,7 +390,7 @@ describe('ContentNodeSelectorComponent', () => { selectTabByIndex(1); fixture.detectChanges(); - const infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]')); + const infoMatIcon = getTabInfoButton(); const iconTooltipMessage = infoMatIcon.attributes['ng-reflect-message']; const expectedMessage = 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE'; @@ -424,11 +426,11 @@ describe('ContentNodeSelectorComponent', () => { }); it('should tabs be headless when local upload is not enabled', () => { - component.data.showLocalUploadButton = false; - fixture.detectChanges(); - const tabGroup = fixture.debugElement.queryAll(By.css('.adf-content-node-selector-headless-tabs'))[0]; + component.data.showLocalUploadButton = false; + fixture.detectChanges(); + const tabGroup = fixture.debugElement.queryAll(By.css('.adf-content-node-selector-headless-tabs'))[0]; - expect(tabGroup).not.toBe(undefined); + expect(tabGroup).not.toBe(undefined); }); it('should tabs show headers when local upload is enabled', () => { @@ -441,12 +443,14 @@ describe('ContentNodeSelectorComponent', () => { }); describe('Drag and drop area', () => { + const getEmptyList = () => fixture.nativeElement.querySelector('[data-automation-id="adf-empty-list"]'); + it('should uploadStarted be false by default', () => { expect(component.uploadStarted).toBe(false); }); it('should uploadStarted become true when the first upload gets started', () => { - const fileUploadEvent = new FileUploadEvent(new FileModel({ name: 'fake-name', size: 100 } as File)); + const fileUploadEvent = new FileUploadEvent(new FileModel({ name: 'fake-name', size: 100 } as File)); uploadService.fileUploadStarting.next(fileUploadEvent); expect(component.uploadStarted).toBe(true); @@ -454,12 +458,13 @@ describe('ContentNodeSelectorComponent', () => { it('should show drag and drop area with the empty list template when no upload has started', async () => { enableLocalUpload(); - const uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1]; + const uploadFromLocalTab = getTabLabel(1); uploadFromLocalTab.nativeElement.click(); fixture.detectChanges(); await fixture.whenRenderingDone(); - const emptyListTemplate = fixture.nativeElement.querySelector('[data-automation-id="adf-empty-list"]'); + + const emptyListTemplate = getEmptyList(); const dragAndDropArea = fixture.debugElement.query(By.css('.adf-upload-drag-area')); expect(emptyListTemplate).not.toBeNull(); @@ -468,19 +473,21 @@ describe('ContentNodeSelectorComponent', () => { it('should not show the empty list template when an upload has started', async () => { enableLocalUpload(); - const uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1]; + const uploadFromLocalTab = getTabLabel(1); uploadFromLocalTab.nativeElement.click(); component.uploadStarted = true; fixture.detectChanges(); await fixture.whenRenderingDone(); - const emptyListTemplate = fixture.nativeElement.querySelector('[data-automation-id="adf-empty-list"]'); + const emptyListTemplate = getEmptyList(); expect(emptyListTemplate).toBeNull(); }); }); describe('Selected nodes counter', () => { + const getNodeCounter = () => fixture.debugElement.nativeElement.querySelector('adf-node-counter'); + it('should getSelectedCount return 0 by default', () => { expect(component.getSelectedCount()).toBe(0); }); @@ -494,19 +501,19 @@ describe('ContentNodeSelectorComponent', () => { it('should show the counter depending on the action', () => { component.action = NodeAction.ATTACH; fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).not.toBe(null); + expect(getNodeCounter()).not.toBe(null); component.action = NodeAction.CHOOSE; fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).not.toBe(null); + expect(getNodeCounter()).not.toBe(null); component.action = NodeAction.COPY; fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).toBe(null); + expect(getNodeCounter()).toBe(null); component.action = NodeAction.MOVE; fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).toBe(null); + expect(getNodeCounter()).toBe(null); }); }); }); diff --git a/lib/content-services/src/lib/content-node-share/content-node-share.dialog.spec.ts b/lib/content-services/src/lib/content-node-share/content-node-share.dialog.spec.ts index 9ccb780a28..51fa1e1e08 100644 --- a/lib/content-services/src/lib/content-node-share/content-node-share.dialog.spec.ts +++ b/lib/content-services/src/lib/content-node-share/content-node-share.dialog.spec.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { TestBed, fakeAsync, ComponentFixture, tick } from '@angular/core/testing'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; import { of } from 'rxjs'; import { NotificationService, AppConfigService } from '@alfresco/adf-core'; @@ -28,8 +28,12 @@ import { TranslateModule } from '@ngx-translate/core'; import { format, endOfDay } from 'date-fns'; import { By } from '@angular/platform-browser'; import { NodeEntry } from '@alfresco/js-api'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing'; describe('ShareDialogComponent', () => { + let loader: HarnessLoader; let node: NodeEntry; let matDialog: MatDialog; const notificationServiceMock = { @@ -45,8 +49,6 @@ describe('ShareDialogComponent', () => { const shareToggleId = '[data-automation-id="adf-share-toggle"]'; const expireToggle = '[data-automation-id="adf-expire-toggle"]'; - const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList; - const fillInDatepickerInput = (value: string) => { const input = fixture.debugElement.query(By.css('.adf-share-link__input')).nativeElement; input.value = value; @@ -55,10 +57,6 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); }; - const clickExpireToggleButton = () => fixture.nativeElement.querySelector(`${expireToggle} label`).dispatchEvent(new MouseEvent('click')); - - const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`).dispatchEvent(new MouseEvent('click')); - beforeEach(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), ContentTestingModule], @@ -99,6 +97,7 @@ describe('ShareDialogComponent', () => { }; spyOn(nodesApiService, 'updateNode').and.returnValue(of(null)); + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => { @@ -133,7 +132,7 @@ describe('ShareDialogComponent', () => { }); }); - it(`should toggle share action when property 'sharedId' does not exists`, () => { + it(`should toggle share action when property 'sharedId' does not exists`, async () => { spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue( of({ entry: { id: 'sharedId', sharedId: 'sharedId' } @@ -151,7 +150,9 @@ describe('ShareDialogComponent', () => { expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalled(); expect(renditionService.getNodeRendition).toHaveBeenCalled(); expect(fixture.nativeElement.querySelector('input[formcontrolname="sharedUrl"]').value).toBe('some-url/sharedId'); - expect(getShareToggleLinkedClasses()).toContain('mat-checked'); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); + expect(await toggle.isChecked()).toBe(true); }); it(`should not toggle share action when file has 'sharedId' property`, async () => { @@ -176,10 +177,12 @@ describe('ShareDialogComponent', () => { expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled(); expect(fixture.nativeElement.querySelector('input[formcontrolname="sharedUrl"]').value).toBe('some-url/sharedId'); - expect(getShareToggleLinkedClasses()).toContain('mat-checked'); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); + expect(await toggle.isChecked()).toBe(true); }); - it('should open a confirmation dialog when unshare button is triggered', () => { + it('should open a confirmation dialog when unshare button is triggered', async () => { spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any); spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough(); @@ -192,14 +195,13 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); - clickShareToggleButton(); - - fixture.detectChanges(); + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); + await toggle.toggle(); expect(matDialog.open).toHaveBeenCalled(); }); - it('should unshare file when confirmation dialog returns true', fakeAsync(() => { + it('should unshare file when confirmation dialog returns true', async () => { spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(true) } as any); spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({})); node.entry.properties['qshare:sharedId'] = 'sharedId'; @@ -211,14 +213,13 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); - clickShareToggleButton(); - - fixture.detectChanges(); + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); + await toggle.toggle(); expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled(); - })); + }); - it('should not unshare file when confirmation dialog returns false', fakeAsync(() => { + it('should not unshare file when confirmation dialog returns false', async () => { spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any); spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough(); node.entry.properties['qshare:sharedId'] = 'sharedId'; @@ -230,14 +231,13 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); - clickShareToggleButton(); - - fixture.detectChanges(); + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); + await toggle.toggle(); expect(sharedLinksApiService.deleteSharedLink).not.toHaveBeenCalled(); - })); + }); - it('should not allow unshare when node has no update permission', () => { + it('should not allow unshare when node has no update permission', async () => { node.entry.properties['qshare:sharedId'] = 'sharedId'; node.entry.allowableOperations = []; @@ -248,7 +248,8 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); - expect(getShareToggleLinkedClasses()).toContain('mat-disabled'); + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); + expect(await toggle.isChecked()).toBe(true); }); it('should delete the current link generated with expiry date and generate a new link without expiry date when toggle is unchecked', async () => { @@ -266,9 +267,9 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); component.form.controls['time'].setValue(new Date()); fixture.detectChanges(); - clickExpireToggleButton(); - fixture.detectChanges(); - await fixture.whenStable(); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle })); + await toggle.toggle(); expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled(); expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith('nodeId', undefined); @@ -286,7 +287,9 @@ describe('ShareDialogComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - expect(fixture.nativeElement.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"]').classList).toContain('mat-disabled'); + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: `[data-automation-id="adf-expire-toggle"]` })); + expect(await toggle.isDisabled()).toBe(true); + expect(fixture.nativeElement.querySelector('[data-automation-id="adf-slide-toggle-checked"]').style.display).toEqual('none'); }); @@ -303,18 +306,19 @@ describe('ShareDialogComponent', () => { }; }); - it('should update node with input date and end of day time when type is `date`', fakeAsync(() => { + it('should update node with input date and end of day time when type is `date`', async () => { const dateTimePickerType = 'date'; const date = new Date('2525-01-01'); spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType as any); fixture.detectChanges(); - clickExpireToggleButton(); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle })); + await toggle.toggle(); fixture.componentInstance.time.setValue(date); component.onTimeChanged(); fixture.detectChanges(); - tick(500); const expiryDate = format(endOfDay(date as Date), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`); @@ -323,11 +327,14 @@ describe('ShareDialogComponent', () => { nodeId: 'nodeId', expiresAt: expiryDate }); - })); + }); - it('should not update node when provided date is less than minDate', () => { + it('should not update node when provided date is less than minDate', async () => { fixture.detectChanges(); - clickExpireToggleButton(); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle })); + await toggle.toggle(); + fillInDatepickerInput('01.01.2010'); expect(component.form.invalid).toBeTrue(); @@ -335,9 +342,12 @@ describe('ShareDialogComponent', () => { expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled(); }); - it('should not accept alphabets in the datepicker input', () => { + it('should not accept alphabets in the datepicker input', async () => { fixture.detectChanges(); - clickExpireToggleButton(); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle })); + await toggle.toggle(); + fillInDatepickerInput('test'); expect(component.form.invalid).toBeTrue(); @@ -346,7 +356,10 @@ describe('ShareDialogComponent', () => { it('should show an error if provided date is invalid', async () => { fixture.detectChanges(); - clickExpireToggleButton(); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle })); + await toggle.toggle(); + fillInDatepickerInput('incorrect'); fixture.detectChanges(); @@ -358,9 +371,12 @@ describe('ShareDialogComponent', () => { expect(component.time.hasError('invalidDate')).toBeTrue(); }); - it('should not show an error when provided date is valid', () => { + it('should not show an error when provided date is valid', async () => { fixture.detectChanges(); - clickExpireToggleButton(); + + const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle })); + await toggle.toggle(); + fillInDatepickerInput('12.12.2525'); const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]')); diff --git a/lib/content-services/src/lib/dialogs/folder.dialog.html b/lib/content-services/src/lib/dialogs/folder.dialog.html index 137649a60a..56d8b6d3c4 100644 --- a/lib/content-services/src/lib/dialogs/folder.dialog.html +++ b/lib/content-services/src/lib/dialogs/folder.dialog.html @@ -1,4 +1,4 @@ -

+

{{ (editing ? editTitle : createTitle) | translate }}

diff --git a/lib/content-services/src/lib/dialogs/folder.dialog.spec.ts b/lib/content-services/src/lib/dialogs/folder.dialog.spec.ts index e0df827bf5..63418db8f3 100644 --- a/lib/content-services/src/lib/dialogs/folder.dialog.spec.ts +++ b/lib/content-services/src/lib/dialogs/folder.dialog.spec.ts @@ -35,13 +35,8 @@ describe('FolderDialogComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], - providers: [ - { provide: MatDialogRef, useValue: dialogRef } - ] + imports: [TranslateModule.forRoot(), ContentTestingModule], + providers: [{ provide: MatDialogRef, useValue: dialogRef }] }); dialogRef.close.calls.reset(); fixture = TestBed.createComponent(FolderDialogComponent); @@ -54,7 +49,6 @@ describe('FolderDialogComponent', () => { }); describe('Edit', () => { - beforeEach(() => { component.data = { folder: { @@ -100,16 +94,13 @@ describe('FolderDialogComponent', () => { component.submit(); - expect(nodesApi.updateNode).toHaveBeenCalledWith( - 'node-id', - { - name: 'folder-name-update', - properties: { - 'cm:title': 'folder-title-update', - 'cm:description': 'folder-description-update' - } + expect(nodesApi.updateNode).toHaveBeenCalledWith('node-id', { + name: 'folder-name-update', + properties: { + 'cm:title': 'folder-title-update', + 'cm:description': 'folder-description-update' } - ); + }); }); it('should call dialog to close with form data when submit is successfully', () => { @@ -174,10 +165,10 @@ describe('FolderDialogComponent', () => { }); it('should have the proper title', () => { - const title = fixture.debugElement.query(By.css('[mat-dialog-title]')); + const title = fixture.debugElement.query(By.css(`[data-automation-id="adf-folder-dialog-title"]`)); expect(title === null).toBe(false); expect(title.nativeElement.innerText.trim()).toBe('CORE.FOLDER_DIALOG.CREATE_FOLDER_TITLE'); - }); + }); it('should init form with empty inputs', () => { expect(component.name).toBe(''); @@ -201,17 +192,14 @@ describe('FolderDialogComponent', () => { component.submit(); - expect(nodesApi.createFolder).toHaveBeenCalledWith( - 'parentNodeId', - { - name: 'folder-name-update', - properties: { - 'cm:title': 'folder-title-update', - 'cm:description': 'folder-description-update' - }, - nodeType: 'cm:folder' - } - ); + expect(nodesApi.createFolder).toHaveBeenCalledWith('parentNodeId', { + name: 'folder-name-update', + properties: { + 'cm:title': 'folder-title-update', + 'cm:description': 'folder-description-update' + }, + nodeType: 'cm:folder' + }); }); it('should submit updated values if form is valid (with custom nodeType)', () => { @@ -224,17 +212,14 @@ describe('FolderDialogComponent', () => { component.submit(); - expect(nodesApi.createFolder).toHaveBeenCalledWith( - 'parentNodeId', - { - name: 'folder-name-update', - properties: { - 'cm:title': 'folder-title-update', - 'cm:description': 'folder-description-update' - }, - nodeType: 'cm:sushi' - } - ); + expect(nodesApi.createFolder).toHaveBeenCalledWith('parentNodeId', { + name: 'folder-name-update', + properties: { + 'cm:title': 'folder-title-update', + 'cm:description': 'folder-description-update' + }, + nodeType: 'cm:sushi' + }); }); it('should call dialog to close with form data when submit is successfully', () => { @@ -315,5 +300,5 @@ describe('FolderDialogComponent', () => { component.submit(); }); }); - }); + }); }); diff --git a/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-dialog.component.spec.ts b/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-dialog.component.spec.ts index 23d3212785..15e6e9805e 100644 --- a/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-dialog.component.spec.ts +++ b/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-dialog.component.spec.ts @@ -26,9 +26,12 @@ import { ContentTestingModule } from '../../../testing/content.testing.module'; import { AddPermissionDialogComponent } from './add-permission-dialog.component'; import { AddPermissionDialogData } from './add-permission-dialog-data.interface'; import { fakeAuthorityResults } from '../../../mock/add-permission.component.mock'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatSelectHarness } from '@angular/material/select/testing'; describe('AddPermissionDialog', () => { - + let loader: HarnessLoader; let fixture: ComponentFixture; let component: AddPermissionDialogComponent; let element: HTMLElement; @@ -53,7 +56,7 @@ describe('AddPermissionDialog', () => { role: 'Consumer' } ], - confirm: new Subject () + confirm: new Subject() }; const dialogRef = { close: jasmine.createSpy('close') @@ -61,10 +64,7 @@ describe('AddPermissionDialog', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], + imports: [TranslateModule.forRoot(), ContentTestingModule], providers: [ { provide: MatDialogRef, useValue: dialogRef }, { provide: MAT_DIALOG_DATA, useValue: data } @@ -74,12 +74,15 @@ describe('AddPermissionDialog', () => { component = fixture.componentInstance; element = fixture.nativeElement; fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => { fixture.destroy(); }); + const getConfirmButton = () => element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + it('should show the INJECTED title', () => { const titleElement = fixture.debugElement.query(By.css('#add-permission-dialog-title')); expect(titleElement).not.toBeNull(); @@ -94,27 +97,31 @@ describe('AddPermissionDialog', () => { }); it('should disable the confirm button when no selection is applied', () => { - const confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + const confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBeTruthy(); }); it('should enable the button when a selection is done', async () => { - const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance; + const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query( + By.directive(AddPermissionPanelComponent) + ).componentInstance; addPermissionPanelComponent.select.emit(fakeAuthorityResults); - let confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + let confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBeTruthy(); fixture.detectChanges(); await fixture.whenStable(); - confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(false); }); it('should update the role after selection', async () => { spyOn(component, 'onMemberUpdate').and.callThrough(); - const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance; - let confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query( + By.directive(AddPermissionPanelComponent) + ).componentInstance; + let confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(true); addPermissionPanelComponent.select.emit([fakeAuthorityResults[0]]); @@ -127,17 +134,12 @@ describe('AddPermissionDialog', () => { fixture.detectChanges(); await fixture.whenStable(); - const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger'))); - selectBox.nativeElement.dispatchEvent(new Event('click')); - fixture.detectChanges(); + const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` })); + await select.open(); - const options = fixture.debugElement.queryAll(By.css('mat-option')); - expect(options).not.toBeNull(); + const options = await select.getOptions(); expect(options.length).toBe(2); - options[0].triggerEventHandler('click', {}); - - fixture.detectChanges(); - await fixture.whenStable(); + await options[0].click(); expect(component.onMemberUpdate).toHaveBeenCalled(); @@ -147,7 +149,7 @@ describe('AddPermissionDialog', () => { currentSelection = selection; }); - confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(false); confirmButton.click(); @@ -156,8 +158,10 @@ describe('AddPermissionDialog', () => { it('should update all the user role on header column update', async () => { spyOn(component, 'onBulkUpdate').and.callThrough(); - const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance; - let confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query( + By.directive(AddPermissionPanelComponent) + ).componentInstance; + let confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(true); addPermissionPanelComponent.select.emit(fakeAuthorityResults); @@ -170,19 +174,12 @@ describe('AddPermissionDialog', () => { fixture.detectChanges(); await fixture.whenStable(); - const selectBox = fixture.debugElement.query(By.css(('[id="adf-bulk-select-role-permission"] .mat-select-trigger'))); - selectBox.nativeElement.dispatchEvent(new Event('click')); + const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-bulk-select-role-permission` })); + await select.open(); - fixture.detectChanges(); - await fixture.whenStable(); - - const options = fixture.debugElement.queryAll(By.css('mat-option')); - expect(options).not.toBeNull(); + const options = await select.getOptions(); expect(options.length).toBe(2); - options[0].triggerEventHandler('click', {}); - - fixture.detectChanges(); - await fixture.whenStable(); + await options[0].click(); expect(component.onBulkUpdate).toHaveBeenCalled(); @@ -190,7 +187,7 @@ describe('AddPermissionDialog', () => { expect(selection.length).toBe(3); }); - confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(false); confirmButton.click(); }); @@ -198,8 +195,10 @@ describe('AddPermissionDialog', () => { it('should delete the user after selection', async () => { spyOn(component, 'onMemberUpdate').and.callThrough(); spyOn(component, 'onMemberDelete').and.callThrough(); - const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance; - let confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query( + By.directive(AddPermissionPanelComponent) + ).componentInstance; + let confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(true); addPermissionPanelComponent.select.emit(fakeAuthorityResults); @@ -212,22 +211,16 @@ describe('AddPermissionDialog', () => { fixture.detectChanges(); await fixture.whenStable(); - const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger'))); - selectBox.nativeElement.dispatchEvent(new Event('click')); + const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` })); + await select.open(); - fixture.detectChanges(); - await fixture.whenStable(); - - const options = fixture.debugElement.queryAll(By.css('mat-option')); - expect(options).not.toBeNull(); + const options = await select.getOptions(); expect(options.length).toBe(2); - options[0].triggerEventHandler('click', {}); - fixture.detectChanges(); - await fixture.whenStable(); + await options[0].click(); expect(component.onMemberUpdate).toHaveBeenCalled(); - confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + confirmButton = getConfirmButton(); expect(confirmButton.disabled).toBe(true); const deleteButton = element.querySelectorAll('[data-automation-id="adf-delete-permission-button"]') as any; deleteButton[1].click(); @@ -246,7 +239,9 @@ describe('AddPermissionDialog', () => { }); it('should stream the confirmed selection on the confirm subject', async () => { - const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance; + const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query( + By.directive(AddPermissionPanelComponent) + ).componentInstance; addPermissionPanelComponent.select.emit(fakeAuthorityResults); fixture.detectChanges(); @@ -255,7 +250,7 @@ describe('AddPermissionDialog', () => { let authorityResult = fixture.debugElement.query(By.css('[data-automation-id="datatable-row-0"]')); expect(authorityResult).toBeNull(); - const confirmButton = element.querySelector('[data-automation-id="add-permission-dialog-confirm-button"]'); + const confirmButton = getConfirmButton(); confirmButton.click(); fixture.detectChanges(); diff --git a/lib/content-services/src/lib/permission-manager/components/permission-container/permission-container.component.spec.ts b/lib/content-services/src/lib/permission-manager/components/permission-container/permission-container.component.spec.ts index a45fcc70a3..7550775b7c 100644 --- a/lib/content-services/src/lib/permission-manager/components/permission-container/permission-container.component.spec.ts +++ b/lib/content-services/src/lib/permission-manager/components/permission-container/permission-container.component.spec.ts @@ -16,23 +16,23 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { TranslateModule } from '@ngx-translate/core'; import { PermissionContainerComponent } from './permission-container.component'; import { ContentTestingModule } from '../../../testing/content.testing.module'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatSelectHarness } from '@angular/material/select/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; describe('PermissionContainerComponent', () => { - + let loader: HarnessLoader; let fixture: ComponentFixture; let component: PermissionContainerComponent; let element: HTMLElement; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); fixture = TestBed.createComponent(PermissionContainerComponent); component = fixture.componentInstance; @@ -60,6 +60,7 @@ describe('PermissionContainerComponent', () => { ]; fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => { @@ -72,26 +73,24 @@ describe('PermissionContainerComponent', () => { expect(element.querySelector('#adf-select-role-permission').textContent).toContain('consumer'); }); - it('should emit update event on role change', () => { + it('should emit update event on role change', async () => { spyOn(component.update, 'emit'); - const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger'))); - selectBox.triggerEventHandler('click', null); - fixture.detectChanges(); + const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` })); + await select.open(); - const options = fixture.debugElement.queryAll(By.css('mat-option')); - expect(options).not.toBeNull(); + const options = await select.getOptions(); expect(options.length).toBe(2); - options[0].triggerEventHandler('click', {}); - fixture.detectChanges(); + await options[0].click(); expect(component.update.emit).toHaveBeenCalledWith({ role: 'Test', permission: component.permissions[0] }); }); - it('should delete update event on row delete', () => { + it('should delete update event on row delete', async () => { spyOn(component.delete, 'emit'); - const deleteButton: HTMLButtonElement = element.querySelector('[data-automation-id="adf-delete-permission-button-GROUP_EVERYONE"]'); - deleteButton.click(); - fixture.detectChanges(); + const deleteButton = await loader.getHarness( + MatButtonHarness.with({ selector: `[data-automation-id="adf-delete-permission-button-GROUP_EVERYONE"]` }) + ); + await deleteButton.click(); expect(component.delete.emit).toHaveBeenCalledWith(component.permissions[0]); }); }); diff --git a/lib/content-services/src/lib/permission-manager/components/permission-list/permission-list.component.spec.ts b/lib/content-services/src/lib/permission-manager/components/permission-list/permission-list.component.spec.ts index 5a76093cfe..c7c91b0bbb 100644 --- a/lib/content-services/src/lib/permission-manager/components/permission-list/permission-list.component.spec.ts +++ b/lib/content-services/src/lib/permission-manager/components/permission-list/permission-list.component.spec.ts @@ -16,7 +16,6 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { TranslateModule } from '@ngx-translate/core'; import { of, throwError } from 'rxjs'; import { SearchService } from '../../../search/services/search.service'; @@ -36,8 +35,13 @@ import { import { ContentTestingModule } from '../../../testing/content.testing.module'; import { Node } from '@alfresco/js-api'; import { NodesApiService } from '../../../common/services/nodes-api.service'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing'; +import { MatSelectHarness } from '@angular/material/select/testing'; describe('PermissionListComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: PermissionListComponent; let element: HTMLElement; @@ -64,6 +68,7 @@ describe('PermissionListComponent', () => { searchQuerySpy = spyOn(searchApiService, 'searchByQueryBody').and.returnValue(of(fakeEmptyResponse)); component.nodeId = 'fake-node-id'; fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => { @@ -117,7 +122,9 @@ describe('PermissionListComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined(); + const toggle = await loader.getHarness(MatSlideToggleHarness); + expect(await toggle.isChecked()).toBe(true); + expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe( 'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON' ); @@ -127,10 +134,11 @@ describe('PermissionListComponent', () => { it('should toggle the inherited button', async () => { getNodeSpy.and.returnValue(of(fakeNodeInheritedOnly)); component.ngOnInit(); - fixture.detectChanges(); - expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined(); + const toggle = await loader.getHarness(MatSlideToggleHarness); + expect(await toggle.isChecked()).toBe(true); + expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe( 'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON' ); @@ -138,12 +146,8 @@ describe('PermissionListComponent', () => { spyOn(nodeService, 'updateNode').and.returnValue(of(fakeLocalPermission)); - const slider = fixture.debugElement.query(By.css('mat-slide-toggle')); - slider.triggerEventHandler('change', { source: { checked: false } }); + await toggle.uncheck(); - fixture.detectChanges(); - - expect(element.querySelector('.adf-inherit-container .mat-checked')).toBe(null); expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe( 'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.OFF' ); @@ -157,7 +161,9 @@ describe('PermissionListComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined(); + const toggle = await loader.getHarness(MatSlideToggleHarness); + expect(await toggle.isChecked()).toBe(true); + expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe( 'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON' ); @@ -165,13 +171,8 @@ describe('PermissionListComponent', () => { spyOn(nodeService, 'updateNode').and.returnValue(of(fakeLocalPermission)); - const slider = fixture.debugElement.query(By.css('mat-slide-toggle')); - slider.triggerEventHandler('change', { source: { checked: false } }); + await toggle.uncheck(); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined(); expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe( 'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON' ); @@ -206,17 +207,16 @@ describe('PermissionListComponent', () => { expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE'); expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor'); - const selectBox = fixture.debugElement.query(By.css('[id="adf-select-role-permission"] .mat-select-trigger')); - selectBox.triggerEventHandler('click', null); - fixture.detectChanges(); + const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` })); + await select.open(); - const options = fixture.debugElement.queryAll(By.css('mat-option')); - expect(options).not.toBeNull(); + const options = await select.getOptions(); expect(options.length).toBe(4); - expect(options[0].nativeElement.innerText).toContain('ADF.ROLES.SITECOLLABORATOR'); - expect(options[1].nativeElement.innerText).toContain('ADF.ROLES.SITECONSUMER'); - expect(options[2].nativeElement.innerText).toContain('ADF.ROLES.SITECONTRIBUTOR'); - expect(options[3].nativeElement.innerText).toContain('ADF.ROLES.SITEMANAGER'); + + expect(await options[0].getText()).toContain('ADF.ROLES.SITECOLLABORATOR'); + expect(await options[1].getText()).toContain('ADF.ROLES.SITECONSUMER'); + expect(await options[2].getText()).toContain('ADF.ROLES.SITECONTRIBUTOR'); + expect(await options[3].getText()).toContain('ADF.ROLES.SITEMANAGER'); }); it('should show readonly member for site manager to toggle the inherit permission', async () => { @@ -247,14 +247,12 @@ describe('PermissionListComponent', () => { expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE'); expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor'); - const selectBox = fixture.debugElement.query(By.css('[id="adf-select-role-permission"] .mat-select-trigger')); - selectBox.triggerEventHandler('click', null); - fixture.detectChanges(); - const options = fixture.debugElement.queryAll(By.css('mat-option')); - expect(options).not.toBeNull(); + const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` })); + await select.open(); + + const options = await select.getOptions(); expect(options.length).toBe(5); - options[3].triggerEventHandler('click', {}); - fixture.detectChanges(); + await options[3].click(); expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', { permissions: { locallySet: [{ accessStatus: 'ALLOWED', name: 'Editor', authorityId: 'GROUP_EVERYONE' }] } }); diff --git a/lib/content-services/src/lib/permission-manager/components/user-icon-column/user-icon-column.component.spec.ts b/lib/content-services/src/lib/permission-manager/components/user-icon-column/user-icon-column.component.spec.ts index de5b27501f..fcbeef42af 100644 --- a/lib/content-services/src/lib/permission-manager/components/user-icon-column/user-icon-column.component.spec.ts +++ b/lib/content-services/src/lib/permission-manager/components/user-icon-column/user-icon-column.component.spec.ts @@ -22,35 +22,33 @@ import { UserIconColumnComponent } from './user-icon-column.component'; import { NodeEntry } from '@alfresco/js-api'; describe('UserIconColumnComponent', () => { - let fixture: ComponentFixture; let component: UserIconColumnComponent; let element: HTMLElement; - const person = { + const person = { firstName: 'fake', lastName: 'user', email: 'fake@test.com' }; - const group = { + const group = { id: 'fake-id', displayName: 'fake authority' }; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); - fixture = TestBed.createComponent(UserIconColumnComponent); + fixture = TestBed.createComponent(UserIconColumnComponent); component = fixture.componentInstance; element = fixture.nativeElement; fixture.detectChanges(); }); describe('person initial', () => { + const getInitials = () => element.querySelector('[data-automation-id="user-initials-image"]')?.textContent; + it('should render person value from context', () => { component.context = { row: { @@ -61,7 +59,7 @@ describe('UserIconColumnComponent', () => { }; component.ngOnInit(); fixture.detectChanges(); - expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('fu'); + expect(getInitials()).toContain('fu'); }); it('should render person value from node', () => { @@ -69,8 +67,8 @@ describe('UserIconColumnComponent', () => { entry: { nodeType: 'cm:person', properties: { - 'cm:firstName': 'Fake', - 'cm:lastName': 'User', + 'cm:firstName': 'Fake', + 'cm:lastName': 'User', 'cm:email': 'fake-user@test.com', 'cm:userName': 'fake-user' } @@ -78,11 +76,13 @@ describe('UserIconColumnComponent', () => { } as NodeEntry; component.ngOnInit(); fixture.detectChanges(); - expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('FU'); + expect(getInitials()).toContain('FU'); }); }); describe('group initial', () => { + const getGroupIcon = () => element.querySelector('[id="group-icon"] .adf-group-icon'); + it('should render group value from context', () => { component.context = { row: { @@ -93,8 +93,8 @@ describe('UserIconColumnComponent', () => { }; component.ngOnInit(); fixture.detectChanges(); - expect(element.querySelector('[id="group-icon"] mat-icon')).toBeDefined(); - expect(element.querySelector('[id="group-icon"] mat-icon').textContent).toContain('people_alt_outline'); + expect(getGroupIcon()).toBeDefined(); + expect(getGroupIcon().textContent).toContain('people_alt_outline'); }); it('should render person value from node', () => { @@ -102,14 +102,14 @@ describe('UserIconColumnComponent', () => { entry: { nodeType: 'cm:authorityContainer', properties: { - 'cm:authorityName': 'Fake authorityN' + 'cm:authorityName': 'Fake authorityN' } } } as NodeEntry; component.ngOnInit(); fixture.detectChanges(); - expect(element.querySelector('[id="group-icon"] mat-icon')).toBeDefined(); - expect(element.querySelector('[id="group-icon"] mat-icon').textContent).toContain('people_alt_outline'); + expect(getGroupIcon()).toBeDefined(); + expect(getGroupIcon().textContent).toContain('people_alt_outline'); }); }); diff --git a/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts b/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts index e0a2e0d535..2edd6b39ba 100644 --- a/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts @@ -20,22 +20,24 @@ import { SearchFilterList } from '../../models/search-filter-list.model'; import { ContentTestingModule } from '../../../testing/content.testing.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { sizeOptions, stepOne, stepThree } from '../../../mock'; -import { By } from '@angular/platform-browser'; import { TranslateModule } from '@ngx-translate/core'; +import { HarnessLoader, TestKey } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; describe('SearchCheckListComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: SearchCheckListComponent; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); fixture = TestBed.createComponent(SearchCheckListComponent); component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); }); it('should setup options from settings', () => { @@ -49,7 +51,7 @@ describe('SearchCheckListComponent', () => { expect(component.options.items).toEqual(options); }); - it('should handle enter key as click on checkboxes', () => { + it('should handle enter key as click on checkboxes', async () => { component.options = new SearchFilterList([ { name: 'Folder', value: `TYPE:'cm:folder'`, checked: false }, { name: 'Document', value: `TYPE:'cm:content'`, checked: false } @@ -58,13 +60,13 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox')); + const option = await loader.getHarness(MatCheckboxHarness); - optionElements[0].triggerEventHandler('keydown.enter', {}); - expect(component.options.items[0].checked).toBeTruthy(); + await (await option.host()).sendKeys(TestKey.ENTER); + expect(await option.isChecked()).toBe(true); - optionElements[0].triggerEventHandler('keydown.enter', {}); - expect(component.options.items[0].checked).toBeFalsy(); + await (await option.host()).sendKeys(TestKey.ENTER); + expect(await option.isChecked()).toBe(false); }); it('should setup operator from the settings', () => { @@ -95,21 +97,13 @@ describe('SearchCheckListComponent', () => { spyOn(component.context, 'update').and.stub(); - component.changeHandler( - { checked: true } as any, - component.options.items[0] - ); + component.changeHandler({ checked: true } as any, component.options.items[0]); expect(component.context.queryFragments[component.id]).toEqual(`TYPE:'cm:folder'`); - component.changeHandler( - { checked: true } as any, - component.options.items[1] - ); + component.changeHandler({ checked: true } as any, component.options.items[1]); - expect(component.context.queryFragments[component.id]).toEqual( - `TYPE:'cm:folder' OR TYPE:'cm:content'` - ); + expect(component.context.queryFragments[component.id]).toEqual(`TYPE:'cm:folder' OR TYPE:'cm:content'`); }); it('should reset selected boxes', () => { @@ -147,7 +141,7 @@ describe('SearchCheckListComponent', () => { }); describe('Pagination', () => { - it('should show 5 items when pageSize not defined', () => { + it('should show 5 items when pageSize not defined', async () => { component.id = 'checklist'; component.context = { queryFragments: { @@ -160,13 +154,14 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox')); - expect(optionElements.length).toEqual(5); - const labels = Array.from(optionElements).map(element => element.nativeElement.innerText); + const options = await loader.getAllHarnesses(MatCheckboxHarness); + expect(options.length).toBe(5); + + const labels = await Promise.all(options.map((element) => element.getLabelText())); expect(labels).toEqual(stepOne); }); - it('should show all items when pageSize is high', () => { + it('should show all items when pageSize is high', async () => { component.id = 'checklist'; component.context = { queryFragments: { @@ -178,14 +173,15 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox')); - expect(optionElements.length).toEqual(13); - const labels = Array.from(optionElements).map(element => element.nativeElement.innerText); + const options = await loader.getAllHarnesses(MatCheckboxHarness); + expect(options.length).toBe(13); + + const labels = await Promise.all(options.map((element) => element.getLabelText())); expect(labels).toEqual(stepThree); }); }); - it('should able to check/reset the checkbox', () => { + it('should able to check/reset the checkbox', async () => { component.id = 'checklist'; component.context = { queryFragments: { @@ -198,16 +194,15 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.query(By.css('mat-checkbox')); - optionElements.triggerEventHandler('change', { checked: true }); + const option = await loader.getHarness(MatCheckboxHarness); + await option.check(); expect(component.submitValues).toHaveBeenCalled(); - const clearAllElement = fixture.debugElement.query(By.css('button[title="SEARCH.FILTER.ACTIONS.CLEAR-ALL"]')); - clearAllElement.triggerEventHandler('click', {} ); - fixture.detectChanges(); + const clearButton = await loader.getHarness(MatButtonHarness.with({ selector: `[title="SEARCH.FILTER.ACTIONS.CLEAR-ALL"]` })); + await clearButton.click(); - const selectedElements = fixture.debugElement.queryAll(By.css('.mat-checkbox-checked')); - expect(selectedElements.length).toBe(0); + const checkedElements = await loader.getAllHarnesses(MatCheckboxHarness.with({ checked: true })); + expect(checkedElements.length).toBe(0); }); }); diff --git a/lib/content-services/src/lib/search/components/search-chip-list/search-chip-list.component.spec.ts b/lib/content-services/src/lib/search/components/search-chip-list/search-chip-list.component.spec.ts index 23b6de5bf7..d13033cac8 100644 --- a/lib/content-services/src/lib/search/components/search-chip-list/search-chip-list.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-chip-list/search-chip-list.component.spec.ts @@ -21,15 +21,13 @@ import { By } from '@angular/platform-browser'; import { SearchFacetFiltersService } from '../../services/search-facet-filters.service'; import { ContentTestingModule } from '../../../testing/content.testing.module'; import { TranslateModule } from '@ngx-translate/core'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatChipHarness, MatChipRemoveHarness } from '@angular/material/chips/testing'; @Component({ selector: 'adf-test-component', - template: ` - - - ` + template: ` ` }) class TestComponent { allowClear = true; @@ -40,23 +38,22 @@ class TestComponent { } describe('SearchChipListComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: TestComponent; let searchFacetFiltersService: SearchFacetFiltersService; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], - declarations: [ - TestComponent - ] + imports: [TranslateModule.forRoot(), ContentTestingModule], + declarations: [TestComponent] }); fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; searchFacetFiltersService = TestBed.inject(SearchFacetFiltersService); + + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); it('should display clear button only when entries present', () => { @@ -65,24 +62,26 @@ describe('SearchChipListComponent', () => { let clearButton = fixture.debugElement.query(By.css(`[data-automation-id="reset-filter"]`)); expect(clearButton).toBeNull(); - searchFacetFiltersService.selectedBuckets = [{ - bucket: { - count: 1, - label: 'test', - filterQuery: 'query' - }, - field: null - }]; + searchFacetFiltersService.selectedBuckets = [ + { + bucket: { + count: 1, + label: 'test', + filterQuery: 'query' + }, + field: null + } + ]; fixture.detectChanges(); clearButton = fixture.debugElement.query(By.css(`[data-automation-id="reset-filter"]`)); expect(clearButton).toBeDefined(); }); - it('should reflect changes in the search filter', () => { + it('should reflect changes in the search filter', async () => { const selectedBuckets = searchFacetFiltersService.selectedBuckets; fixture.detectChanges(); - let chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"]`)); + let chips = await loader.getAllHarnesses(MatChipHarness.with({ selector: '[data-automation-id="chip-list-entry"]' })); expect(chips.length).toBe(0); selectedBuckets.push({ @@ -95,7 +94,7 @@ describe('SearchChipListComponent', () => { }); fixture.detectChanges(); - chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"]`)); + chips = await loader.getAllHarnesses(MatChipHarness.with({ selector: '[data-automation-id="chip-list-entry"]' })); expect(chips.length).toBe(1); }); @@ -115,32 +114,30 @@ describe('SearchChipListComponent', () => { fixture.detectChanges(); - const chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"] .mat-chip-remove`)); - chips[0].nativeElement.click(); + const removeButton = await loader.getHarness(MatChipRemoveHarness.with({ ancestor: `[data-automation-id="chip-list-entry"]` })); + await removeButton.click(); await fixture.whenStable(); expect(searchFacetFiltersService.unselectFacetBucket).toHaveBeenCalled(); }); - it('should remove items from the search filter on clear button click', () => { + it('should remove items from the search filter on clear button click', async () => { spyOn(searchFacetFiltersService, 'unselectFacetBucket').and.stub(); - const selectedBucket1: any = { field: { id: 1 }, bucket: {label: 'bucket1'} }; - const selectedBucket2: any = { field: { id: 2 }, bucket: {label: 'bucket2'} }; + const selectedBucket1: any = { field: { id: 1 }, bucket: { label: 'bucket1' } }; + const selectedBucket2: any = { field: { id: 2 }, bucket: { label: 'bucket2' } }; searchFacetFiltersService.selectedBuckets = [selectedBucket1, selectedBucket2]; fixture.detectChanges(); - const closeButtons = fixture.debugElement.nativeElement.querySelectorAll('.mat-chip-remove'); + const closeButtons = await loader.getAllHarnesses(MatChipRemoveHarness); expect(closeButtons.length).toBe(2); - - closeButtons[0].click(); - fixture.detectChanges(); + await closeButtons[0].click(); expect(searchFacetFiltersService.unselectFacetBucket).toHaveBeenCalledWith(selectedBucket1.field, selectedBucket1.bucket); }); - it('should disable clear mode via input properties', () => { + it('should disable clear mode via input properties', async () => { spyOn(component.searchFilter, 'unselectFacetBucket').and.callThrough(); component.allowClear = false; @@ -157,10 +154,10 @@ describe('SearchChipListComponent', () => { fixture.detectChanges(); - const chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"] .mat-chip-remove`)); - expect(chips.length).toBe(1); + const closeButtons = await loader.getAllHarnesses(MatChipRemoveHarness.with({ ancestor: `[data-automation-id="chip-list-entry"]` })); + expect(closeButtons.length).toBe(1); - const clearButton = fixture.debugElement.query(By.css(`[data-automation-id="reset-filter"]`)); - expect(clearButton).toBeNull(); + const hasClearButton = await loader.hasHarness(MatChipRemoveHarness.with({ selector: `[data-automation-id="reset-filter"]` })); + expect(hasClearButton).toBe(false); }); }); diff --git a/lib/content-services/src/lib/search/components/search-date-range/search-date-range.component.spec.ts b/lib/content-services/src/lib/search/components/search-date-range/search-date-range.component.spec.ts index 0e43d82647..806b555640 100644 --- a/lib/content-services/src/lib/search/components/search-date-range/search-date-range.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-date-range/search-date-range.component.spec.ts @@ -32,10 +32,7 @@ describe('SearchDateRangeComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); fixture = TestBed.createComponent(SearchDateRangeComponent); component = fixture.componentInstance; @@ -43,6 +40,9 @@ describe('SearchDateRangeComponent', () => { afterEach(() => fixture.destroy()); + const getFromInput = () => fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const getToInput = () => fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-to-input"]'); + it('should setup form elements on init', () => { fixture.detectChanges(); @@ -74,7 +74,6 @@ describe('SearchDateRangeComponent', () => { }); it('should reset form', () => { - fixture.detectChanges(); component.form.setValue({ from: fromDate, to: toDate }); @@ -129,10 +128,13 @@ describe('SearchDateRangeComponent', () => { spyOn(context, 'update').and.stub(); fixture.detectChanges(); - component.apply({ - from: fromDate, - to: toDate - }, true); + component.apply( + { + from: fromDate, + to: toDate + }, + true + ); const startDate = startOfDay(fromDate).toISOString(); const endDate = endOfDay(toDate).toISOString(); @@ -146,7 +148,7 @@ describe('SearchDateRangeComponent', () => { it('should show date-format error when Invalid found', async () => { fixture.detectChanges(); - const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const input = getFromInput(); input.value = '10-f-18'; input.dispatchEvent(new Event('input')); @@ -159,7 +161,7 @@ describe('SearchDateRangeComponent', () => { it('should hide date-format error when correcting input', async () => { fixture.detectChanges(); - const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const input = getFromInput(); input.value = '10-f-18'; input.dispatchEvent(new Event('input')); @@ -181,7 +183,7 @@ describe('SearchDateRangeComponent', () => { component.settings = { field: 'cm:created', maxDate: 'today' }; fixture.detectChanges(); - const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const input = getFromInput(); input.value = format(addDays(new Date(), 1), 'dd-MM-yyyy'); input.dispatchEvent(new Event('input')); @@ -194,11 +196,11 @@ describe('SearchDateRangeComponent', () => { it('should show error for required constraint', async () => { fixture.detectChanges(); - const fromInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const fromInput = getFromInput(); fromInput.value = ''; fromInput.dispatchEvent(new Event('input')); - const toInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-to-input"]'); + const toInput = getToInput(); toInput.value = ''; toInput.dispatchEvent(new Event('input')); @@ -212,11 +214,11 @@ describe('SearchDateRangeComponent', () => { it('should show error for incorrect date range', async () => { fixture.detectChanges(); - const fromInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const fromInput = getFromInput(); fromInput.value = '11-10-2018'; fromInput.dispatchEvent(new Event('input')); - const toInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-to-input"]'); + const toInput = getToInput(); toInput.value = '10-10-2018'; toInput.dispatchEvent(new Event('input')); @@ -230,7 +232,7 @@ describe('SearchDateRangeComponent', () => { it('should not show date-format error when valid found', async () => { fixture.detectChanges(); - const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]'); + const input = getFromInput(); input.value = '10-10-2018'; input.dispatchEvent(new Event('input')); diff --git a/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip-tabbed/search-facet-chip-tabbed.component.spec.ts b/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip-tabbed/search-facet-chip-tabbed.component.spec.ts index bf8d91bd10..0ac62cfa0c 100644 --- a/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip-tabbed/search-facet-chip-tabbed.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip-tabbed/search-facet-chip-tabbed.component.spec.ts @@ -23,8 +23,13 @@ import { SearchFilterList } from '../../../models/search-filter-list.model'; import { SearchFacetChipTabbedComponent } from './search-facet-chip-tabbed.component'; import { FacetField } from '../../../models/facet-field.interface'; import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { HarnessLoader, TestKey } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatChipHarness } from '@angular/material/chips/testing'; +import { MatIconHarness } from '@angular/material/icon/testing'; describe('SearchFacetChipTabbedComponent', () => { + let loader: HarnessLoader; let component: SearchFacetChipTabbedComponent; let fixture: ComponentFixture; @@ -48,17 +53,9 @@ describe('SearchFacetChipTabbedComponent', () => { } }; fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); - /** - * Open the facet - */ - function openFacet() { - const chip = fixture.debugElement.query(By.css('mat-chip')); - chip.triggerEventHandler('click', {}); - fixture.detectChanges(); - } - /** * Get the filter display value * @@ -90,71 +87,92 @@ describe('SearchFacetChipTabbedComponent', () => { expect(displayValue).toBe('SEARCH.FILTER.ANY'); }); - it('should display remove icon and disable facet when no items are loaded', () => { - const chip = fixture.debugElement.query(By.css('mat-chip')); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(chip.classes['mat-chip-disabled']).toBeTrue(); - expect(icon).toEqual('remove'); + it('should display remove icon and disable facet when no items are loaded', async () => { + const chip = await loader.getHarness(MatChipHarness); + const icon = await chip.getHarness(MatIconHarness); + + expect(await chip.isDisabled()).toBe(true); + expect(await icon.getName()).toEqual('remove'); }); - it('should not open context menu when no items are loaded', () => { + it('should not open context menu when no items are loaded', async () => { spyOn(component.menuTrigger, 'openMenu'); - const chip = fixture.debugElement.query(By.css('mat-chip')).nativeElement; - chip.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' })); + + const chip = await loader.getHarness(MatChipHarness); + const host = await chip.host(); + await host.sendKeys(TestKey.ENTER); + expect(component.menuTrigger.openMenu).not.toHaveBeenCalled(); }); - it('should display correct title when facet is opened', () => { - openFacet(); + it('should display correct title when facet is opened', async () => { + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + const title = fixture.debugElement.query(By.css('.adf-search-filter-title')).nativeElement.innerText.split('\n')[0]; expect(title).toBe(component.tabbedFacet.label); }); - it('should display adf-search-facet-tabbed-content component', () => { - openFacet(); + it('should display adf-search-facet-tabbed-content component', async () => { + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + const activeTabLabel = fixture.debugElement.query(By.css('adf-search-facet-tabbed-content')); expect(activeTabLabel).toBeTruthy(); }); - it('should display arrow down icon and not disable the chip when items are loaded', () => { + it('should display arrow down icon and not disable the chip when items are loaded', async () => { component.isPopulated = true; fixture.detectChanges(); - const chip = fixture.debugElement.query(By.css('mat-chip')); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(chip.classes['mat-chip-disabled']).toBeUndefined(); - expect(icon).toEqual('keyboard_arrow_down'); + const chip = await loader.getHarness(MatChipHarness); + const icon = await chip.getHarness(MatIconHarness); + + expect(await chip.isDisabled()).toBe(false); + expect(await icon.getName()).toBe('keyboard_arrow_down'); }); it('should display arrow up icon when menu is opened', async () => { - openFacet(); + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + emitChildEvent('isPopulated', true); await fixture.whenStable(); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(icon).toEqual('keyboard_arrow_up'); + + const icon = await chip.getHarness(MatIconHarness); + + expect(await icon.getName()).toBe('keyboard_arrow_up'); }); - it('should update display value when new displayValue$ emitted', () => { + it('should update display value when new displayValue$ emitted', async () => { const displayValue = 'field_LABEL: test, test2'; - openFacet(); + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + emitChildEvent('displayValue$', displayValue); fixture.detectChanges(); expect(getDisplayValue()).toBe(displayValue); }); - it('should call onApply and close modal when apply btn is clicked', () => { + it('should call onApply and close modal when apply btn is clicked', async () => { spyOn(component.menuTrigger, 'closeMenu').and.callThrough(); spyOn(component, 'onApply').and.callThrough(); - openFacet(); + + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + const applyButton = fixture.debugElement.query(By.css('#apply-filter-button')); applyButton.triggerEventHandler('click', {}); expect(component.menuTrigger.closeMenu).toHaveBeenCalled(); expect(component.onApply).toHaveBeenCalled(); }); - it('should call onRemove and close modal when cancel btn is clicked', () => { + it('should call onRemove and close modal when cancel btn is clicked', async () => { spyOn(component.menuTrigger, 'closeMenu').and.callThrough(); spyOn(component, 'onRemove').and.callThrough(); - openFacet(); + + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + const applyButton = fixture.debugElement.query(By.css('#cancel-filter-button')); applyButton.triggerEventHandler('click', {}); expect(component.menuTrigger.closeMenu).toHaveBeenCalled(); diff --git a/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.html b/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.html index 67d13580c5..4f014722b9 100644 --- a/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.html +++ b/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.html @@ -5,7 +5,7 @@ [disabled]="!isPopulated()" tabIndex="0" [matMenuTriggerFor]="menu" - (onMenuOpen)="onMenuOpen()" + (menuOpened)="onMenuOpen()" (keydown.enter)="onEnterKeydown()" (keydown.escape)="onEscKeydown()" [attr.title]="facetField.displayValue$ | async" diff --git a/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.spec.ts b/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.spec.ts index 8b84cdeeb2..72c1117311 100644 --- a/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-filter-chips/search-facet-chip/search-facet-chip.component.spec.ts @@ -19,77 +19,85 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SearchFacetChipComponent } from './search-facet-chip.component'; import { ContentTestingModule } from '../../../../testing/content.testing.module'; import { TranslateModule } from '@ngx-translate/core'; -import { By } from '@angular/platform-browser'; import { SearchQueryBuilderService } from '../../../services/search-query-builder.service'; import { SearchFilterList } from '../../../models/search-filter-list.model'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatMenuHarness } from '@angular/material/menu/testing'; +import { HarnessLoader, TestKey } from '@angular/cdk/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; +import { MatIconHarness } from '@angular/material/icon/testing'; describe('SearchFacetChipComponent', () => { - let component: SearchFacetChipComponent; - let fixture: ComponentFixture; - let queryBuilder: SearchQueryBuilderService; + let loader: HarnessLoader; + let component: SearchFacetChipComponent; + let fixture: ComponentFixture; + let queryBuilder: SearchQueryBuilderService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] - }); - fixture = TestBed.createComponent(SearchFacetChipComponent); - component = fixture.componentInstance; - queryBuilder = TestBed.inject(SearchQueryBuilderService); - spyOn(queryBuilder, 'update').and.stub(); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), ContentTestingModule] + }); + fixture = TestBed.createComponent(SearchFacetChipComponent); + component = fixture.componentInstance; + queryBuilder = TestBed.inject(SearchQueryBuilderService); + spyOn(queryBuilder, 'update').and.stub(); - component.field = { type: 'field', label: 'f2', field: 'f2', buckets: new SearchFilterList() }; - fixture.detectChanges(); - }); - - it('should update search query on apply click', () => { - const chip = fixture.debugElement.query(By.css('mat-chip')); - chip.triggerEventHandler('click', { stopPropagation: () => null }); + component.field = { type: 'field', label: 'f2', field: 'f2', buckets: new SearchFilterList() }; fixture.detectChanges(); - const applyButton = fixture.debugElement.query(By.css('#apply-filter-button')); - applyButton.triggerEventHandler('click', {}); + loader = TestbedHarnessEnvironment.loader(fixture); + }); + + it('should update search query on apply click', async () => { + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + + const applyButton = await menu.getHarness(MatButtonHarness.with({ selector: '#apply-filter-button' })); + await applyButton.click(); + expect(queryBuilder.update).toHaveBeenCalled(); }); - it('should update search query on cancel click', () => { - const chip = fixture.debugElement.query(By.css('mat-chip')); - chip.triggerEventHandler('click', { stopPropagation: () => null }); - fixture.detectChanges(); - const applyButton = fixture.debugElement.query(By.css('#cancel-filter-button')); - applyButton.triggerEventHandler('click', {}); + it('should update search query on cancel click', async () => { + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + + const cancelButton = await menu.getHarness(MatButtonHarness.with({ selector: '#cancel-filter-button' })); + await cancelButton.click(); + expect(queryBuilder.update).toHaveBeenCalled(); }); - it('should display arrow down icon and not disable the chip when items are loaded', () => { + it('should display arrow down icon and not disable the chip when items are loaded', async () => { component.field.buckets.items = [{ count: 1, label: 'test', filterQuery: '' }]; - fixture.detectChanges(); - const chip = fixture.debugElement.query(By.css('mat-chip')); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(chip.classes['mat-chip-disabled']).toBeUndefined(); - expect(icon).toEqual('keyboard_arrow_down'); + + const menu = await loader.getHarness(MatMenuHarness); + expect(await menu.isDisabled()).toBe(false); + + const icon = await loader.getHarness(MatIconHarness); + expect(await icon.getName()).toBe('keyboard_arrow_down'); }); - it('should display arrow up icon when menu is opened', () => { + it('should display arrow up icon when menu is opened', async () => { component.field.buckets.items = [{ count: 1, label: 'test', filterQuery: '' }]; - component.onMenuOpen(); - fixture.detectChanges(); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(icon).toEqual('keyboard_arrow_up'); + + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + + const icon = await loader.getHarness(MatIconHarness); + expect(await icon.getName()).toBe('keyboard_arrow_up'); }); - it('should display remove icon and disable facet when no items are loaded', () => { - const chip = fixture.debugElement.query(By.css('mat-chip')); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(chip.classes['mat-chip-disabled']).toBeTrue(); - expect(icon).toEqual('remove'); + it('should display remove icon and disable facet when no items are loaded', async () => { + const menu = await loader.getHarness(MatMenuHarness); + expect(await menu.isDisabled()).toBe(true); + + const icon = await loader.getHarness(MatIconHarness); + expect(await icon.getName()).toBe('remove'); }); - it('should not open context menu when no items are loaded', () => { - spyOn(component.menuTrigger, 'openMenu'); - const chip = fixture.debugElement.query(By.css('mat-chip')).nativeElement; - chip.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' })); - expect(component.menuTrigger.openMenu).not.toHaveBeenCalled(); + it('should not open context menu when no items are loaded', async () => { + const menu = await loader.getHarness(MatMenuHarness); + await (await menu.host()).sendKeys(TestKey.ENTER); + expect(await menu.isOpen()).toBe(false); }); }); diff --git a/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.html b/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.html index f645c1dad4..75bbbe6403 100644 --- a/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.html +++ b/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.html @@ -4,7 +4,7 @@ [class.adf-search-toggle-chip]="(widget.getDisplayValue() | async) || menuTrigger.menuOpen" tabIndex="0" [matMenuTriggerFor]="menu" - (onMenuOpen)="onMenuOpen()" + (menuOpened)="onMenuOpen()" (keydown.enter)="onEnterKeydown()" (keydown.escape)="onEscKeydown()" [attr.title]="widget.getDisplayValue() | async" diff --git a/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.spec.ts b/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.spec.ts index 749e179881..a4027fb6dc 100644 --- a/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-filter-chips/search-widget-chip/search-widget-chip.component.spec.ts @@ -23,19 +23,20 @@ import { ContentTestingModule } from '../../../../testing/content.testing.module import { MatMenuModule } from '@angular/material/menu'; import { By } from '@angular/platform-browser'; import { SearchQueryBuilderService } from '../../../services/search-query-builder.service'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatChipHarness } from '@angular/material/chips/testing'; +import { MatIconHarness } from '@angular/material/icon/testing'; describe('SearchWidgetChipComponent', () => { + let loader: HarnessLoader; let component: SearchWidgetChipComponent; let fixture: ComponentFixture; let queryBuilder: SearchQueryBuilderService; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - MatMenuModule, - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [MatMenuModule, TranslateModule.forRoot(), ContentTestingModule] }); queryBuilder = TestBed.inject(SearchQueryBuilderService); fixture = TestBed.createComponent(SearchWidgetChipComponent); @@ -44,35 +45,40 @@ describe('SearchWidgetChipComponent', () => { component.category = simpleCategories[1]; fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); - it('should update search query on apply click', () => { - const chip = fixture.debugElement.query(By.css('mat-chip')); - chip.triggerEventHandler('click', { stopPropagation: () => null }); - fixture.detectChanges(); - const applyButton = fixture.debugElement.query(By.css('#apply-filter-button')); - applyButton.triggerEventHandler('click', {}); - expect(queryBuilder.update).toHaveBeenCalled(); + it('should update search query on apply click', async () => { + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + + const applyButton = fixture.debugElement.query(By.css('#apply-filter-button')); + applyButton.triggerEventHandler('click', {}); + + expect(queryBuilder.update).toHaveBeenCalled(); }); - it('should update search query on cancel click', () => { - const chip = fixture.debugElement.query(By.css('mat-chip')); - chip.triggerEventHandler('click', { stopPropagation: () => null }); - fixture.detectChanges(); - const applyButton = fixture.debugElement.query(By.css('#cancel-filter-button')); - applyButton.triggerEventHandler('click', {}); - expect(queryBuilder.update).toHaveBeenCalled(); + it('should update search query on cancel click', async () => { + const chip = await loader.getHarness(MatChipHarness); + await (await chip.host()).click(); + + const applyButton = fixture.debugElement.query(By.css('#cancel-filter-button')); + applyButton.triggerEventHandler('click', {}); + expect(queryBuilder.update).toHaveBeenCalled(); }); - it('should display arrow down icon', () => { - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(icon).toEqual('keyboard_arrow_down'); + it('should display arrow down icon', async () => { + const chip = await loader.getHarness(MatChipHarness); + const icon = await chip.getHarness(MatIconHarness); + expect(await icon.getName()).toBe('keyboard_arrow_down'); }); - it('should display arrow up icon when menu is opened', () => { - component.onMenuOpen(); - fixture.detectChanges(); - const icon = fixture.debugElement.query(By.css('mat-chip mat-icon')).nativeElement.innerText; - expect(icon).toEqual('keyboard_arrow_up'); + it('should display arrow up icon when menu is opened', async () => { + component.onMenuOpen(); + fixture.detectChanges(); + + const chip = await loader.getHarness(MatChipHarness); + const icon = await chip.getHarness(MatIconHarness); + expect(await icon.getName()).toBe('keyboard_arrow_up'); }); }); diff --git a/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts b/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts index 62a8038f4a..def44e1aac 100644 --- a/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts @@ -24,8 +24,13 @@ import { ContentTestingModule } from '../../../testing/content.testing.module'; import { SEARCH_QUERY_SERVICE_TOKEN } from '../../search-query-service.token'; import { By } from '@angular/platform-browser'; import { SearchFilterContainerComponent } from './search-filter-container.component'; -import { MatMenuTrigger } from '@angular/material/menu'; import { SearchCategory } from '../../models/search-category.interface'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatInputHarness } from '@angular/material/input/testing'; +import { MatMenuHarness } from '@angular/material/menu/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; +import { MatBadgeHarness } from '@angular/material/badge/testing'; const mockCategory: SearchCategory = { id: 'queryName', @@ -44,6 +49,7 @@ const mockCategory: SearchCategory = { }; describe('SearchFilterContainerComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: SearchFilterContainerComponent; let queryBuilder: SearchHeaderQueryBuilderService; @@ -54,10 +60,7 @@ describe('SearchFilterContainerComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], + imports: [TranslateModule.forRoot(), ContentTestingModule], providers: [ { provide: SearchService, useValue: searchMock }, { provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchHeaderQueryBuilderService } @@ -66,9 +69,10 @@ describe('SearchFilterContainerComponent', () => { fixture = TestBed.createComponent(SearchFilterContainerComponent); component = fixture.componentInstance; queryBuilder = fixture.componentInstance['searchFilterQueryBuilder']; - component.col = {key: '123', type: 'text'}; + component.col = { key: '123', type: 'text' }; spyOn(queryBuilder, 'getCategoryForColumn').and.returnValue(mockCategory); fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => { @@ -86,26 +90,23 @@ describe('SearchFilterContainerComponent', () => { }); it('should set/update the active filter after the Apply button is clicked', async () => { - const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]'); - menuButton.click(); - fixture.detectChanges(); - await fixture.whenStable(); + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + component.widgetContainer.componentRef.instance.value = 'searchText'; - const applyButton = fixture.debugElement.query(By.css('#apply-filter-button')); - applyButton.triggerEventHandler('click', {}); - fixture.detectChanges(); - await fixture.whenStable(); + + const applyButton = await menu.getHarness(MatButtonHarness.with({ selector: '#apply-filter-button' })); + await applyButton.click(); + expect(queryBuilder.getActiveFilters().length).toBe(1); expect(queryBuilder.getActiveFilters()[0].key).toBe('name'); expect(queryBuilder.getActiveFilters()[0].value).toBe('searchText'); - menuButton.click(); - fixture.detectChanges(); - await fixture.whenStable(); + await menu.open(); + component.widgetContainer.componentRef.instance.value = 'updated text'; - applyButton.triggerEventHandler('click', {}); - fixture.detectChanges(); - await fixture.whenStable(); + + await applyButton.click(); expect(queryBuilder.getActiveFilters().length).toBe(1); expect(queryBuilder.getActiveFilters()[0].key).toBe('name'); expect(queryBuilder.getActiveFilters()[0].value).toBe('updated text'); @@ -113,16 +114,15 @@ describe('SearchFilterContainerComponent', () => { it('should remove active filter after the Clear button is clicked', async () => { queryBuilder.setActiveFilter('name', 'searchText'); - const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]'); - menuButton.click(); - fixture.detectChanges(); - await fixture.whenStable(); + + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + component.widgetContainer.componentRef.instance.value = 'searchText'; - const fakeEvent = jasmine.createSpyObj('event', ['stopPropagation']); - const clearButton = fixture.debugElement.query(By.css('#clear-filter-button')); - clearButton.triggerEventHandler('click', fakeEvent); - fixture.detectChanges(); - await fixture.whenStable(); + + const clearButton = await menu.getHarness(MatButtonHarness.with({ selector: '#clear-filter-button' })); + await clearButton.click(); + expect(queryBuilder.getActiveFilters().length).toBe(0); }); @@ -133,15 +133,13 @@ describe('SearchFilterContainerComponent', () => { component.filterChange.subscribe(() => { eventRaised = true; }); - const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]'); - menuButton.click(); - fixture.detectChanges(); - await fixture.whenStable(); + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); component.widgetContainer.componentRef.instance.value = 'searchText'; const widgetContainer = fixture.debugElement.query(By.css('adf-search-widget-container')); - widgetContainer.triggerEventHandler('keypress', {key: 'Enter'}); + widgetContainer.triggerEventHandler('keypress', { key: 'Enter' }); fixture.detectChanges(); await fixture.whenStable(); @@ -150,39 +148,33 @@ describe('SearchFilterContainerComponent', () => { }); it('should hide the red dot after the filter is cleared', async () => { - const badge: HTMLElement = fixture.nativeElement.querySelector(`[data-automation-id="filter-menu-button"] .mat-badge-content`); - expect(window.getComputedStyle(badge).display).toBe('none'); + const badge = await loader.getHarness(MatBadgeHarness); + expect(await badge.isHidden()).toBe(true); + + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); - const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]'); - menuButton.click(); - fixture.detectChanges(); - await fixture.whenStable(); component.widgetContainer.componentRef.instance.value = 'searchText'; const widgetContainer = fixture.debugElement.query(By.css('adf-search-widget-container')); - widgetContainer.triggerEventHandler('keypress', {key: 'Enter'}); + widgetContainer.triggerEventHandler('keypress', { key: 'Enter' }); fixture.detectChanges(); await fixture.whenStable(); - expect(window.getComputedStyle(badge).display).not.toBe('none'); + expect(await badge.isHidden()).toBe(false); - menuButton.click(); - fixture.detectChanges(); - await fixture.whenStable(); - const fakeEvent = jasmine.createSpyObj('event', ['stopPropagation']); - const clearButton = fixture.debugElement.query(By.css('#clear-filter-button')); - clearButton.triggerEventHandler('click', fakeEvent); - fixture.detectChanges(); - await fixture.whenStable(); - expect(window.getComputedStyle(badge).display).toBe('none'); + await menu.open(); + + const clearButton = await menu.getHarness(MatButtonHarness.with({ selector: '#clear-filter-button' })); + await clearButton.click(); + + expect(await badge.isHidden()).toBe(true); }); describe('Accessibility', () => { - 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('[data-automation-id="filter-menu-button"]'); - menuButton.click(); - fixture.detectChanges(); + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); expect(component.focusTrap).toBeDefined(); // eslint-disable-next-line no-underscore-dangle @@ -190,32 +182,19 @@ describe('SearchFilterContainerComponent', () => { }); it('should focus the input element when the menu is opened', async () => { - const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]'); - menuButton.click(); - - fixture.detectChanges(); - await fixture.whenStable(); - - const inputElement = fixture.debugElement.query(By.css('.mat-input-element')); - expect(document.activeElement).toBe(inputElement.nativeElement); + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + const input = await menu.getHarness(MatInputHarness); + expect(await input.isFocused()).toBe(true); }); it('should focus the menu trigger when the menu is closed', async () => { - const menuButton: HTMLButtonElement = fixture.nativeElement.querySelector('[data-automation-id="filter-menu-button"]'); - menuButton.click(); + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); - fixture.detectChanges(); - await fixture.whenStable(); - - const matMenuTrigger = fixture.debugElement.query(By.directive(MatMenuTrigger)).injector.get(MatMenuTrigger); - matMenuTrigger.closeMenu(); - - fixture.detectChanges(); - await fixture.whenStable(); - - const matMenuButton = fixture.debugElement.query(By.css('[data-automation-id="filter-menu-button"]')); - expect(document.activeElement).toBe(matMenuButton.nativeElement); + await menu.close(); + expect(await menu.isFocused()).toBe(true); }); }); }); diff --git a/lib/content-services/src/lib/search/components/search-filter/search-filter.component.spec.ts b/lib/content-services/src/lib/search/components/search-filter/search-filter.component.spec.ts index 8a3fc9291f..5fdf889aeb 100644 --- a/lib/content-services/src/lib/search/components/search-filter/search-filter.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-filter/search-filter.component.spec.ts @@ -18,7 +18,7 @@ import { SearchFilterComponent } from './search-filter.component'; import { SearchQueryBuilderService } from '../../services/search-query-builder.service'; import { AppConfigService, TranslationService } from '@alfresco/adf-core'; -import { SearchService } from '../../services/search.service'; +import { SearchService } from '../../services/search.service'; import { Subject } from 'rxjs'; import { SearchFilterList } from '../../models/search-filter-list.model'; import { ComponentFixture, TestBed } from '@angular/core/testing'; @@ -40,8 +40,15 @@ import { import { TranslateModule } from '@ngx-translate/core'; import { SearchFacetFiltersService } from '../../services/search-facet-filters.service'; import { SearchFacetFieldComponent } from '../search-facet-field/search-facet-field.component'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatExpansionPanelHarness } from '@angular/material/expansion/testing'; +import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; +import { MatInputHarness } from '@angular/material/input/testing'; describe('SearchFilterComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: SearchFilterComponent; let queryBuilder: SearchQueryBuilderService; @@ -53,21 +60,17 @@ describe('SearchFilterComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], - providers: [ - { provide: SearchService, useValue: searchMock } - ] + imports: [TranslateModule.forRoot(), ContentTestingModule], + providers: [{ provide: SearchService, useValue: searchMock }] }); searchFacetFiltersService = TestBed.inject(SearchFacetFiltersService); queryBuilder = TestBed.inject(SearchQueryBuilderService); fixture = TestBed.createComponent(SearchFilterComponent); appConfigService = TestBed.inject(AppConfigService); const translationService = fixture.debugElement.injector.get(TranslationService); - spyOn(translationService, 'instant').and.callFake((key) => key ? `${key}_translated` : null); + spyOn(translationService, 'instant').and.callFake((key) => (key ? `${key}_translated` : null)); component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => fixture.destroy()); @@ -79,27 +82,41 @@ describe('SearchFilterComponent', () => { spyOn(queryBuilder, 'execute').and.stub(); queryBuilder.config = { categories: [], - facetFields: { fields: [ + facetFields: { + fields: [ { label: 'f1', field: 'f1' }, { label: 'f2', field: 'f2' } - ]}, + ] + }, facetQueries: { queries: [] } }; searchFacetFiltersService.responseFacets = [ - { type: 'field', label: 'f1', field: 'f1', buckets: new SearchFilterList([ - { label: 'b1', count: 10, filterQuery: 'filter', checked: true }, - { label: 'b2', count: 1, filterQuery: 'filter2' }]) }, + { + type: 'field', + label: 'f1', + field: 'f1', + buckets: new SearchFilterList([ + { label: 'b1', count: 10, filterQuery: 'filter', checked: true }, + { label: 'b2', count: 1, filterQuery: 'filter2' } + ]) + }, { type: 'field', label: 'f2', field: 'f2', buckets: new SearchFilterList([]) } ]; queryBuilder.addUserFacetBucket('f1', searchFacetFiltersService.responseFacets[0].buckets.items[0]); const serverResponseFields: any = [ - { type: 'field', label: 'f1', field: 'f1', buckets: [ - { label: 'b1', metrics: [{value: {count: 6}}], filterQuery: 'filter' }, - { label: 'b2', metrics: [{value: {count: 1}}], filterQuery: 'filter2' }] }, + { + type: 'field', + label: 'f1', + field: 'f1', + buckets: [ + { label: 'b1', metrics: [{ value: { count: 6 } }], filterQuery: 'filter' }, + { label: 'b2', metrics: [{ value: { count: 1 } }], filterQuery: 'filter2' } + ] + }, { type: 'field', label: 'f2', field: 'f2', buckets: [] } ]; const data = { @@ -123,27 +140,41 @@ describe('SearchFilterComponent', () => { spyOn(queryBuilder, 'execute').and.stub(); queryBuilder.config = { categories: [], - facetFields: { fields: [ + facetFields: { + fields: [ { label: 'f1', field: 'f1' }, { label: 'f2', field: 'f2' } - ]}, + ] + }, facetQueries: { queries: [] } }; searchFacetFiltersService.responseFacets = [ - { type: 'field', label: 'f1', field: 'f1', buckets: new SearchFilterList([ - { label: 'b1', count: 10, filterQuery: 'filter', checked: true }, - { label: 'b2', count: 1, filterQuery: 'filter2' }]) }, + { + type: 'field', + label: 'f1', + field: 'f1', + buckets: new SearchFilterList([ + { label: 'b1', count: 10, filterQuery: 'filter', checked: true }, + { label: 'b2', count: 1, filterQuery: 'filter2' } + ]) + }, { type: 'field', label: 'f2', field: 'f2', buckets: new SearchFilterList([]) } ]; searchFacetFiltersService.queryBuilder.addUserFacetBucket('f1', searchFacetFiltersService.responseFacets[0].buckets.items[0]); const serverResponseFields: any = [ - { type: 'field', label: 'f1', field: 'f1', buckets: [ - { label: 'b1', metrics: [{value: {count: 6}}], filterQuery: 'filter' }, - { label: 'b2', metrics: [{value: {count: 1}}], filterQuery: 'filter2' }] }, + { + type: 'field', + label: 'f1', + field: 'f1', + buckets: [ + { label: 'b1', metrics: [{ value: { count: 6 } }], filterQuery: 'filter' }, + { label: 'b2', metrics: [{ value: { count: 1 } }], filterQuery: 'filter2' } + ] + }, { type: 'field', label: 'f2', field: 'f2', buckets: [] } ]; const data = { @@ -167,19 +198,27 @@ describe('SearchFilterComponent', () => { spyOn(queryBuilder, 'execute').and.stub(); queryBuilder.config = { categories: [], - facetFields: { fields: [ + facetFields: { + fields: [ { label: 'f1', field: 'f1' }, { label: 'f2', field: 'f2' } - ]}, + ] + }, facetQueries: { queries: [] } }; searchFacetFiltersService.responseFacets = [ - { type: 'field', label: 'f1', field: 'f1', buckets: new SearchFilterList([ - { label: 'b1', count: 10, filterQuery: 'filter', checked: true }, - { label: 'b2', count: 1, filterQuery: 'filter2' }]) }, + { + type: 'field', + label: 'f1', + field: 'f1', + buckets: new SearchFilterList([ + { label: 'b1', count: 10, filterQuery: 'filter', checked: true }, + { label: 'b2', count: 1, filterQuery: 'filter2' } + ]) + }, { type: 'field', label: 'f2', field: 'f2', buckets: new SearchFilterList() } ]; searchFacetFiltersService.queryBuilder.addUserFacetBucket('f1', searchFacetFiltersService.responseFacets[0].buckets.items[0]); @@ -205,9 +244,10 @@ describe('SearchFilterComponent', () => { const queryResponse = { label: 'query response', buckets: new SearchFilterList([ - { label: 'q1', query: 'q1', checked: true, metrics: [{value: {count: 1}}] }, - { label: 'q2', query: 'q2', checked: false, metrics: [{value: {count: 1}}] }, - { label: 'q3', query: 'q3', checked: true, metrics: [{value: {count: 1}}] }]) + { label: 'q1', query: 'q1', checked: true, metrics: [{ value: { count: 1 } }] }, + { label: 'q2', query: 'q2', checked: false, metrics: [{ value: { count: 1 } }] }, + { label: 'q3', query: 'q3', checked: true, metrics: [{ value: { count: 1 } }] } + ]) } as any; searchFacetFiltersService.responseFacets = [queryResponse]; @@ -222,10 +262,9 @@ describe('SearchFilterComponent', () => { expect(entry.checked).toEqual(false); } }); - }); + }); describe('widgets', () => { - it('should have expandable categories', async () => { fixture.detectChanges(); await fixture.whenStable(); @@ -235,24 +274,8 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); + const panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(1); - - const element: HTMLElement = panels[0].nativeElement; - - (element.childNodes[0] as HTMLElement).click(); - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(element.classList.contains('mat-expanded')).toBeTruthy(); - - (element.childNodes[0] as HTMLElement).click(); - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(element.classList.contains('mat-expanded')).toEqual(false); }); it('should not show the disabled widget', async () => { @@ -262,7 +285,7 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); + const panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(0); }); @@ -273,21 +296,11 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); + const panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(1); - const title = fixture.debugElement.query(By.css('.mat-expansion-panel-header-title')); - expect(title.nativeElement.innerText.trim()).toBe('Type'); - - const element: HTMLElement = panels[0].nativeElement; - expect(element.classList.contains('mat-expanded')).toBeTruthy(); - - (element.childNodes[0] as HTMLElement).click(); - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(element.classList.contains('mat-expanded')).toEqual(false); + expect(await panels[0].getTitle()).toBe('Type'); + expect(await panels[0].isExpanded()).toBe(true); }); it('should show the widgets only if configured', async () => { @@ -297,11 +310,11 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); + const panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(2); - const titleElements = fixture.debugElement.queryAll(By.css('.mat-expansion-panel-header-title')); - expect(titleElements.map(title => title.nativeElement.innerText.trim())).toEqual(['Name', 'Type']); + expect(await panels[0].getTitle()).toBe('Name'); + expect(await panels[1].getTitle()).toBe('Type'); }); it('should be update the search query when name changed', async () => { @@ -311,17 +324,19 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - let panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); + + let panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(6); const inputElement = fixture.debugElement.query(By.css('[data-automation-id="expansion-panel-Name"] input')); inputElement.triggerEventHandler('change', { target: { value: '*' } }); + expect(queryBuilder.update).toHaveBeenCalled(); queryBuilder.executed.next(mockSearchResult); fixture.detectChanges(); - panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); + panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(8); }); @@ -332,19 +347,20 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const inputElement = fixture.debugElement.query(By.css('[data-automation-id="expansion-panel-Name"] input')); - inputElement.triggerEventHandler('change', { target: { value: '*' } }); + const input = await loader.getHarness(MatInputHarness); + await input.setValue('*'); queryBuilder.executed.next(getMockSearchResultWithResponseBucket()); fixture.detectChanges(); - const panels = fixture.debugElement.queryAll(By.css('.mat-expansion-panel')); - + const panels = await loader.getAllHarnesses(MatExpansionPanelHarness); expect(panels.length).toBe(9); }); - it('should show the long facet options list with pagination', () => { - const panel = '[data-automation-id="expansion-panel-Size facet queries"]'; + it('should show the long facet options list with pagination', async () => { + const showMoreButton = MatButtonHarness.with({ selector: `[title="SEARCH.FILTER.ACTIONS.SHOW-MORE"]` }); + const showLessButton = MatButtonHarness.with({ selector: `[title="SEARCH.FILTER.ACTIONS.SHOW-LESS"]` }); + appConfigService.config.search = searchFilter; queryBuilder.resetToDefaults(); @@ -352,58 +368,51 @@ describe('SearchFilterComponent', () => { queryBuilder.executed.next(mockSearchResult); fixture.detectChanges(); - let sizes = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(sizes).toEqual(stepOne); + const panel = await loader.getHarness( + MatExpansionPanelHarness.with({ + selector: `[data-automation-id="expansion-panel-Size facet queries"]` + }) + ); - let moreButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-MORE"]`)); - let lessButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-LESS"]`)); + let sizes = await panel.getAllHarnesses(MatCheckboxHarness); + let sizeLabels = await Promise.all(sizes.map((element) => element.getLabelText())); + expect(sizeLabels).toEqual(stepOne); - expect(lessButton).toEqual(null); - expect(moreButton).toBeDefined(); + let moreButton = await loader.getHarness(showMoreButton); + expect(await loader.hasHarness(showLessButton)).toBe(false); - moreButton.triggerEventHandler('click', {}); - fixture.detectChanges(); + await moreButton.click(); - sizes = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(sizes).toEqual(stepTwo); + sizes = await panel.getAllHarnesses(MatCheckboxHarness); + sizeLabels = await Promise.all(sizes.map((element) => element.getLabelText())); + expect(sizeLabels).toEqual(stepTwo); - moreButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-MORE"]`)); - lessButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-LESS"]`)); - expect(lessButton).toBeDefined(); - expect(moreButton).toBeDefined(); + moreButton = await loader.getHarness(showMoreButton); + expect(await loader.hasHarness(showLessButton)).toBe(true); + await moreButton.click(); - moreButton.triggerEventHandler('click', {}); - fixture.detectChanges(); - sizes = getAllMenus(`${panel} mat-checkbox`, fixture); + sizes = await panel.getAllHarnesses(MatCheckboxHarness); + sizeLabels = await Promise.all(sizes.map((element) => element.getLabelText())); + expect(sizeLabels).toEqual(stepThree); - expect(sizes).toEqual(stepThree); + expect(await loader.hasHarness(showMoreButton)).toBe(false); + let lessButton = await loader.getHarness(showLessButton); + await lessButton.click(); - moreButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-MORE"]`)); - lessButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-LESS"]`)); - expect(lessButton).toBeDefined(); - expect(moreButton).toEqual(null); + sizes = await panel.getAllHarnesses(MatCheckboxHarness); + sizeLabels = await Promise.all(sizes.map((element) => element.getLabelText())); + expect(sizeLabels).toEqual(stepTwo); - lessButton.triggerEventHandler('click', {}); - fixture.detectChanges(); + expect(await loader.hasHarness(showMoreButton)).toBe(true); + lessButton = await loader.getHarness(showLessButton); + await lessButton.click(); - sizes = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(sizes).toEqual(stepTwo); + sizes = await panel.getAllHarnesses(MatCheckboxHarness); + sizeLabels = await Promise.all(sizes.map((element) => element.getLabelText())); + expect(sizeLabels).toEqual(stepOne); - moreButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-MORE"]`)); - lessButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-LESS"]`)); - expect(lessButton).toBeDefined(); - expect(moreButton).toBeDefined(); - - lessButton.triggerEventHandler('click', {}); - fixture.detectChanges(); - - sizes = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(sizes).toEqual(stepOne); - - moreButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-MORE"]`)); - lessButton = fixture.debugElement.query(By.css(`${panel} button[title="SEARCH.FILTER.ACTIONS.SHOW-LESS"]`)); - expect(lessButton).toEqual(null); - expect(moreButton).toBeDefined(); + expect(await loader.hasHarness(showMoreButton)).toBe(true); + expect(await loader.hasHarness(showLessButton)).toBe(false); }); it('should not show facets if filter is not available', () => { @@ -422,8 +431,8 @@ describe('SearchFilterComponent', () => { expect(facetElement).toEqual(null); }); - it('should search the facets options and select it', () => { - const panel = '[data-automation-id="expansion-panel-Size facet queries"]'; + it('should search the facets options and select it', async () => { + const panelSelector = '[data-automation-id="expansion-panel-Size facet queries"]'; appConfigService.config.search = searchFilter; queryBuilder.resetToDefaults(); fixture.detectChanges(); @@ -432,41 +441,39 @@ describe('SearchFilterComponent', () => { spyOn(queryBuilder, 'update').and.stub(); - const inputElement = fixture.debugElement.query(By.css(`${panel} input`)); - inputElement.nativeElement.value = 'Extra'; - inputElement.nativeElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); + const panel = await loader.getHarness( + MatExpansionPanelHarness.with({ + selector: panelSelector + }) + ); - let filteredMenu = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(filteredMenu).toEqual(['Extra Small (10239)']); + const input = await panel.getHarness(MatInputHarness); + await input.setValue('Extra'); - inputElement.nativeElement.value = 'my'; - inputElement.nativeElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); + let checkboxes = await panel.getAllHarnesses(MatCheckboxHarness); + expect(checkboxes.length).toBe(1); + expect(await checkboxes[0].getLabelText()).toBe('Extra Small (10239)'); - filteredMenu = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(filteredMenu).toEqual(filteredResult); + await input.setValue('my'); - const clearButton = fixture.debugElement.query(By.css(`${panel} mat-form-field button`)); - clearButton.triggerEventHandler('click', {}); - fixture.detectChanges(); + checkboxes = await panel.getAllHarnesses(MatCheckboxHarness); + let labels = await Promise.all(checkboxes.map((element) => element.getLabelText())); + expect(labels).toEqual(filteredResult); - filteredMenu = getAllMenus(`${panel} mat-checkbox`, fixture); - expect(filteredMenu).toEqual(stepOne); + const clearButton = await panel.getHarness(MatButtonHarness.with({ selector: '[title="SEARCH.FILTER.BUTTONS.CLEAR"]' })); + await clearButton.click(); - const firstOption = fixture.debugElement.query(By.css(`${panel} mat-checkbox`)); - firstOption.triggerEventHandler('change', { checked: true }); - fixture.detectChanges(); - - const checkedOption = fixture.debugElement.query(By.css(`${panel} mat-checkbox.mat-checkbox-checked`)); - expect(checkedOption.nativeElement.innerText).toEqual('Extra Small (10239)'); + checkboxes = await panel.getAllHarnesses(MatCheckboxHarness); + labels = await Promise.all(checkboxes.map((element) => element.getLabelText())); + expect(labels).toEqual(stepOne); + await checkboxes[0].check(); expect(queryBuilder.update).toHaveBeenCalledTimes(1); }); - it('should preserve the filter state if other fields edited', () => { - const panel1 = '[data-automation-id="expansion-panel-Size facet queries"]'; - const panel2 = '[data-automation-id="expansion-panel-Type facet queries"]'; + it('should preserve the filter state if other fields edited', async () => { + const panel1Selector = '[data-automation-id="expansion-panel-Size facet queries"]'; + const panel2selector = '[data-automation-id="expansion-panel-Type facet queries"]'; appConfigService.config.search = searchFilter; queryBuilder.resetToDefaults(); fixture.detectChanges(); @@ -474,39 +481,39 @@ describe('SearchFilterComponent', () => { fixture.detectChanges(); spyOn(queryBuilder, 'update').and.stub(); - const inputElement = fixture.debugElement.query(By.css(`${panel1} input`)); + const inputElement = fixture.debugElement.query(By.css(`${panel1Selector} input`)); inputElement.nativeElement.value = 'my'; inputElement.nativeElement.dispatchEvent(new Event('input')); fixture.detectChanges(); - let filteredMenu = getAllMenus(`${panel1} mat-checkbox`, fixture); - expect(filteredMenu).toEqual(filteredResult); + const panel1 = await loader.getHarness(MatExpansionPanelHarness.with({ selector: panel1Selector })); - const firstOption = fixture.debugElement.query(By.css(`${panel1} mat-checkbox`)); - firstOption.triggerEventHandler('change', { checked: true }); - fixture.detectChanges(); + let checkboxes = await panel1.getAllHarnesses(MatCheckboxHarness); + let labels = await Promise.all(checkboxes.map((element) => element.getLabelText())); + expect(labels).toEqual(filteredResult); - let panel1CheckedOption = fixture.debugElement.query(By.css(`${panel1} mat-checkbox.mat-checkbox-checked`)); - expect(panel1CheckedOption.nativeElement.innerText).toEqual('my1 (806)'); + await checkboxes[0].check(); + expect(await checkboxes[0].isChecked()).toBe(true); + expect(await checkboxes[0].getLabelText()).toBe('my1 (806)'); - const panel2Options = fixture.debugElement.query(By.css(`${panel2} mat-checkbox`)); - panel2Options.triggerEventHandler('change', { checked: true }); - fixture.detectChanges(); + const panel2 = await loader.getHarness(MatExpansionPanelHarness.with({ selector: panel2selector })); + checkboxes = await panel2.getAllHarnesses(MatCheckboxHarness); + await checkboxes[0].check(); + expect(await checkboxes[0].isChecked()).toBe(true); + expect(await checkboxes[0].getLabelText()).toBe('SEARCH.FACET_QUERIES.MIMETYPE (13)'); - const panel2CheckedOption = fixture.debugElement.query(By.css(`${panel2} mat-checkbox.mat-checkbox-checked`)); - expect(panel2CheckedOption.nativeElement.innerText).toEqual('SEARCH.FACET_QUERIES.MIMETYPE (13)'); + checkboxes = await panel1.getAllHarnesses(MatCheckboxHarness); + labels = await Promise.all(checkboxes.map((element) => element.getLabelText())); + expect(labels).toEqual(filteredResult); - filteredMenu = getAllMenus(`${panel1} mat-checkbox`, fixture); - expect(filteredMenu).toEqual(filteredResult); - - panel1CheckedOption = fixture.debugElement.query(By.css(`${panel1} mat-checkbox.mat-checkbox-checked`)); - expect(panel1CheckedOption.nativeElement.innerText).toEqual('my1 (806)'); + const checkedOption = await panel1.getHarness(MatCheckboxHarness.with({ checked: true })); + expect(await checkedOption.getLabelText()).toBe('my1 (806)'); expect(queryBuilder.update).toHaveBeenCalledTimes(2); }); it('should reset the query fragments when reset All is clicked', () => { - component.queryBuilder.queryFragments = { fragment1 : 'value1'}; + component.queryBuilder.queryFragments = { fragment1: 'value1' }; appConfigService.config.search = searchFilter; searchFacetFiltersService.responseFacets = []; component.displayResetButton = true; @@ -519,11 +526,10 @@ describe('SearchFilterComponent', () => { expect(component.queryBuilder.queryFragments).toEqual({}); expect(queryBuilder.resetToDefaults).toHaveBeenCalled(); }); - }); }); export const getAllMenus = (regex, fixture: ComponentFixture): string[] => { const elements = fixture.debugElement.queryAll(By.css(regex)); - return Array.from(elements).map(element => element.nativeElement.innerText); + return Array.from(elements).map((element) => element.nativeElement.innerText); }; diff --git a/lib/content-services/src/lib/search/components/search-form/search-form.component.spec.ts b/lib/content-services/src/lib/search/components/search-form/search-form.component.spec.ts index 319c84aaa3..8182b49033 100644 --- a/lib/content-services/src/lib/search/components/search-form/search-form.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-form/search-form.component.spec.ts @@ -23,8 +23,13 @@ import { SEARCH_QUERY_SERVICE_TOKEN } from '../../search-query-service.token'; import { SearchQueryBuilderService } from '../../services/search-query-builder.service'; import { SearchForm } from '../../models/search-form.interface'; import { By } from '@angular/platform-browser'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatMenuHarness } from '@angular/material/menu/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; describe('SearchFormComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: SearchFormComponent; let queryBuilder: SearchQueryBuilderService; @@ -36,62 +41,62 @@ describe('SearchFormComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ], - providers: [ - { provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchQueryBuilderService } - ] + imports: [TranslateModule.forRoot(), ContentTestingModule], + providers: [{ provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchQueryBuilderService }] }); fixture = TestBed.createComponent(SearchFormComponent); component = fixture.componentInstance; queryBuilder = TestBed.inject(SEARCH_QUERY_SERVICE_TOKEN); queryBuilder.searchForms.next(mockSearchForms); fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); + const getTitle = () => fixture.debugElement.query(By.css('.adf-search-form-title'))?.nativeElement as HTMLSpanElement; + it('should show search forms', () => { - const title = fixture.debugElement.query(By.css('.adf-search-form-title')); - expect(title.nativeElement.innerText).toContain(mockSearchForms[1].name); + const title = getTitle(); + expect(title.innerText).toContain(mockSearchForms[1].name); }); - it('should emit on form change', (done) => { + it('should emit on form change', async () => { spyOn(queryBuilder, 'updateSelectedConfiguration').and.stub(); - component.formChange.subscribe((form) => { - expect(form).toEqual(mockSearchForms[2]); - expect(queryBuilder.updateSelectedConfiguration).toHaveBeenCalled(); - done(); - }); - const button = fixture.debugElement.query(By.css('.adf-search-form')).nativeElement; - button.click(); - fixture.detectChanges(); + let changedForm: SearchForm; + component.formChange.subscribe((form) => (changedForm = form)); - const matOption = fixture.debugElement.queryAll(By.css('.mat-menu-item'))[2].nativeElement; - matOption.click(); + const menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + + const menuItems = await menu.getItems(); + expect(menuItems.length).toEqual(3); + await menuItems[2].click(); + + expect(changedForm).toEqual(mockSearchForms[2]); + expect(queryBuilder.updateSelectedConfiguration).toHaveBeenCalled(); }); - it('should not show menu if only one config found', () => { + it('should not show menu if only one config found', async () => { queryBuilder.searchForms.next([{ name: 'one', selected: true, default: true, index: 0 }]); fixture.detectChanges(); - const button = fixture.debugElement.query(By.css('.adf-search-form')).nativeElement; - button.click(); + const button = await loader.getHarness(MatButtonHarness.with({ selector: '.adf-search-form' })); + await button.click(); - const title = fixture.debugElement.query(By.css('.adf-search-form-title')); - expect(title.nativeElement.innerText).toContain('one'); + const title = getTitle(); + expect(title.innerText).toContain('one'); fixture.detectChanges(); - const matOption = fixture.debugElement.query(By.css('.mat-menu-item')); - expect(matOption).toBe(null, 'should not show mat menu'); + + const hasMenu = await loader.hasHarness(MatMenuHarness); + expect(hasMenu).toBe(false); }); it('should not display search form if no form configured', () => { queryBuilder.searchForms.next([]); fixture.detectChanges(); - const field = fixture.debugElement.query(By.css('.adf-search-form-title')); - expect(field).toEqual(null, 'search form displayed for empty configuration'); + const field = getTitle(); + expect(field).toBeUndefined(); }); }); diff --git a/lib/content-services/src/lib/search/components/search-logical-filter/search-logical-filter.component.html b/lib/content-services/src/lib/search/components/search-logical-filter/search-logical-filter.component.html index 07d32d2ea1..4ba39e54bc 100644 --- a/lib/content-services/src/lib/search/components/search-logical-filter/search-logical-filter.component.html +++ b/lib/content-services/src/lib/search/components/search-logical-filter/search-logical-filter.component.html @@ -1,6 +1,6 @@
- {{('SEARCH.LOGICAL_SEARCH.' + field + '_LABEL') | translate}} + {{('SEARCH.LOGICAL_SEARCH.' + field + '_LABEL') | translate}} { beforeEach(() => { TestBed.configureTestingModule({ declarations: [SearchLogicalFilterComponent], - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); fixture = TestBed.createComponent(SearchLogicalFilterComponent); @@ -62,7 +59,7 @@ describe('SearchLogicalFilterComponent', () => { * @returns list of labels */ function getInputsLabels(): string[] { - return fixture.debugElement.queryAll(By.css('.adf-search-input mat-label')).map((label) => label.nativeElement.innerText); + return fixture.debugElement.queryAll(By.css(`[data-automation-id="adf-search-input-label"]`)).map((label) => label.nativeElement.innerText); } /** @@ -164,7 +161,9 @@ describe('SearchLogicalFilterComponent', () => { enterNewPhrase('test5 test6 ', 2); component.submitValues(); expect(component.context.update).toHaveBeenCalled(); - expect(component.context.queryFragments[component.id]).toBe('((NOT field1:"test5" AND NOT field1:"test6") AND (NOT field2:"test5" AND NOT field2:"test6"))'); + expect(component.context.queryFragments[component.id]).toBe( + '((NOT field1:"test5" AND NOT field1:"test6") AND (NOT field2:"test5" AND NOT field2:"test6"))' + ); }); it('should form correct query from match exact field and trim it', () => { diff --git a/lib/content-services/src/lib/search/components/search-panel/search-panel.component.spec.ts b/lib/content-services/src/lib/search/components/search-panel/search-panel.component.spec.ts index 7242373914..69b40cd8d6 100644 --- a/lib/content-services/src/lib/search/components/search-panel/search-panel.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-panel/search-panel.component.spec.ts @@ -20,22 +20,26 @@ import { SearchFilterList } from '../../models/search-filter-list.model'; import { ContentTestingModule } from '../../../testing/content.testing.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { sizeOptions, stepOne, stepThree } from '../../../mock'; -import { By } from '@angular/platform-browser'; import { TranslateModule } from '@ngx-translate/core'; +import { HarnessLoader, TestKey } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; +import { By } from '@angular/platform-browser'; describe('SearchCheckListComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: SearchCheckListComponent; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); fixture = TestBed.createComponent(SearchCheckListComponent); component = fixture.componentInstance; + + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); it('should setup options from settings', () => { @@ -49,7 +53,7 @@ describe('SearchCheckListComponent', () => { expect(component.options.items).toEqual(options); }); - it('should handle enter key as click on checkboxes', () => { + it('should handle enter key as click on checkboxes', async () => { component.options = new SearchFilterList([ { name: 'Folder', value: `TYPE:'cm:folder'`, checked: false }, { name: 'Document', value: `TYPE:'cm:content'`, checked: false } @@ -58,13 +62,12 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox')); + const options = await loader.getAllHarnesses(MatCheckboxHarness); + await (await options[0].host()).sendKeys(TestKey.ENTER); + expect(await options[0].isChecked()).toBe(true); - optionElements[0].triggerEventHandler('keydown.enter', {}); - expect(component.options.items[0].checked).toBeTruthy(); - - optionElements[0].triggerEventHandler('keydown.enter', {}); - expect(component.options.items[0].checked).toBeFalsy(); + await (await options[0].host()).sendKeys(TestKey.ENTER); + expect(await options[0].isChecked()).toBe(false); }); it('should setup operator from the settings', () => { @@ -95,21 +98,13 @@ describe('SearchCheckListComponent', () => { spyOn(component.context, 'update').and.stub(); - component.changeHandler( - { checked: true } as any, - component.options.items[0] - ); + component.changeHandler({ checked: true } as any, component.options.items[0]); expect(component.context.queryFragments[component.id]).toEqual(`TYPE:'cm:folder'`); - component.changeHandler( - { checked: true } as any, - component.options.items[1] - ); + component.changeHandler({ checked: true } as any, component.options.items[1]); - expect(component.context.queryFragments[component.id]).toEqual( - `TYPE:'cm:folder' OR TYPE:'cm:content'` - ); + expect(component.context.queryFragments[component.id]).toEqual(`TYPE:'cm:folder' OR TYPE:'cm:content'`); }); it('should reset selected boxes', () => { @@ -147,7 +142,7 @@ describe('SearchCheckListComponent', () => { }); describe('Pagination', () => { - it('should show 5 items when pageSize not defined', () => { + it('should show 5 items when pageSize not defined', async () => { component.id = 'checklist'; component.context = { queryFragments: { @@ -160,13 +155,14 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox')); - expect(optionElements.length).toEqual(5); - const labels = Array.from(optionElements).map(element => element.nativeElement.innerText); + const options = await loader.getAllHarnesses(MatCheckboxHarness); + expect(options.length).toEqual(5); + + const labels = await Promise.all(Array.from(options).map(async (element) => element.getLabelText())); expect(labels).toEqual(stepOne); }); - it('should show all items when pageSize is high', () => { + it('should show all items when pageSize is high', async () => { component.id = 'checklist'; component.context = { queryFragments: { @@ -178,14 +174,15 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox')); - expect(optionElements.length).toEqual(13); - const labels = Array.from(optionElements).map(element => element.nativeElement.innerText); + const options = await loader.getAllHarnesses(MatCheckboxHarness); + expect(options.length).toEqual(13); + + const labels = await Promise.all(Array.from(options).map(async (element) => element.getLabelText())); expect(labels).toEqual(stepThree); }); }); - it('should able to check/reset the checkbox', () => { + it('should able to check/reset the checkbox', async () => { component.id = 'checklist'; component.context = { queryFragments: { @@ -198,16 +195,15 @@ describe('SearchCheckListComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.query(By.css('mat-checkbox')); - optionElements.triggerEventHandler('change', { checked: true }); + const checkbox = await loader.getHarness(MatCheckboxHarness); + await checkbox.check(); expect(component.submitValues).toHaveBeenCalled(); const clearAllElement = fixture.debugElement.query(By.css('button[title="SEARCH.FILTER.ACTIONS.CLEAR-ALL"]')); - clearAllElement.triggerEventHandler('click', {} ); + clearAllElement.triggerEventHandler('click', {}); fixture.detectChanges(); - const selectedElements = fixture.debugElement.queryAll(By.css('.mat-checkbox-checked')); - expect(selectedElements.length).toBe(0); + expect(await checkbox.isChecked()).toBe(false); }); }); diff --git a/lib/content-services/src/lib/search/components/search-radio/search-radio.component.spec.ts b/lib/content-services/src/lib/search/components/search-radio/search-radio.component.spec.ts index 221ee0b037..415217637f 100644 --- a/lib/content-services/src/lib/search/components/search-radio/search-radio.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-radio/search-radio.component.spec.ts @@ -16,29 +16,31 @@ */ import { sizeOptions, stepOne, stepThree } from '../../../mock'; -import { By } from '@angular/platform-browser'; import { SearchRadioComponent } from './search-radio.component'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ContentTestingModule } from '../../../testing/content.testing.module'; import { TranslateModule } from '@ngx-translate/core'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatRadioButtonHarness, MatRadioGroupHarness } from '@angular/material/radio/testing'; describe('SearchRadioComponent', () => { - let fixture: ComponentFixture; - let component: SearchRadioComponent; + let loader: HarnessLoader; + let fixture: ComponentFixture; + let component: SearchRadioComponent; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] - }); - fixture = TestBed.createComponent(SearchRadioComponent); - component = fixture.componentInstance; - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), ContentTestingModule] + }); + fixture = TestBed.createComponent(SearchRadioComponent); + component = fixture.componentInstance; - describe('Pagination', () => { - it('should show 5 items when pageSize not defined', () => { + loader = TestbedHarnessEnvironment.loader(fixture); + }); + + describe('Pagination', () => { + it('should show 5 items when pageSize not defined', async () => { component.id = 'radio'; component.context = { queryFragments: { @@ -51,13 +53,14 @@ describe('SearchRadioComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-radio-button')); - expect(optionElements.length).toEqual(5); - const labels = Array.from(optionElements).map(element => element.nativeElement.innerText); + const options = await loader.getAllHarnesses(MatRadioButtonHarness); + expect(options.length).toEqual(5); + + const labels = await Promise.all(Array.from(options).map(async (element) => element.getLabelText())); expect(labels).toEqual(stepOne); }); - it('should show all items when pageSize is high', () => { + it('should show all items when pageSize is high', async () => { component.id = 'radio'; component.context = { queryFragments: { @@ -69,14 +72,15 @@ describe('SearchRadioComponent', () => { component.ngOnInit(); fixture.detectChanges(); - const optionElements = fixture.debugElement.queryAll(By.css('mat-radio-button')); - expect(optionElements.length).toEqual(13); - const labels = Array.from(optionElements).map(element => element.nativeElement.innerText); + const options = await loader.getAllHarnesses(MatRadioButtonHarness); + expect(options.length).toEqual(13); + + const labels = await Promise.all(Array.from(options).map(async (element) => element.getLabelText())); expect(labels).toEqual(stepThree); }); }); - it('should able to check the radio button', async () => { + it('should able to check the radio button', async () => { component.id = 'radio'; component.context = { queryFragments: { @@ -85,15 +89,10 @@ describe('SearchRadioComponent', () => { update: () => {} } as any; component.settings = { options: sizeOptions } as any; - spyOn(component.context, 'update').and.stub(); - fixture.detectChanges(); - await fixture.whenStable(); - const optionElements = fixture.debugElement.query(By.css('mat-radio-group')); - optionElements.triggerEventHandler('change', { value: sizeOptions[0].value }); - fixture.detectChanges(); + const group = await loader.getHarness(MatRadioGroupHarness); + await group.checkRadioButton({ selector: `[data-automation-id="search-radio-${sizeOptions[0].name}"]` }); - expect(component.context.update).toHaveBeenCalled(); expect(component.context.queryFragments[component.id]).toBe(sizeOptions[0].value); }); }); diff --git a/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts b/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts index b33b0ef7df..2ba2a5f116 100644 --- a/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts @@ -19,17 +19,19 @@ import { SearchTextComponent } from './search-text.component'; import { ContentTestingModule } from '../../../testing/content.testing.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatInputHarness } from '@angular/material/input/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; describe('SearchTextComponent', () => { + let loader: HarnessLoader; let fixture: ComponentFixture; let component: SearchTextComponent; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); fixture = TestBed.createComponent(SearchTextComponent); component = fixture.componentInstance; @@ -44,6 +46,8 @@ describe('SearchTextComponent', () => { queryFragments: {}, update: () => {} } as any; + + loader = TestbedHarnessEnvironment.loader(fixture); }); it('should parse value from the context at startup', () => { @@ -100,16 +104,19 @@ describe('SearchTextComponent', () => { fixture.detectChanges(); await fixture.whenStable(); expect(component.value).toEqual('secret.pdf'); - const input = fixture.debugElement.nativeElement.querySelector('.mat-form-field-infix input'); - expect(input.value).toEqual('secret.pdf'); + + const input = await loader.getHarness(MatInputHarness); + expect(await input.getValue()).toBe('secret.pdf'); }); - it('should be able to reset by clicking clear button', async () => { + it('should be able to reset by clicking clear button', async () => { component.context.queryFragments[component.id] = `cm:name:'secret.pdf'`; fixture.detectChanges(); await fixture.whenStable(); - const clearElement = fixture.debugElement.nativeElement.querySelector('button'); - clearElement.click(); + + const clearButton = await loader.getHarness(MatButtonHarness); + await clearButton.click(); + expect(component.value).toBe(''); expect(component.context.queryFragments[component.id]).toBe(''); }); diff --git a/lib/content-services/src/lib/site-dropdown/sites-dropdown.component.spec.ts b/lib/content-services/src/lib/site-dropdown/sites-dropdown.component.spec.ts index 02fa9ecbbd..2281db8bfa 100644 --- a/lib/content-services/src/lib/site-dropdown/sites-dropdown.component.spec.ts +++ b/lib/content-services/src/lib/site-dropdown/sites-dropdown.component.spec.ts @@ -15,13 +15,12 @@ * limitations under the License. */ -import { DebugElement } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { DropdownSitesComponent, Relations } from './sites-dropdown.component'; import { AuthenticationService } from '@alfresco/adf-core'; import { of } from 'rxjs'; -import { getFakeSitePaging, +import { + getFakeSitePaging, getFakeSitePagingNoMoreItems, getFakeSitePagingFirstPage, getFakeSitePagingLastPage, @@ -30,6 +29,10 @@ import { getFakeSitePaging, import { ContentTestingModule } from '../testing/content.testing.module'; import { TranslateModule } from '@ngx-translate/core'; import { SitesService } from '../common/services/sites.service'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { MatSelectHarness } from '@angular/material/select/testing'; +import { SiteEntry } from '@alfresco/js-api'; const customSiteList = { list: { @@ -51,70 +54,57 @@ const customSiteList = { }; describe('DropdownSitesComponent', () => { - + let loader: HarnessLoader; let component: any; let fixture: ComponentFixture; - let debug: DebugElement; let element: HTMLElement; let siteService: SitesService; let authService: AuthenticationService; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - ContentTestingModule - ] + imports: [TranslateModule.forRoot(), ContentTestingModule] }); }); describe('Rendering tests', () => { - describe('Infinite Loading', () => { - beforeEach(() => { siteService = TestBed.inject(SitesService); fixture = TestBed.createComponent(DropdownSitesComponent); - debug = fixture.debugElement; element = fixture.nativeElement; component = fixture.componentInstance; spyOn(siteService, 'getSites').and.returnValue(of(getFakeSitePaging())); + loader = TestbedHarnessEnvironment.loader(fixture); }); - it('Should show loading item if there are more itemes', async () => { + it('Should show loading item if there are more items', async () => { fixture.detectChanges(); await fixture.whenStable(); expect(element.querySelector('[data-automation-id="site-loading"]')).toBeDefined(); }); - it('Should not show loading item if there are more itemes', async () => { + it('Should not show loading item if there are more items', async () => { fixture.detectChanges(); await fixture.whenStable(); fixture.detectChanges(); expect(element.querySelector('[data-automation-id="site-loading"]')).toBeNull(); }); - }); describe('Sites', () => { - beforeEach(() => { siteService = TestBed.inject(SitesService); spyOn(siteService, 'getSites').and.returnValue(of(getFakeSitePagingNoMoreItems())); fixture = TestBed.createComponent(DropdownSitesComponent); - debug = fixture.debugElement; element = fixture.nativeElement; component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); }); - const openSelectBox = () => { - const selectBox = debug.query(By.css(('[data-automation-id="site-my-files-option"] .mat-select-trigger'))); - selectBox.triggerEventHandler('click', null); - }; - it('Dropdown sites should be rendered', async () => { fixture.detectChanges(); await fixture.whenStable(); @@ -131,13 +121,11 @@ describe('DropdownSitesComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); - fixture.detectChanges(); - await fixture.whenStable(); - - const options: any = debug.queryAll(By.css('mat-option')); - expect(options[0].nativeElement.innerText).toContain('DROPDOWN.MY_FILES_OPTION'); + const options = await select.getOptions(); + expect(await options[0].getText()).toContain('DROPDOWN.MY_FILES_OPTION'); }); it('should hide the "My files" option if the developer desires that way', async () => { @@ -146,23 +134,19 @@ describe('DropdownSitesComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); - fixture.detectChanges(); - await fixture.whenStable(); - - const options: any = debug.queryAll(By.css('mat-option')); - expect(options[0].nativeElement.innerText).not.toContain('DROPDOWN.MY_FILES_OPTION'); + const options = await select.getOptions(); + expect(await options[0].getText()).not.toContain('DROPDOWN.MY_FILES_OPTION'); }); it('should show the default placeholder label by default', async () => { fixture.detectChanges(); await fixture.whenStable(); - openSelectBox(); - - fixture.detectChanges(); - await fixture.whenStable(); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); expect(fixture.nativeElement.innerText.trim()).toContain('NODE_SELECTOR.LOCATION'); }); @@ -173,10 +157,8 @@ describe('DropdownSitesComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - openSelectBox(); - - fixture.detectChanges(); - await fixture.whenStable(); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); expect(fixture.nativeElement.innerText.trim()).toContain('NODE_SELECTOR.LOCATION'); }); @@ -187,51 +169,42 @@ describe('DropdownSitesComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - openSelectBox(); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); - fixture.detectChanges(); - await fixture.whenStable(); + const options = await select.getOptions(); - const options = debug.queryAll(By.css('mat-option')); - options[0].triggerEventHandler('click', null); - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(options[0].nativeElement.innerText).toContain('PERSONAL_FILES'); - expect(options[1].nativeElement.innerText).toContain('FILE_LIBRARIES'); + expect(await options[0].getText()).toContain('PERSONAL_FILES'); + expect(await options[1].getText()).toContain('FILE_LIBRARIES'); }); it('should load sites by default', async () => { fixture.detectChanges(); await fixture.whenStable(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); + const options = await select.getOptions(); + + expect(await options[1].getText()).toContain('fake-test-site'); + expect(await options[2].getText()).toContain('fake-test-2'); + }); + + it('should raise an event when a site is selected', async () => { fixture.detectChanges(); await fixture.whenStable(); - const options: any = debug.queryAll(By.css('mat-option')); - expect(options[1].nativeElement.innerText).toContain('fake-test-site'); - expect(options[2].nativeElement.innerText).toContain('fake-test-2'); - }); + let site: SiteEntry; + component.change.subscribe((value) => (site = value)); - it('should raise an event when a site is selected', (done) => { - fixture.detectChanges(); + const select = await loader.getHarness(MatSelectHarness); + await select.open(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); - fixture.detectChanges(); - const options: any = debug.queryAll(By.css('mat-option')); - options[1].nativeElement.click(); - fixture.detectChanges(); - }); + const options = await select.getOptions(); + await options[1].click(); - component.change.subscribe((site) => { - expect(site.entry.guid).toBe('fake-1'); - done(); - }); + expect(site.entry.guid).toBe('fake-1'); }); it('should be possible to select the default value', async () => { @@ -245,13 +218,13 @@ describe('DropdownSitesComponent', () => { }); describe('Default value', () => { - beforeEach(() => { siteService = TestBed.inject(SitesService); spyOn(siteService, 'getSites').and.returnValues(of(getFakeSitePagingFirstPage()), of(getFakeSitePagingLastPage())); fixture = TestBed.createComponent(DropdownSitesComponent); component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); }); it('should load new sites if default value is not in the first page', (done) => { @@ -277,15 +250,14 @@ describe('DropdownSitesComponent', () => { }); describe('Sites with members', () => { - beforeEach(() => { siteService = TestBed.inject(SitesService); spyOn(siteService, 'getSites').and.returnValue(of(getFakeSitePagingWithMembers())); fixture = TestBed.createComponent(DropdownSitesComponent); - debug = fixture.debugElement; element = fixture.nativeElement; component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); }); afterEach(() => { @@ -293,28 +265,23 @@ describe('DropdownSitesComponent', () => { }); describe('No relations', () => { - beforeEach(() => { component.relations = Relations.Members; authService = TestBed.inject(AuthenticationService); }); - it('should show only sites which logged user is member of when member relation is set', (done) => { + it('should show only sites which logged user is member of when member relation is set', async () => { spyOn(authService, 'getEcmUsername').and.returnValue('test'); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); - fixture.detectChanges(); - fixture.whenStable().then(() => { - const options: any = debug.queryAll(By.css('mat-option')); - expect(options[1].nativeElement.innerText).toContain('FAKE-SITE-PUBLIC'); - expect(options[2].nativeElement.innerText).toContain('FAKE-PRIVATE-SITE-MEMBER'); - expect(options[3]).toBeUndefined(); - done(); - }); - }); + await fixture.whenStable(); + + const select = await loader.getHarness(MatSelectHarness); + await select.open(); + + const options = await select.getOptions(); + + expect(await options[1].getText()).toContain('FAKE-SITE-PUBLIC'); + expect(await options[2].getText()).toContain('FAKE-PRIVATE-SITE-MEMBER'); }); }); @@ -324,22 +291,19 @@ describe('DropdownSitesComponent', () => { authService = TestBed.inject(AuthenticationService); }); - it('should show all the sites if no relation is set', (done) => { + it('should show all the sites if no relation is set', async () => { spyOn(authService, 'getEcmUsername').and.returnValue('test'); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); - fixture.detectChanges(); - fixture.whenStable().then(() => { - const options: any = debug.queryAll(By.css('mat-option')); - expect(options[1].nativeElement.innerText).toContain('FAKE-MODERATED-SITE'); - expect(options[2].nativeElement.innerText).toContain('FAKE-SITE-PUBLIC'); - expect(options[3].nativeElement.innerText).toContain('FAKE-PRIVATE-SITE-MEMBER'); - done(); - }); - }); + await fixture.whenStable(); + + const select = await loader.getHarness(MatSelectHarness); + await select.open(); + + const options = await select.getOptions(); + + expect(await options[1].getText()).toContain('FAKE-MODERATED-SITE'); + expect(await options[2].getText()).toContain('FAKE-SITE-PUBLIC'); + expect(await options[3].getText()).toContain('FAKE-PRIVATE-SITE-MEMBER'); }); }); }); diff --git a/lib/content-services/src/lib/upload/components/file-uploading-dialog.component.html b/lib/content-services/src/lib/upload/components/file-uploading-dialog.component.html index 8058577375..54dc152b49 100644 --- a/lib/content-services/src/lib/upload/components/file-uploading-dialog.component.html +++ b/lib/content-services/src/lib/upload/components/file-uploading-dialog.component.html @@ -8,6 +8,7 @@