diff --git a/src/app/components/search/search-input/search-input.component.ts b/src/app/components/search/search-input/search-input.component.ts
index e2c4f4a70..53c07bf68 100644
--- a/src/app/components/search/search-input/search-input.component.ts
+++ b/src/app/components/search/search-input/search-input.component.ts
@@ -131,7 +131,9 @@ export class SearchInputComponent implements OnInit, OnDestroy {
if (urlSegmentGroup) {
const urlSegments: UrlSegment[] = urlSegmentGroup.segments;
- this.searchedWord = urlSegments[0].parameters['q'] || '';
+ this.searchedWord = urlSegments[0].parameters['q']
+ ? decodeURIComponent(urlSegments[0].parameters['q'])
+ : '';
}
}
diff --git a/src/app/components/search/search-results/search-results.component.spec.ts b/src/app/components/search/search-results/search-results.component.spec.ts
index 754005081..6481c785b 100644
--- a/src/app/components/search/search-results/search-results.component.spec.ts
+++ b/src/app/components/search/search-results/search-results.component.spec.ts
@@ -8,6 +8,7 @@ import { Store } from '@ngrx/store';
import { NavigateToFolder } from '../../../store/actions';
import { Pagination } from '@alfresco/js-api';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
+import { ActivatedRoute } from '@angular/router';
describe('SearchComponent', () => {
let component: SearchResultsComponent;
@@ -18,7 +19,25 @@ describe('SearchComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- imports: [CoreModule.forRoot(), AppTestingModule, AppSearchResultsModule]
+ imports: [CoreModule.forRoot(), AppTestingModule, AppSearchResultsModule],
+ providers: [
+ {
+ provide: ActivatedRoute,
+ useValue: {
+ snapshot: {
+ data: {
+ sortingPreferenceKey: ''
+ }
+ },
+ params: [
+ {
+ q:
+ 'TYPE: "cm:folder" AND %28=cm: name: email OR cm: name: budget%29'
+ }
+ ]
+ }
+ }
+ ]
});
config = TestBed.get(AppConfigService);
@@ -27,9 +46,18 @@ describe('SearchComponent', () => {
fixture = TestBed.createComponent(SearchResultsComponent);
component = fixture.componentInstance;
+
+ spyOn(queryBuilder, 'update').and.stub();
+
fixture.detectChanges();
}));
+ it('should decode encoded URI', () => {
+ expect(queryBuilder.userQuery).toEqual(
+ '(TYPE: "cm:folder" AND (=cm: name: email OR cm: name: budget))'
+ );
+ });
+
it('should return null if formatting invalid query', () => {
expect(component.formatSearchQuery(null)).toBeNull();
expect(component.formatSearchQuery('')).toBeNull();
@@ -169,8 +197,6 @@ describe('SearchComponent', () => {
skipCount: 0
});
- spyOn(queryBuilder, 'update').and.stub();
-
component.onPaginationChanged(page);
expect(queryBuilder.paging).toEqual({
diff --git a/src/app/components/search/search-results/search-results.component.ts b/src/app/components/search/search-results/search-results.component.ts
index 6b4d552a7..f183f61f5 100644
--- a/src/app/components/search/search-results/search-results.component.ts
+++ b/src/app/components/search/search-results/search-results.component.ts
@@ -102,7 +102,7 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
const query = this.formatSearchQuery(this.searchedWord);
if (query) {
- this.queryBuilder.userQuery = query;
+ this.queryBuilder.userQuery = decodeURIComponent(query);
this.queryBuilder.update();
} else {
this.queryBuilder.userQuery = null;
diff --git a/src/app/store/effects/search.effects.spec.ts b/src/app/store/effects/search.effects.spec.ts
new file mode 100644
index 000000000..639a316a8
--- /dev/null
+++ b/src/app/store/effects/search.effects.spec.ts
@@ -0,0 +1,78 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2018 Alfresco Software Limited
+ *
+ * This file is part of the Alfresco Example Content Application.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * The Alfresco Example Content Application is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Alfresco Example Content Application is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+import { TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { AppTestingModule } from '../../testing/app-testing.module';
+import { SearchEffects } from './search.effects';
+import { EffectsModule } from '@ngrx/effects';
+import { Store } from '@ngrx/store';
+import { SearchByTermAction } from '../actions/search.actions';
+import { Router } from '@angular/router';
+
+describe('SearchEffects', () => {
+ let store: Store;
+ let router: Router;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [AppTestingModule, EffectsModule.forRoot([SearchEffects])]
+ });
+
+ store = TestBed.get(Store);
+ router = TestBed.get(Router);
+
+ spyOn(router, 'navigateByUrl').and.stub();
+ });
+
+ describe('searchByTerm$', () => {
+ it('should navigate to `search` when search options has library false', fakeAsync(() => {
+ store.dispatch(new SearchByTermAction('test', []));
+ tick();
+ expect(router.navigateByUrl).toHaveBeenCalledWith('/search;q=test');
+ }));
+
+ it('should navigate to `search-libraries` when search options has library true', fakeAsync(() => {
+ store.dispatch(
+ new SearchByTermAction('test', [{ id: 'libraries', value: true }])
+ );
+
+ tick();
+
+ expect(router.navigateByUrl).toHaveBeenCalledWith(
+ '/search-libraries;q=test'
+ );
+ }));
+
+ it('should encode search string for parentheses', fakeAsync(() => {
+ store.dispatch(new SearchByTermAction('(test)', []));
+
+ tick();
+
+ expect(router.navigateByUrl).toHaveBeenCalledWith(
+ '/search;q=%2528test%2529'
+ );
+ }));
+ });
+});
diff --git a/src/app/store/effects/search.effects.ts b/src/app/store/effects/search.effects.ts
index 2f5cc3673..8b9063c4e 100644
--- a/src/app/store/effects/search.effects.ts
+++ b/src/app/store/effects/search.effects.ts
@@ -38,18 +38,20 @@ export class SearchEffects {
searchByTerm$ = this.actions$.pipe(
ofType(SEARCH_BY_TERM),
map(action => {
+ const query = action.payload
+ .replace(/[(]/g, '%28')
+ .replace(/[)]/g, '%29');
+
const libItem = action.searchOptions.find(
item => item.id === SearchOptionIds.Libraries
);
const librarySelected = !!libItem && libItem.value;
if (librarySelected) {
this.router.navigateByUrl(
- '/search-libraries;q=' + encodeURIComponent(action.payload)
+ '/search-libraries;q=' + encodeURIComponent(query)
);
} else {
- this.router.navigateByUrl(
- '/search;q=' + encodeURIComponent(action.payload)
- );
+ this.router.navigateByUrl('/search;q=' + encodeURIComponent(query));
}
})
);