diff --git a/resources/i18n/en.json b/resources/i18n/en.json index b6a23068d7..169ff0efe9 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -92,7 +92,8 @@ }, "results": { "head": "Search Results", - "no-results": "There were no results for this search" + "no-results": "Your search returned no results. Having trouble finding what you're looking for? Try putting", + "no-results-link": "quotes around it" }, "sidebar": { "close": "Back to results", diff --git a/src/app/+search-page/search-results/search-results.component.html b/src/app/+search-page/search-results/search-results.component.html index ed6fc18d9c..4915b552c3 100644 --- a/src/app/+search-page/search-results/search-results.component.html +++ b/src/app/+search-page/search-results/search-results.component.html @@ -7,5 +7,12 @@ [hideGear]="true"> - - + +
+ {{ 'search.results.no-results' | translate }} + + {{"search.results.no-results-link" | translate}} + +
diff --git a/src/app/+search-page/search-results/search-results.component.spec.ts b/src/app/+search-page/search-results/search-results.component.spec.ts index 4f299c5c50..54463d916d 100644 --- a/src/app/+search-page/search-results/search-results.component.spec.ts +++ b/src/app/+search-page/search-results/search-results.component.spec.ts @@ -1,40 +1,92 @@ import { ComponentFixture, TestBed, async, tick, fakeAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ResourceType } from '../../core/shared/resource-type'; import { Community } from '../../core/shared/community.model'; import { TranslateModule } from '@ngx-translate/core'; import { SearchResultsComponent } from './search-results.component'; +import { QueryParamsDirectiveStub } from '../../shared/testing/query-params-directive-stub'; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; let fixture: ComponentFixture; - let heading: DebugElement; beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - declarations: [SearchResultsComponent], + imports: [TranslateModule.forRoot(), NoopAnimationsModule], + declarations: [ + SearchResultsComponent, + QueryParamsDirectiveStub], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(SearchResultsComponent); - comp = fixture.componentInstance; // SearchFormComponent test instance - heading = fixture.debugElement.query(By.css('heading')); + comp = fixture.componentInstance; // SearchResultsComponent test instance }); - it('should display heading when results are not empty', fakeAsync(() => { - (comp as any).searchResults = 'test'; - (comp as any).searchConfig = {pagination: ''}; + it('should display results when results are not empty', () => { + (comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } }; + (comp as any).searchConfig = {}; fixture.detectChanges(); - tick(); - expect(heading).toBeDefined(); - })); + expect(fixture.debugElement.query(By.css('ds-viewable-collection'))).not.toBeNull(); + }); - it('should not display heading when results is empty', () => { - expect(heading).toBeNull(); + it('should not display link when results are not empty', () => { + (comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } }; + (comp as any).searchConfig = {}; + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('a'))).toBeNull(); + }); + + it('should display error message if error is != 400', () => { + (comp as any).searchResults = { hasFailed: true, error: { statusCode: 500 } }; + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('ds-error'))).not.toBeNull(); + }); + + it('should display link with new search where query is quoted if search return a error 400', () => { + (comp as any).searchResults = { hasFailed: true, error: { statusCode: 400 } }; + (comp as any).searchConfig = { query: 'foobar' }; + fixture.detectChanges(); + + const linkDes = fixture.debugElement.queryAll(By.directive(QueryParamsDirectiveStub)); + + // get attached link directive instances + // using each DebugElement's injector + const routerLinkQuery = linkDes.map((de) => de.injector.get(QueryParamsDirectiveStub)); + + expect(routerLinkQuery.length).toBe(1, 'should have 1 router link with query params'); + expect(routerLinkQuery[0].queryParams.query).toBe('"foobar"', 'query params should be "foobar"'); + }); + + it('should display link with new search where query is quoted if search result is empty', () => { + (comp as any).searchResults = { payload: { page: { length: 0 } } }; + (comp as any).searchConfig = { query: 'foobar' }; + fixture.detectChanges(); + + const linkDes = fixture.debugElement.queryAll(By.directive(QueryParamsDirectiveStub)); + + // get attached link directive instances + // using each DebugElement's injector + const routerLinkQuery = linkDes.map((de) => de.injector.get(QueryParamsDirectiveStub)); + + expect(routerLinkQuery.length).toBe(1, 'should have 1 router link with query params'); + expect(routerLinkQuery[0].queryParams.query).toBe('"foobar"', 'query params should be "foobar"'); + }); + + it('should add quotes around the given string', () => { + expect(comp.surroundStringWithQuotes('teststring')).toEqual('"teststring"'); + }); + + it('should not add quotes around the given string if they are already there', () => { + expect(comp.surroundStringWithQuotes('"teststring"')).toEqual('"teststring"'); + }); + + it('should not add quotes around a given empty string', () => { + expect(comp.surroundStringWithQuotes('')).toEqual(''); }); }); diff --git a/src/app/+search-page/search-results/search-results.component.ts b/src/app/+search-page/search-results/search-results.component.ts index 6399243f92..ae0abfcd27 100644 --- a/src/app/+search-page/search-results/search-results.component.ts +++ b/src/app/+search-page/search-results/search-results.component.ts @@ -6,6 +6,7 @@ import { SearchOptions } from '../search-options.model'; import { SearchResult } from '../search-result.model'; import { PaginatedList } from '../../core/data/paginated-list'; import { ViewMode } from '../../core/shared/view-mode.model'; +import { isNotEmpty } from '../../shared/empty.util'; @Component({ selector: 'ds-search-results', @@ -35,4 +36,16 @@ export class SearchResultsComponent { */ @Input() viewMode: ViewMode; + /** + * Method to change the given string by surrounding it by quotes if not already present. + */ + surroundStringWithQuotes(input: string): string { + let result = input; + + if (isNotEmpty(result) && !(result.startsWith('\"') && result.endsWith('\"'))) { + result = `"${result}"`; + } + + return result; + } } diff --git a/src/app/shared/testing/query-params-directive-stub.ts b/src/app/shared/testing/query-params-directive-stub.ts new file mode 100644 index 0000000000..c19c5e6a5f --- /dev/null +++ b/src/app/shared/testing/query-params-directive-stub.ts @@ -0,0 +1,10 @@ +import { Directive, Input } from '@angular/core'; + +/* tslint:disable:directive-class-suffix */ +@Directive({ + // tslint:disable-next-line:directive-selector + selector: '[queryParams]', +}) +export class QueryParamsDirectiveStub { + @Input('queryParams') queryParams: any; +} diff --git a/src/app/shared/testing/test-module.ts b/src/app/shared/testing/test-module.ts new file mode 100644 index 0000000000..03d22640d3 --- /dev/null +++ b/src/app/shared/testing/test-module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { QueryParamsDirectiveStub } from './query-params-directive-stub'; + +/** + * This module isn't used. It serves to prevent the AoT compiler + * complaining about components/pipes/directives that were + * created only for use in tests. + * See https://github.com/angular/angular/issues/13590 + */ +@NgModule({ + declarations: [ + QueryParamsDirectiveStub + ] +}) +export class TestModule {}