import 'reflect-metadata'; import { ChangeDetectorRef, ElementRef, Renderer2, } from '@angular/core'; import { DropdownBoxV2Component, } from './dropdown-box-v2.component'; const initDropdownBoxComponent = ( window?: Window, renderer?: Renderer2, changeDetectorRef?: ChangeDetectorRef, ) => new DropdownBoxV2Component( window, renderer, changeDetectorRef, ); describe('ngOnChanges', () => { test('Sets the selectedOption from the provided value', () => { const dropdownBoxComponent = initDropdownBoxComponent(); dropdownBoxComponent.isOpen = false; dropdownBoxComponent.selectedOption = undefined; dropdownBoxComponent.options = [ { label: 'foo', value: 'bar' }, { label: 'widgets', value: 'doodads'}, ]; dropdownBoxComponent.value = 'doodads'; dropdownBoxComponent.ngOnChanges(); expect(dropdownBoxComponent.selectedOption.value) .toBe('doodads'); }); }); describe('onClick', () => { const initOnClickData = () => { const window = {} as Window; const mockUnlistenFunction = () => undefined; const renderer = {} as Renderer2; renderer.listen = jest.fn().mockReturnValue(jest.fn()); const changeDetectorRef = {} as ChangeDetectorRef; changeDetectorRef.detectChanges = jest.fn(); const dropdownBoxComponent = initDropdownBoxComponent( window, renderer, changeDetectorRef, ); dropdownBoxComponent.isOpen = false; dropdownBoxComponent.rendererWindowUnlisten = jest.fn( () => 'foo', ); dropdownBoxComponent.onClickOutside = () => undefined; dropdownBoxComponent.onClickOutside.bind = jest.fn(); return { changeDetectorRef, dropdownBoxComponent, mockUnlistenFunction, renderer, window, }; }; test('Calls rendererWindowUnlisten', () => { const { dropdownBoxComponent, } = initOnClickData(); const unlisten = dropdownBoxComponent.rendererWindowUnlisten; dropdownBoxComponent.onClick(undefined, undefined); expect(unlisten).toHaveBeenCalled(); }); test('Resets rendererWindowUnlisten', () => { const { dropdownBoxComponent, } = initOnClickData(); const initialUnlisten = dropdownBoxComponent.rendererWindowUnlisten; dropdownBoxComponent.onClick(undefined, undefined); const postClickUnlisten = dropdownBoxComponent.rendererWindowUnlisten; expect(initialUnlisten) .not.toBe(postClickUnlisten); }); test('Calls renderer.listen', () => { const { dropdownBoxComponent, renderer, window, } = initOnClickData(); dropdownBoxComponent.onClick(undefined, undefined); expect(renderer.listen) .toHaveBeenCalledWith( window, 'click', dropdownBoxComponent.onClickOutside.bind(dropdownBoxComponent), ); }); // tslint:disable-next-line test('Opens closed DropdownBox', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.onClick(undefined, undefined); expect(dropdownBoxComponent.isOpen) .toBe(true); }); // tslint:disable-next-line test('Closes opened DropdownBox', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.isOpen = true; dropdownBoxComponent.onClick(undefined, undefined); expect(dropdownBoxComponent.isOpen) .toBe(false); }); // tslint:disable-next-line test('Calls onChange', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.onChange.emit = jest.fn(); dropdownBoxComponent.onClick('testKey', 'newValue'); expect(dropdownBoxComponent.onChange.emit) .toHaveBeenCalledWith('testKey'); }); // tslint:disable-next-line test('Changes value of DropdownBox when different option is selected', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.onChange.emit = jest.fn(); dropdownBoxComponent.selectedOption = { label: 'foo', value: 'bar', }; dropdownBoxComponent.onClick('widgets', 'doodads'); expect(dropdownBoxComponent.selectedOption) .toEqual( { label: 'doodads', labelUnit0: false, labelUnit1: false, value: 'widgets', }, ); }); // tslint:disable-next-line test('Change is not emitted when currently applied option is selected', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.onChange.emit = jest.fn(); dropdownBoxComponent.selectedOption = { label: 'foo', value: 'bar', }; dropdownBoxComponent.onClick('bar', 'foo'); expect(dropdownBoxComponent.onChange.emit) .not.toHaveBeenCalled(); }); // tslint:disable-next-line test('Value of DropdownBox is not changed when currently applied option is selected', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.onChange.emit = jest.fn(); dropdownBoxComponent.selectedOption = { label: 'foo', value: 'bar', }; dropdownBoxComponent.onClick('bar', 'foo'); expect(dropdownBoxComponent.selectedOption.label) .toBe('foo'); }); // tslint:disable-next-line test('Value not lost when opened', () => { const { dropdownBoxComponent, } = initOnClickData(); dropdownBoxComponent.onChange.emit = jest.fn(); dropdownBoxComponent.selectedOption = { label: 'foo', value: 'bar', }; dropdownBoxComponent.isOpen = false; dropdownBoxComponent.onClick(undefined, null); expect(dropdownBoxComponent.selectedOption) .toEqual( { label: 'foo', value: 'bar', }, ); }); }); describe('onClickOutside', () => { const initOnClickOutsideData = () => { const window = {} as Window; const changeDetectorRef = {} as ChangeDetectorRef; changeDetectorRef.markForCheck = jest.fn(); const dropdownBoxComponent = initDropdownBoxComponent( window, undefined, changeDetectorRef, ); dropdownBoxComponent.isOpen = true; dropdownBoxComponent.dropDownRoot = { nativeElement: {} as Element, } as ElementRef; dropdownBoxComponent.dropDownRoot.nativeElement.contains = jest.fn() .mockReturnValue(false); dropdownBoxComponent.rendererWindowUnlisten = jest.fn(); const mockEvent = {} as MouseEvent; Object.defineProperty(mockEvent, 'target', { value: {} as Element, }); return { changeDetectorRef, dropdownBoxComponent, mockEvent, }; }; // tslint:disable-next-line test('Calls nativeElement.contains for the drop down root element', () => { const { dropdownBoxComponent, mockEvent, } = initOnClickOutsideData(); dropdownBoxComponent.onClickOutside(mockEvent); expect(dropdownBoxComponent.dropDownRoot.nativeElement.contains) .toHaveBeenCalledWith(mockEvent.target); }); // tslint:disable-next-line test('Calls nativeElement.contains for the drop down root element', () => { const { changeDetectorRef, dropdownBoxComponent, mockEvent, } = initOnClickOutsideData(); dropdownBoxComponent.onClickOutside(mockEvent); expect(changeDetectorRef.markForCheck) .toHaveBeenCalled(); }); // tslint:disable-next-line test('Sets isOpen to false if clicked element is not descendent of the dropdown component', () => { const { dropdownBoxComponent, mockEvent, } = initOnClickOutsideData(); dropdownBoxComponent.onClickOutside(mockEvent); expect(dropdownBoxComponent.isOpen).toBe(false); }); // tslint:disable-next-line test('Calls rendererWindowUnlisten is isOpen is false', () => { const { dropdownBoxComponent, mockEvent, } = initOnClickOutsideData(); dropdownBoxComponent.isOpen = false; const unlistener = dropdownBoxComponent.rendererWindowUnlisten; dropdownBoxComponent.onClickOutside(mockEvent); expect(unlistener).toHaveBeenCalled(); }); // tslint:disable-next-line test('Sets rendererWindowUnlisten to undefined if isOpen is false', () => { const { dropdownBoxComponent, mockEvent, } = initOnClickOutsideData(); dropdownBoxComponent.isOpen = false; dropdownBoxComponent.onClickOutside(mockEvent); expect(dropdownBoxComponent.rendererWindowUnlisten).toBeUndefined(); }); }); describe('ngOnDestroy', () => { test('Calls rendererWindowUnlisten if set', () => { const dropdownBoxComponent = initDropdownBoxComponent(); dropdownBoxComponent.rendererWindowUnlisten = jest.fn(); const unlisten = dropdownBoxComponent.rendererWindowUnlisten; dropdownBoxComponent.ngOnDestroy(); expect(unlisten).toHaveBeenCalled(); }); });