From 67e0c02a5a31c598637b1cefa69e5cf85c4b41a5 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Fri, 18 May 2018 19:22:12 +0300 Subject: [PATCH] [ADF-2984] Show date invalid message on search date range picker (#3323) * [ADF-2984] Show date invalid message on search date range picker * [ADF-2984] test that required format is displayed when date input is invalid * [ADF-2984] More space above buttons --- lib/content-services/i18n/en.json | 1 + .../search-date-range.component.html | 12 +- .../search-date-range.component.spec.ts | 284 ++++++++++-------- .../search-date-range.component.ts | 3 +- .../search-filter.component.scss | 4 + 5 files changed, 179 insertions(+), 125 deletions(-) diff --git a/lib/content-services/i18n/en.json b/lib/content-services/i18n/en.json index effecc279a..5b9f89c98c 100644 --- a/lib/content-services/i18n/en.json +++ b/lib/content-services/i18n/en.json @@ -189,6 +189,7 @@ "REQUIRED-VALUE": "Required value", "NO-DAYS": "No days selected.", "INVALID-FORMAT": "Invalid Format", + "INVALID-DATE": "Invalid date. Please enter the date in the format '{{ requiredFormat }}'", "BEYOND-MAX-DATE": "Date is too late." } }, diff --git a/lib/content-services/search/components/search-date-range/search-date-range.component.html b/lib/content-services/search/components/search-date-range/search-date-range.component.html index f50400aeb0..bb69773a0b 100644 --- a/lib/content-services/search/components/search-date-range/search-date-range.component.html +++ b/lib/content-services/search/components/search-date-range/search-date-range.component.html @@ -7,12 +7,15 @@ (focusout)="onChangedHandler($event, from)"> - + {{ 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' | translate }} {{ 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' | translate }} + + {{ 'SEARCH.FILTER.VALIDATION.INVALID-DATE' | translate: { requiredFormat: datePickerDateFormat } }} + @@ -24,7 +27,7 @@ (focusout)="onChangedHandler($event, to)"> - + {{ 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' | translate }} @@ -33,9 +36,12 @@ {{ 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' | translate }} + + {{ 'SEARCH.FILTER.VALIDATION.INVALID-DATE' | translate: { requiredFormat: datePickerDateFormat } }} + -
+
diff --git a/lib/content-services/search/components/search-date-range/search-date-range.component.spec.ts b/lib/content-services/search/components/search-date-range/search-date-range.component.spec.ts index 45996a7792..6ae2fcebaf 100644 --- a/lib/content-services/search/components/search-date-range/search-date-range.component.spec.ts +++ b/lib/content-services/search/components/search-date-range/search-date-range.component.spec.ts @@ -17,140 +17,184 @@ import { CustomMomentDateAdapter, SearchDateRangeComponent } from './search-date-range.component'; import { Observable } from 'rxjs/Observable'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ContentTestingModule } from '../../../testing/content.testing.module'; +import { setupTestBed } from '@alfresco/adf-core'; +import { By } from '@angular/platform-browser'; +import { TranslateService } from '@ngx-translate/core'; declare let moment: any; describe('SearchDateRangeComponent', () => { + describe('component class', () => { - let component: SearchDateRangeComponent; - let fromDate = '2016-10-16'; - let toDate = '2017-10-16'; - const localeFixture = 'it'; - const dateFormatFixture = 'DD-MMM-YY'; + let component: SearchDateRangeComponent; + let fromDate = '2016-10-16'; + let toDate = '2017-10-16'; + const localeFixture = 'it'; + const dateFormatFixture = 'DD-MMM-YY'; - const buildAdapter = (): CustomMomentDateAdapter => { - const dateAdapter = new CustomMomentDateAdapter(null); - dateAdapter.customDateFormat = null; - return dateAdapter; - }; - - const buildUserPreferences = (): any => { - const userPreferences = { - userPreferenceStatus: { LOCALE: localeFixture }, - select: (property) => { - return Observable.of(userPreferences.userPreferenceStatus[property]); - } - }; - return userPreferences; - }; - - const theDateAdapter = buildAdapter(); - - beforeEach(() => { - component = new SearchDateRangeComponent(theDateAdapter, buildUserPreferences()); - }); - - it('should setup form elements on init', () => { - component.ngOnInit(); - expect(component.from).toBeDefined(); - expect(component.to).toBeDefined(); - expect(component.form).toBeDefined(); - }); - - it('should setup locale from userPreferencesService', () => { - spyOn(component, 'setLocale').and.stub(); - component.ngOnInit(); - expect(component.setLocale).toHaveBeenCalledWith(localeFixture); - }); - - it('should setup the format of the date from configuration', () => { - component.settings = { field: 'cm:created', dateFormat: dateFormatFixture }; - component.ngOnInit(); - expect(theDateAdapter.customDateFormat).toBe(dateFormatFixture); - }); - - it('should setup form control with formatted valid date on change', () => { - component.settings = { field: 'cm:created', dateFormat: dateFormatFixture }; - component.ngOnInit(); - - const inputString = '20.feb.18'; - const momentFromInput = moment(inputString, dateFormatFixture); - expect(momentFromInput.isValid()).toBeTruthy(); - - component.onChangedHandler({ srcElement: { value: inputString }}, component.from); - expect(component.from.value).toEqual(momentFromInput); - }); - - it('should NOT setup form control with invalid date on change', () => { - component.settings = { field: 'cm:created', dateFormat: dateFormatFixture }; - component.ngOnInit(); - - const inputString = '20.f.18'; - const momentFromInput = moment(inputString, dateFormatFixture); - expect(momentFromInput.isValid()).toBeFalsy(); - - component.onChangedHandler({ srcElement: { value: inputString }}, component.from); - expect(component.from.value).not.toEqual(momentFromInput); - }); - - it('should reset form', () => { - component.ngOnInit(); - component.form.setValue({ from: fromDate, to: toDate }); - - expect(component.from.value).toEqual(fromDate); - expect(component.to.value).toEqual(toDate); - - component.reset(); - - expect(component.from.value).toEqual(''); - expect(component.to.value).toEqual(''); - expect(component.form.value).toEqual({ from: '', to: '' }); - }); - - it('should update query builder on reset', () => { - const context: any = { - queryFragments: { - createdDateRange: 'query' - }, - update() {} + const buildAdapter = (): CustomMomentDateAdapter => { + const dateAdapter = new CustomMomentDateAdapter(null); + dateAdapter.customDateFormat = null; + return dateAdapter; }; - component.id = 'createdDateRange'; - component.context = context; - - spyOn(context, 'update').and.stub(); - - component.ngOnInit(); - component.reset(); - - expect(context.queryFragments.createdDateRange).toEqual(''); - expect(context.update).toHaveBeenCalled(); - }); - - it('should update query builder on value changes', () => { - const context: any = { - queryFragments: {}, - update() {} + const buildUserPreferences = (): any => { + const userPreferences = { + userPreferenceStatus: {LOCALE: localeFixture}, + select: (property) => { + return Observable.of(userPreferences.userPreferenceStatus[property]); + } + }; + return userPreferences; }; - component.id = 'createdDateRange'; - component.context = context; - component.settings = { field: 'cm:created' }; + const theDateAdapter = buildAdapter(); - spyOn(context, 'update').and.stub(); + beforeEach(() => { + component = new SearchDateRangeComponent(theDateAdapter, buildUserPreferences()); + }); - component.ngOnInit(); - component.apply({ - from: fromDate, - to: toDate - }, true); + it('should setup form elements on init', () => { + component.ngOnInit(); + expect(component.from).toBeDefined(); + expect(component.to).toBeDefined(); + expect(component.form).toBeDefined(); + }); - const startDate = moment(fromDate).startOf('day').format(); - const endDate = moment(toDate).endOf('day').format(); + it('should setup locale from userPreferencesService', () => { + spyOn(component, 'setLocale').and.stub(); + component.ngOnInit(); + expect(component.setLocale).toHaveBeenCalledWith(localeFixture); + }); - const expectedQuery = `cm:created:['${startDate}' TO '${endDate}']`; - expect(context.queryFragments[component.id]).toEqual(expectedQuery); - expect(context.update).toHaveBeenCalled(); + it('should setup the format of the date from configuration', () => { + component.settings = {field: 'cm:created', dateFormat: dateFormatFixture}; + component.ngOnInit(); + expect(theDateAdapter.customDateFormat).toBe(dateFormatFixture); + }); + + it('should setup form control with formatted valid date on change', () => { + component.settings = {field: 'cm:created', dateFormat: dateFormatFixture}; + component.ngOnInit(); + + const inputString = '20.feb.18'; + const momentFromInput = moment(inputString, dateFormatFixture); + expect(momentFromInput.isValid()).toBeTruthy(); + + component.onChangedHandler({srcElement: {value: inputString}}, component.from); + expect(component.from.value.toString()).toEqual(momentFromInput.toString()); + }); + + it('should NOT setup form control with invalid date on change', () => { + component.settings = {field: 'cm:created', dateFormat: dateFormatFixture}; + component.ngOnInit(); + + const inputString = '20.f.18'; + const momentFromInput = moment(inputString, dateFormatFixture); + expect(momentFromInput.isValid()).toBeFalsy(); + + component.onChangedHandler({srcElement: {value: inputString}}, component.from); + expect(component.from.value.toString()).not.toEqual(momentFromInput.toString()); + }); + + it('should reset form', () => { + component.ngOnInit(); + component.form.setValue({from: fromDate, to: toDate}); + + expect(component.from.value).toEqual(fromDate); + expect(component.to.value).toEqual(toDate); + + component.reset(); + + expect(component.from.value).toEqual(''); + expect(component.to.value).toEqual(''); + expect(component.form.value).toEqual({from: '', to: ''}); + }); + + it('should update query builder on reset', () => { + const context: any = { + queryFragments: { + createdDateRange: 'query' + }, + update() {} + }; + + component.id = 'createdDateRange'; + component.context = context; + + spyOn(context, 'update').and.stub(); + + component.ngOnInit(); + component.reset(); + + expect(context.queryFragments.createdDateRange).toEqual(''); + expect(context.update).toHaveBeenCalled(); + }); + + it('should update query builder on value changes', () => { + const context: any = { + queryFragments: {}, + update() {} + }; + + component.id = 'createdDateRange'; + component.context = context; + component.settings = {field: 'cm:created'}; + + spyOn(context, 'update').and.stub(); + + component.ngOnInit(); + component.apply({ + from: fromDate, + to: toDate + }, true); + + const startDate = moment(fromDate).startOf('day').format(); + const endDate = moment(toDate).endOf('day').format(); + + const expectedQuery = `cm:created:['${startDate}' TO '${endDate}']`; + expect(context.queryFragments[component.id]).toEqual(expectedQuery); + expect(context.update).toHaveBeenCalled(); + }); }); + describe('component DOM', () => { + let component: SearchDateRangeComponent; + let fixture: ComponentFixture; + let translateService: TranslateService; + let translationSpy: jasmine.Spy; + const dateFormatFixture = 'DD MMM YYYY'; + + setupTestBed({ + imports: [ContentTestingModule] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SearchDateRangeComponent); + component = fixture.componentInstance; + + translateService = TestBed.get(TranslateService); + translationSpy = spyOn(translateService, 'get').and.callFake((key) => { + return Observable.of(key); + }); + + component.settings = {'dateFormat': dateFormatFixture, field: 'cm:created'}; + fixture.detectChanges(); + }); + + it('should display the required format when input date is invalid', () => { + const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + + inputEl.value = 'invalid-date'; + inputEl.dispatchEvent(new Event('input')); + fixture.detectChanges(); + inputEl.dispatchEvent(new Event('blur')); + fixture.detectChanges(); + + expect(translationSpy.calls.mostRecent().args) + .toEqual(['SEARCH.FILTER.VALIDATION.INVALID-DATE', {requiredFormat: dateFormatFixture}]); + }); + }); }); diff --git a/lib/content-services/search/components/search-date-range/search-date-range.component.ts b/lib/content-services/search/components/search-date-range/search-date-range.component.ts index 7480b28c70..308e38f8a9 100644 --- a/lib/content-services/search/components/search-date-range/search-date-range.component.ts +++ b/lib/content-services/search/components/search-date-range/search-date-range.component.ts @@ -127,8 +127,7 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit { const inputValue = event.srcElement.value; if (inputValue) { - const formatDate = moment(inputValue, this.datePickerDateFormat); - + const formatDate = this.dateAdapter.parse(inputValue, this.datePickerDateFormat); if (formatDate.isValid()) { formControl.setValue(formatDate); } diff --git a/lib/content-services/search/components/search-filter/search-filter.component.scss b/lib/content-services/search/components/search-filter/search-filter.component.scss index e2bab4350b..add604040d 100644 --- a/lib/content-services/search/components/search-filter/search-filter.component.scss +++ b/lib/content-services/search/components/search-filter/search-filter.component.scss @@ -24,6 +24,10 @@ .mat-button { text-transform: uppercase; } + + &--topSpace { + padding-top: 15px; + } } }