diff --git a/projects/novo-elements/src/elements/date-picker/DatePickerInput.spec.ts b/projects/novo-elements/src/elements/date-picker/DatePickerInput.spec.ts index fbc72a12b..a0f5c5093 100644 --- a/projects/novo-elements/src/elements/date-picker/DatePickerInput.spec.ts +++ b/projects/novo-elements/src/elements/date-picker/DatePickerInput.spec.ts @@ -1,12 +1,14 @@ // NG2 +import { EventEmitter } from '@angular/core'; import { TestBed, async } from '@angular/core/testing'; +import { TAB, ENTER, ESCAPE } from '@angular/cdk/keycodes'; // App import { NovoDatePickerInputElement } from './DatePickerInput'; import { NovoLabelService } from '../../services/novo-label-service'; import { NovoDatePickerModule } from './DatePicker.module'; import { DateFormatService } from '../../services/date-format/DateFormat'; -xdescribe('Elements: NovoDatePickerInputElement', () => { +describe('Elements: NovoDatePickerInputElement', () => { let fixture; let component; @@ -22,6 +24,151 @@ xdescribe('Elements: NovoDatePickerInputElement', () => { component = fixture.debugElement.componentInstance; })); + describe('Method: openPanel()', () => { + it('should open the Calendar picker panel if the field has not been disabled', () => { + // Arrange + component.disabled = false; + spyOn(component.overlay, 'openPanel'); + // Act + component.openPanel(); + // Assert + expect(component.overlay.openPanel).toHaveBeenCalled(); + }); + + it('should not open the Calendar picker panel if the field has been disabled', () => { + // Arrange + component.disabled = true; + spyOn(component.overlay, 'openPanel'); + // Act + component.openPanel(); + // Assert + expect(component.overlay.openPanel).not.toHaveBeenCalled(); + }); + }); + + describe('Method: _handleKeydown(event)', () => { + let keyboardEvent: Pick; + beforeEach(async () => { + keyboardEvent = { keyCode: undefined, target: new EventTarget(), stopPropagation: () => {} }; + spyOn(component, 'openPanel').and.callFake(() => {}); + spyOn(component, 'closePanel').and.callFake(() => {}); + spyOn(component, 'formatDate'); + spyOn(keyboardEvent, 'stopPropagation'); + }); + + it('should call formatDate if the Enter key has been pressed', () => { + // Arrange + const enterEvent: Pick = { + ...keyboardEvent, + keyCode: ENTER, + }; + // Act + component._handleKeydown(enterEvent); + // Assert + expect(component.formatDate).toHaveBeenCalled(); + expect(enterEvent.stopPropagation).toHaveBeenCalled(); + }); + + it('should call formatDate if the Tab key has been pressed', () => { + // Arrange + const tabEvent: Pick = { + ...keyboardEvent, + keyCode: TAB, + }; + // Act + component._handleKeydown(tabEvent); + // Assert + expect(component.formatDate).toHaveBeenCalled(); + expect(tabEvent.stopPropagation).toHaveBeenCalled(); + }); + + it('should call closePanel if the Tab key has been pressed', () => { + // Arrange + const tabEvent: Pick = { + ...keyboardEvent, + keyCode: TAB, + }; + // Act + component._handleKeydown(tabEvent); + // Assert + expect(component.closePanel).toHaveBeenCalled(); + expect(tabEvent.stopPropagation).toHaveBeenCalled(); + }); + + it('should set value that appears in the field to the value it had before edits were made if the Escape key has been pressed', () => { + // Arrange + const escapeEvent: Pick = { + ...keyboardEvent, + keyCode: ESCAPE, + }; + component.formattedValue = 'Test1'; + component.currentValue = 'Test2'; + // Act + component._handleKeydown(escapeEvent); + // Assert + expect(component.formattedValue).toBe('Test2'); + expect(escapeEvent.stopPropagation).toHaveBeenCalled(); + }); + + it('should call closePanel if the Escape key has been pressed', () => { + // Arrange + const escapeEvent: Pick = { + ...keyboardEvent, + keyCode: ESCAPE, + }; + // Act + component._handleKeydown(escapeEvent); + // Assert + expect(component.closePanel).toHaveBeenCalled(); + expect(escapeEvent.stopPropagation).toHaveBeenCalled(); + }); + }); + + describe('Method: _handleBlur()', () => { + let blurEvent: Pick = { type: 'blur' }; + it('should reset the value in the field if it is different from the original', () => { + // Arrange + spyOn(component.blurEvent, 'emit'); + component.currentValue = 'Test1'; + component.formattedValue = 'Test2'; + // Act + component._handleBlur(blurEvent); + // Assert + expect(component.formattedValue).toBe('Test1'); + }); + }); + + describe('Method: _handleFocus()', () => { + let focusEvent: Pick = { type: 'focus' }; + + it('should set the current value to that which is currently in the field upon focusing', () => { + // Arrange + spyOn(component.focusEvent, 'emit'); + spyOn(component, 'openPanel').and.callFake(() => {}); + component.currentValue = 'Test1'; + component.formattedValue = 'Test2'; + // Act + component._handleFocus(focusEvent); + // Assert + expect(component.currentValue).toBe('Test2'); + }); + }); + + describe('Method: _setFormValue()', () => { + it('should set the currentValue and formattedValue to the same upon saving when this.value is defined', () => { + // Arrange + component.value = '06/07/2008'; + component.formattedValue = ''; + component.currentValue = ''; + spyOn(component, 'formatDateValue').and.returnValue(component.value); + // Act + component._setFormValue(component.value); + // Assert + expect(component.currentValue).toBe('06/07/2008'); + expect(component.formattedValue).toBe('06/07/2008'); + }); + }); + describe('Method: formatDate()', () => { it('should call parseString from the dateFormatService and then dispatchOnChange.', () => { spyOn(component.dateFormatService, 'parseString').and.callThrough(); diff --git a/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts b/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts index fde64582d..ce5897400 100644 --- a/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts +++ b/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts @@ -37,7 +37,17 @@ const DATE_VALUE_ACCESSOR = { selector: 'novo-date-picker-input', providers: [DATE_VALUE_ACCESSOR], template: ` - + @@ -49,6 +59,8 @@ export class NovoDatePickerInputElement implements OnInit, ControlValueAccessor public value: any; public formattedValue: string = ''; private userDefinedFormat: boolean; + private currentValue: string = ''; + private valueChanged: boolean = false; /** View -> model callback called when value changes */ _onChange: (value: any) => void = () => {}; @@ -112,43 +124,50 @@ export class NovoDatePickerInputElement implements OnInit, ControlValueAccessor this.overlay.openPanel(); } } + closePanel(): void { this.overlay.closePanel(); } + get panelOpen(): boolean { return this.overlay && this.overlay.panelOpen; } /** END: Convenient Panel Methods. */ - _handleKeydown(event: KeyboardEvent): void { - if ((event.keyCode === ESCAPE || event.keyCode === ENTER || event.keyCode === TAB) && this.panelOpen) { - this._handleEvent(event, true); + _handleKeydown({ keyCode, target, stopPropagation }: Pick): void { + if (!this.panelOpen) { + this.openPanel(); + } + if (keyCode === ENTER || keyCode === TAB) { + let value = this._getHTMLInputElementValue(target); + this.formatDate(value, true); + if (keyCode === TAB) { + this.closePanel(); + } + } else if (keyCode === ESCAPE) { + this.formattedValue = this.currentValue; this.closePanel(); - event.stopPropagation(); } + stopPropagation(); } - _handleInput(event: KeyboardEvent): void { - if (document.activeElement === event.target) { - this._handleEvent(event, false); - } + _getHTMLInputElementValue(target: EventTarget): string { + return (target as HTMLInputElement).value; } _handleBlur(event: FocusEvent): void { + if (this.currentValue !== this.formattedValue) { + this.formattedValue = this.currentValue; + } this.blurEvent.emit(event); } _handleFocus(event: FocusEvent): void { this.openPanel(); + this.currentValue = this.formattedValue; this.focusEvent.emit(event); } - _handleEvent(event: Event, blur: boolean): void { - let value = (event.target as HTMLInputElement).value; - this.formatDate(value, blur); - this.openPanel(); - } - protected formatDate(value: string, blur: boolean) { try { let [dateTimeValue, formatted] = this.dateFormatService.parseString(value, false, 'date'); @@ -205,6 +224,7 @@ export class NovoDatePickerInputElement implements OnInit, ControlValueAccessor if (this.value) { let test = this.formatDateValue(this.value); this.formattedValue = test; + this.currentValue = this.formattedValue; } }