import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import { InputComponent } from './input.component'; import {AngularMaterialModule} from '../modules/angular-material.module'; import {FormsModule} from '@angular/forms'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {By} from '@angular/platform-browser'; import {SimpleChange, SimpleChanges} from '@angular/core'; import {of} from 'rxjs/internal/observable/of'; import {DataCardService} from '../api/data-card.service'; describe('InputComponent', () => { let component: InputComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ InputComponent ], imports: [AngularMaterialModule, FormsModule, NoopAnimationsModule], providers: [ {provide: DataCardService, useValue: {isDataCardClosed: of(false)}} ] }) .compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(InputComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('detects mouse hover events', (done) => { fixture.whenStable().then(() => { const element = fixture.elementRef.nativeElement; element.dispatchEvent(new Event('mouseenter')); fixture.detectChanges(); expect(component.hover).toBeTrue(); element.dispatchEvent(new Event('mouseleave')); fixture.detectChanges(); expect(component.hover).toBeFalse(); done(); }); }); it('registers as touched on blur', (done) => { let touched = false; component.registerOnTouched(() => touched = true); fixture.whenStable().then(() => { const element = fixture.elementRef.nativeElement; element.dispatchEvent(new Event('blur')); fixture.detectChanges(); expect(touched).toBeTrue(); done(); }); }); it('updates inner value when ngModel is updated on the outside', () => { component.writeValue('tis but a test'); expect(component.innerModel).toEqual('tis but a test'); }); describe('debouncing', () => { beforeEach(() => { fixture = TestBed.createComponent(InputComponent); component = fixture.componentInstance; // Notice how we DON'T call fixture.detectChanges() here - that's because we need to set the debounce // property before we initialize the component fully }); it('debounces input when asked to', fakeAsync(() => { component.debounceInMs = 200; const spy = spyOn(component, 'writeValue').and.callThrough(); fixture.detectChanges(); fixture.whenStable().then(() => { const input = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement; emulateKeystroke(input, 'h'); tick(1); emulateKeystroke(input, 'e'); tick(1); emulateKeystroke(input, 'l'); tick(1); emulateKeystroke(input, 'l'); tick(1); emulateKeystroke(input, 'o'); tick(200); expect(spy).toHaveBeenCalledTimes(1); expect(component.value).toEqual('hello'); }); })); it('does not debounce if not asked to', fakeAsync(() => { component.debounceInMs = undefined; const spy = spyOn(component, 'writeValue').and.callThrough(); fixture.detectChanges(); fixture.whenStable().then(() => { const input = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement; emulateKeystroke(input, 'h'); tick(1); emulateKeystroke(input, 'e'); tick(1); emulateKeystroke(input, 'l'); tick(1); emulateKeystroke(input, 'l'); tick(1); emulateKeystroke(input, 'o'); tick(200); expect(spy).toHaveBeenCalledTimes(5); expect(component.value).toEqual('hello'); }); })); }); it('makes ngModel undefined when set to not relevant', () => { component.writeValue('test'); fixture.detectChanges(); component.notRelevant = true; component.ngOnChanges({notRelevant: {currentValue: true, previousValue: undefined} as SimpleChange} as SimpleChanges); expect(component.value).toBe(''); }); it('re-fills the date when set to not relevant and back again', () => { component.writeValue('test'); fixture.detectChanges(); component.notRelevant = true; component.ngOnChanges({notRelevant: {currentValue: true, previousValue: undefined} as SimpleChange} as SimpleChanges); expect(component.value).toBe(''); component.notRelevant = false; component.ngOnChanges({notRelevant: {currentValue: false, previousValue: true} as SimpleChange} as SimpleChanges); expect(component.value).toBe('test'); }); it('does not register a change on the first value set', () => { // This is to avoid issues where values initialized from an async call will mark the form as dirty const mock = { onChange: (whatever: any) => undefined }; const onChange = spyOn(mock, 'onChange'); component.registerOnChange(onChange); component.writeValue('whatever'); expect(onChange).not.toHaveBeenCalled(); fixture.debugElement.query(By.css('input')).triggerEventHandler('focus', {}); component.writeValue('even more whatever'); expect(onChange).toHaveBeenCalledWith('even more whatever'); }); it('becomes dirtyable when clicked', () => { fixture.debugElement.query(By.css('input')).triggerEventHandler('focus', {}); fixture.detectChanges(); expect((component as any).dirtyAble).toBeTrue(); }); }); function emulateKeystroke(input: HTMLInputElement, char: string): void { input.value += char; input.dispatchEvent(new Event('keyup')); }