diff --git a/e2e/playwright/info-drawer/exclude.tests.json b/e2e/playwright/info-drawer/exclude.tests.json index 190151e4f..a4d923e14 100644 --- a/e2e/playwright/info-drawer/exclude.tests.json +++ b/e2e/playwright/info-drawer/exclude.tests.json @@ -1,4 +1,5 @@ { "XAT-5523": "https://hyland.atlassian.net/browse/ACA-4697", - "XAT-5516": "https://hyland.atlassian.net/browse/ACS-9889" + "XAT-5516": "https://hyland.atlassian.net/browse/ACS-9889", + "XAT-5546": "https://hyland.atlassian.net/browse/ACS-10621" } diff --git a/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.spec.ts b/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.spec.ts index b6dfac27a..1da62717e 100644 --- a/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.spec.ts +++ b/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.spec.ts @@ -23,9 +23,11 @@ */ import { SearchInputControlComponent } from './search-input-control.component'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { AppTestingModule } from '../../../testing/app-testing.module'; import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute, NavigationStart, Router } from '@angular/router'; +import { of } from 'rxjs'; describe('SearchInputControlComponent', () => { let fixture: ComponentFixture; @@ -87,4 +89,43 @@ describe('SearchInputControlComponent', () => { fixture.detectChanges(); expect(component.isTermTooShort()).toBe(false); }); + + describe('ngOnInit', () => { + let route: ActivatedRoute; + let router: Router; + + beforeEach(() => { + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + spyOnProperty(router, 'events').and.returnValue(of(new NavigationStart(1, ''))); + }); + + it('should set * as value when url params has q parameter and input is empty', fakeAsync(() => { + spyOn(component.searchFieldFormControl, 'setValue'); + route.queryParams = of({ q: 'someQueryParams' }); + + component.ngOnInit(); + tick(); + expect(component.searchFieldFormControl.setValue).toHaveBeenCalledWith('*'); + })); + + it('should not set * as value when url params has missing q parameter and input is empty', fakeAsync(() => { + spyOn(component.searchFieldFormControl, 'setValue'); + route.queryParams = of({ otherQueryParam: 'someQueryParams' }); + + component.ngOnInit(); + tick(); + expect(component.searchFieldFormControl.setValue).not.toHaveBeenCalled(); + })); + + it('should not set * as value when url params has q parameter and input is not empty', fakeAsync(() => { + component.searchFieldFormControl.setValue('some value'); + spyOn(component.searchFieldFormControl, 'setValue'); + route.queryParams = of({ q: 'someQueryParams' }); + + component.ngOnInit(); + tick(); + expect(component.searchFieldFormControl.setValue).not.toHaveBeenCalled(); + })); + }); }); diff --git a/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.ts b/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.ts index d326d67c2..c085e3a0c 100644 --- a/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.ts +++ b/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.ts @@ -45,6 +45,9 @@ import { MatInputModule } from '@angular/material/input'; import { FormControl, FormsModule, ReactiveFormsModule, StatusChangeEvent, TouchedChangeEvent, Validators } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { noWhitespaceValidator } from '@alfresco/aca-shared'; +import { combineLatest } from 'rxjs'; +import { filter, startWith } from 'rxjs/operators'; +import { ActivatedRoute, NavigationStart, Router } from '@angular/router'; @Component({ imports: [CommonModule, TranslatePipe, MatButtonModule, MatIconModule, MatFormFieldModule, MatInputModule, FormsModule, ReactiveFormsModule], @@ -56,6 +59,8 @@ import { noWhitespaceValidator } from '@alfresco/aca-shared'; }) export class SearchInputControlComponent implements OnInit, OnChanges { private readonly destroyRef = inject(DestroyRef); + private readonly route = inject(ActivatedRoute); + private readonly router = inject(Router); /** Type of the input field to render, e.g. "search" or "text" (default). */ @Input() @@ -115,6 +120,19 @@ export class SearchInputControlComponent implements OnInit, OnChanges { } } }); + combineLatest([ + this.route.queryParams, + this.router.events.pipe( + filter((e): e is NavigationStart => e instanceof NavigationStart), + startWith(null) + ) + ]) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(([params]) => { + if (params['q'] && !this.searchFieldFormControl.value) { + setTimeout(() => this.searchFieldFormControl.setValue('*')); + } + }); } ngOnChanges(changes: SimpleChanges): void { diff --git a/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts b/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts index 127714504..e6a4d3dcc 100644 --- a/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts +++ b/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts @@ -271,12 +271,11 @@ describe('SearchComponent', () => { expect(queryBuilder.userQuery).toBe(`((cm:tag:"orange*"))`); }); - it('should get initial saved search when url matches', fakeAsync(() => { + it('should get initial saved search when url matches', () => { route.queryParams = of({ q: encodeQuery({ name: 'test' }) }); component.ngOnInit(); - tick(); expect(component.initialSavedSearch).toEqual({ name: 'test', encodedUrl: encodeQuery({ name: 'test' }), order: 0 }); - })); + }); it('should render a menu with 2 options when initial saved search is found', async () => { route.queryParams = of({ q: encodeQuery({ name: 'test' }) }); @@ -369,5 +368,17 @@ describe('SearchComponent', () => { expect(executeSpy).toHaveBeenCalledTimes(1); })); + it('should format userQuery when url parameters changed and userQuery is not contained by url', () => { + routerEvents.next(new NavigationStart(1, '')); + queryParams.next({ q: encodeQuery('') }); + expect(queryBuilder.userQuery).toBe('((cm:name:"*"))'); + }); + + it('should not format userQuery when url parameters changed when userQuery is already contained by url', () => { + routerEvents.next(new NavigationStart(1, '')); + queryParams.next({ q: encodeQuery({ userQuery: 'test' }) }); + expect(queryBuilder.userQuery).toBe('(test)'); + }); + testHeader(SearchResultsComponent, false); }); diff --git a/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts b/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts index 828ecbfcb..ab9edbd02 100644 --- a/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts +++ b/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts @@ -251,6 +251,9 @@ export class SearchResultsComponent extends PageComponent implements OnInit { .subscribe((navigationStartEvent) => { const shouldExecuteQuery = this.shouldExecuteQuery(navigationStartEvent, this.encodedQuery); this.queryBuilder.userQuery = extractUserQueryFromEncodedQuery(this.encodedQuery); + if (!this.searchedWord && !this.queryBuilder.userQuery && this.encodedQuery) { + this.queryBuilder.userQuery = formatSearchTerm('*', this.searchConfig['app:fields']); + } if (shouldExecuteQuery) { this.queryBuilder.execute(false); @@ -260,13 +263,18 @@ export class SearchResultsComponent extends PageComponent implements OnInit { } onSearchError(error: { message: any }) { - const { statusCode } = JSON.parse(error.message).error; + let message: string; + try { + const { statusCode } = JSON.parse(error.message).error; - const messageKey = `APP.BROWSE.SEARCH.ERRORS.${statusCode}`; - let message = this.translationService.instant(messageKey); + const messageKey = `APP.BROWSE.SEARCH.ERRORS.${statusCode}`; + message = this.translationService.instant(messageKey); - if (message === messageKey) { - message = this.translationService.instant(`APP.BROWSE.SEARCH.ERRORS.GENERIC`); + if (message === messageKey) { + message = this.translationService.instant(`APP.BROWSE.SEARCH.ERRORS.GENERIC`); + } + } catch { + message = error.message; } this.notificationService.showError(message); diff --git a/projects/aca-playwright-shared/src/base-config/playwright.config.ts b/projects/aca-playwright-shared/src/base-config/playwright.config.ts index cad77c372..fb47d09d6 100644 --- a/projects/aca-playwright-shared/src/base-config/playwright.config.ts +++ b/projects/aca-playwright-shared/src/base-config/playwright.config.ts @@ -65,7 +65,8 @@ export const getGlobalConfig: PlaywrightTestConfig = { screenshot: 'only-on-failure', launchOptions: { devtools: false, - args: ['--no-sandbox', '--disable-site-isolation-trials'] + args: ['--no-sandbox', '--disable-site-isolation-trials'], + slowMo: 300 } }, diff --git a/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-tags.component.ts b/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-tags.component.ts index 38db7c48f..d2bd1849e 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-tags.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-tags.component.ts @@ -24,7 +24,7 @@ import { SearchPage } from '../../../pages'; import { BaseComponent } from '../../base.component'; -import { Page } from '@playwright/test'; +import { Page, Locator } from '@playwright/test'; export class SearchFiltersTags extends BaseComponent { private static rootElement = '.adf-search-filter-menu-card'; @@ -35,10 +35,14 @@ export class SearchFiltersTags extends BaseComponent { public addOptionInput = this.getChild(`[data-automation-id$='adf-search-chip-autocomplete-input']`); + private searchOption(value: string): Locator { + return this.page.locator(`[data-automation-id="option-${value}"]`); + } + async filterByTag(page: SearchPage, tag: string): Promise { await page.searchFilters.tagsFilter.click(); await page.searchFiltersTags.addOptionInput.fill(tag); - await page.page.keyboard.press('Enter'); + await this.searchOption(tag).click(); await page.searchFilters.menuCardApply.click(); await page.dataTable.progressBarWaitForReload(); } diff --git a/projects/aca-playwright-shared/src/page-objects/components/search/search-overlay.components.ts b/projects/aca-playwright-shared/src/page-objects/components/search/search-overlay.components.ts index d424e330d..e56cc0d17 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/search/search-overlay.components.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/search/search-overlay.components.ts @@ -89,6 +89,7 @@ export class SearchOverlayComponent extends BaseComponent { } async searchFor(input: string): Promise { + await this.searchInput.clear(); await this.searchInput.fill(input); await this.searchButton.click({ force: true }); }