import 'reflect-metadata'; import { requiredMocks, } from './../../../../test-mocks'; requiredMocks(jest); import { ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, ViewContainerRef, } from '@angular/core'; import * as mock from './../../../mocks/index'; const initMockDocument = mock.document(jest); const initViewContainerRef = mock.viewContainerRef(jest); import { TooltipMiniComponent, } from './tooltip-mini.component'; import { TooltipMiniDirective, } from './tooltip-mini.directive'; import { BrowserDetectorService, } from './../../../helpers/services/index'; const initTooltipMiniDirective = ( viewContainerRef?: ViewContainerRef, componentFactoryResolver?: ComponentFactoryResolver, document: Document = initMockDocument(), browserDetectorService?: BrowserDetectorService, ) => { return new TooltipMiniDirective( viewContainerRef, componentFactoryResolver, document, browserDetectorService, ); }; const initTooltipMiniComponent = ( tooltipDirective: TooltipMiniDirective, ) => { const tooltipMiniComponent = { instance: {}, location: { nativeElement: { style: {}, }, }, } as ComponentRef; tooltipMiniComponent.location.nativeElement.getBoundingClientRect = jest.fn().mockReturnValue({ left: 5, right: 5, }); tooltipDirective.tooltipMiniComponent = tooltipMiniComponent; }; const initChangeDetector = ( tooltipDirective: TooltipMiniDirective, ) => { tooltipDirective.tooltipMiniComponent .instance.changeDetectorRef = {} as ChangeDetectorRef; tooltipDirective.tooltipMiniComponent.instance .changeDetectorRef.markForCheck = jest.fn(); }; describe('ngOnInit', () => { // tslint:disable-next-line test('It calls resolveComponentFactory on componentFactoryResolver with the TooltipMiniComponent', () => { const viewContainerRef = { } as ViewContainerRef; viewContainerRef.createComponent = jest.fn().mockReturnValue({ location: {}, }); const componentFactoryResolver = {} as ComponentFactoryResolver; componentFactoryResolver.resolveComponentFactory = jest.fn(); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, componentFactoryResolver, ); tooltipDirective.initTooltipComponentVariables = jest.fn(); tooltipDirective.ngOnInit(); expect(componentFactoryResolver .resolveComponentFactory) .toHaveBeenCalledWith( TooltipMiniComponent, ); }); // tslint:disable-next-line test('It calls createComponent on viewContainerRef with the result of componentFactoryResolver.resolveComponentFactory', () => { const viewContainerRef = { } as ViewContainerRef; const resolveComponentResult = {}; viewContainerRef.createComponent = jest.fn().mockReturnValue({ location: {}, }); const componentFactoryResolver = {} as ComponentFactoryResolver; componentFactoryResolver.resolveComponentFactory = jest.fn().mockReturnValue(resolveComponentResult); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, componentFactoryResolver, ); tooltipDirective.initTooltipComponentVariables = jest.fn(); tooltipDirective.ngOnInit(); expect(viewContainerRef.createComponent) .toHaveBeenCalledWith( resolveComponentResult, ); }); // tslint:disable-next-line test('It sets the tooltipMiniComponent to the response of viewContainerRef.createComponent', () => { const viewContainerRef = { } as ViewContainerRef; const createComponentResult = { location: {}, }; viewContainerRef.createComponent = jest.fn().mockReturnValue( createComponentResult, ); const componentFactoryResolver = {} as ComponentFactoryResolver; componentFactoryResolver.resolveComponentFactory = jest.fn(); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, componentFactoryResolver, ); tooltipDirective.initTooltipComponentVariables = jest.fn(); tooltipDirective.ngOnInit(); expect(tooltipDirective.tooltipMiniComponent) .toBe(createComponentResult); }); // tslint:disable-next-line test('It calls document.body.appendChild with tooltipMiniComponent.location.nativeElement', () => { const viewContainerRef = { } as ViewContainerRef; const expectedTooltipComponentNativeElement = {}; const createComponentResult = { location: { nativeElement: expectedTooltipComponentNativeElement, }, }; viewContainerRef.createComponent = jest.fn().mockReturnValue( createComponentResult, ); const componentFactoryResolver = {} as ComponentFactoryResolver; componentFactoryResolver.resolveComponentFactory = jest.fn(); const document = initMockDocument(); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, componentFactoryResolver, document, ); tooltipDirective.initTooltipComponentVariables = jest.fn(); tooltipDirective.ngOnInit(); expect( document.body.appendChild, ).toHaveBeenCalledWith( expectedTooltipComponentNativeElement, ); }); // tslint:disable-next-line test('It calls initTooltipComponentVariables', () => { const viewContainerRef = { } as ViewContainerRef; const createComponentResult = { location: {}, }; viewContainerRef.createComponent = jest.fn().mockReturnValue( createComponentResult, ); const componentFactoryResolver = {} as ComponentFactoryResolver; componentFactoryResolver.resolveComponentFactory = jest.fn(); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, componentFactoryResolver, ); tooltipDirective.initTooltipComponentVariables = jest.fn(); tooltipDirective.ngOnInit(); expect( tooltipDirective.initTooltipComponentVariables, ).toHaveBeenCalled(); }); }); describe('ngOnChanges', () => { // tslint:disable-next-line test('It calls initTooltipComponentVariables', () => { const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.initTooltipComponentVariables = jest.fn(); tooltipDirective.ngOnChanges(); expect( tooltipDirective.initTooltipComponentVariables, ).toHaveBeenCalled(); }); }); describe('ngOnDestroy', () => { // tslint:disable-next-line test('It calls tooltipMiniComponent.destroy', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); tooltipDirective.tooltipMiniComponent.destroy = jest.fn(); tooltipDirective.ngOnDestroy(); expect(tooltipDirective.tooltipMiniComponent.destroy) .toHaveBeenCalled(); }); }); describe('initTooltipComponentVariables', () => { // tslint:disable-next-line test('It sets the tooltipMiniComponent.text to the value in tooltip', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); tooltipDirective.tooltipMini = 'test'; tooltipDirective.initTooltipComponentVariables(); expect( tooltipDirective.tooltipMiniComponent .instance.text, ).toBe(tooltipDirective.tooltipMini); }); // tslint:disable-next-line test('It calls tooltipMiniComponent.instance.changeDetectorRef.markForCheck', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); tooltipDirective.initTooltipComponentVariables(); expect( tooltipDirective.tooltipMiniComponent .instance.changeDetectorRef.markForCheck, ).toHaveBeenCalled(); }); }); describe('updateTooltipLocation', () => { const setsBasicStyleValues = ( styleName: string, expectedValue: string, ) => { const viewContainerRef = initViewContainerRef(); viewContainerRef.element.nativeElement .getBoundingClientRect = jest.fn() .mockReturnValue({}); const document = initMockDocument(); document.body.getBoundingClientRect = jest.fn() .mockReturnValue({}); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, undefined, document, ); initTooltipMiniComponent(tooltipDirective); tooltipDirective.updateTooltipLocation(); expect( tooltipDirective.tooltipMiniComponent .location.nativeElement.style[styleName], ).toBe(expectedValue); }; const initUpdateTooltipLocationData = () => { const viewContainerRef = initViewContainerRef(); viewContainerRef.element.nativeElement .getBoundingClientRect = jest.fn() .mockReturnValue({ left: 30, top: 10, width: 10, }); const document = initMockDocument(); document.body.getBoundingClientRect = jest.fn() .mockReturnValue({ left: 5, top: 5, }); const tooltipDirective = initTooltipMiniDirective( viewContainerRef, undefined, document, ); tooltipDirective.handleBeingOffScreen = jest.fn(); initTooltipMiniComponent(tooltipDirective); return { tooltipDirective, }; }; // tslint:disable-next-line test('Sets the components display to block', () => { setsBasicStyleValues( 'display', 'block', ); }); // tslint:disable-next-line test('Sets the components position to absolute', () => { setsBasicStyleValues( 'position', 'absolute', ); }); // tslint:disable-next-line test('Sets the components translate to pull it to the top and center', () => { setsBasicStyleValues( 'transform', 'translate(-50%, -100%)', ); }); // tslint:disable-next-line test('Sets the components left so its halfway across the elements left in relation to the body', () => { const { tooltipDirective, } = initUpdateTooltipLocationData(); tooltipDirective.updateTooltipLocation(); expect( tooltipDirective.tooltipMiniComponent .location.nativeElement.style.left, ).toBe('30px'); }); // tslint:disable-next-line test('Sets the components top so its equal to the elements top in relation to the bodies top', () => { const { tooltipDirective, } = initUpdateTooltipLocationData(); tooltipDirective.updateTooltipLocation(); expect( tooltipDirective.tooltipMiniComponent .location.nativeElement.style.top, ).toBe('5px'); }); test('It calls handleBeingOffScreen', () => { const { tooltipDirective, } = initUpdateTooltipLocationData(); tooltipDirective.updateTooltipLocation(); expect(tooltipDirective.handleBeingOffScreen) .toHaveBeenCalled(); }); }); describe('handleBeingOffScreen', () => { const initHandleBeingOffScreenData = () => { const document = { body: { offsetWidth: 10, }, } as Document; const tooltipDirective = initTooltipMiniDirective( undefined, undefined, document, ); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); return { tooltipDirective, }; }; test('Calls getBoundingClientRect on the element', () => { jest.useFakeTimers(); const { tooltipDirective, } = initHandleBeingOffScreenData(); tooltipDirective.handleBeingOffScreen(); jest.runAllTimers(); expect( tooltipDirective.tooltipMiniComponent.location.nativeElement .getBoundingClientRect, ).toHaveBeenCalled(); }); // tslint:disable-next-line test('Sets expandsToRight to true on the sub component if the tooltip is too far to the left', () => { jest.useFakeTimers(); const { tooltipDirective, } = initHandleBeingOffScreenData(); tooltipDirective.tooltipMiniComponent.location.nativeElement .getBoundingClientRect = jest.fn().mockReturnValue({ left: -1, right: 5, }); tooltipDirective.handleBeingOffScreen(); jest.runAllTimers(); expect(tooltipDirective.tooltipMiniComponent.instance.expandsToRight) .toBe(true); }); // tslint:disable-next-line test('Calls markForCheck the sub component if the tooltip is too far to the left', () => { jest.useFakeTimers(); const { tooltipDirective, } = initHandleBeingOffScreenData(); tooltipDirective.tooltipMiniComponent.location.nativeElement .getBoundingClientRect = jest.fn().mockReturnValue({ left: -1, right: 5, }); tooltipDirective.handleBeingOffScreen(); jest.runAllTimers(); expect( tooltipDirective.tooltipMiniComponent.instance .changeDetectorRef.markForCheck, ).toHaveBeenCalled(); }); // tslint:disable-next-line test('Sets expandsToLeft to true on the sub component if the tooltip is too far to the right', () => { jest.useFakeTimers(); const { tooltipDirective, } = initHandleBeingOffScreenData(); tooltipDirective.tooltipMiniComponent.location.nativeElement .getBoundingClientRect = jest.fn().mockReturnValue({ left: 5, right: 11, }); tooltipDirective.handleBeingOffScreen(); jest.runAllTimers(); expect(tooltipDirective.tooltipMiniComponent.instance.expandsToLeft) .toBe(true); }); // tslint:disable-next-line test('Calls markForCheck the sub component if the tooltip is too far to the right', () => { jest.useFakeTimers(); const { tooltipDirective, } = initHandleBeingOffScreenData(); tooltipDirective.tooltipMiniComponent.location.nativeElement .getBoundingClientRect = jest.fn().mockReturnValue({ left: 5, right: 11, }); tooltipDirective.handleBeingOffScreen(); jest.runAllTimers(); expect( tooltipDirective.tooltipMiniComponent.instance .changeDetectorRef.markForCheck, ).toHaveBeenCalled(); }); }); describe('changeTooltipVisibility', () => { // tslint:disable-next-line test('It calls updateTooltipLocation if visible is true', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); tooltipDirective.updateTooltipLocation = jest.fn(); tooltipDirective.changeTooltipVisibility(true); expect( tooltipDirective.updateTooltipLocation, ).toHaveBeenCalled(); }); // tslint:disable-next-line test('It does not call updateTooltipLocation if visible is false', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); tooltipDirective.updateTooltipLocation = jest.fn(); tooltipDirective.changeTooltipVisibility(false); expect( tooltipDirective.updateTooltipLocation, ).not.toHaveBeenCalled(); }); // tslint:disable-next-line test('It sets tooltipMiniComponent visible to the argument', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); tooltipDirective.tooltipMiniComponent.instance .visible = false; tooltipDirective.updateTooltipLocation = jest.fn(); tooltipDirective.changeTooltipVisibility(true); expect( tooltipDirective.tooltipMiniComponent.instance .visible, ).toBe(true); }); // tslint:disable-next-line test('It calls markForCheck on the tooltipMiniComponent changeDetectorRef', () => { const tooltipDirective = initTooltipMiniDirective(); initTooltipMiniComponent(tooltipDirective); initChangeDetector(tooltipDirective); tooltipDirective.updateTooltipLocation = jest.fn(); tooltipDirective.changeTooltipVisibility(true); expect( tooltipDirective.tooltipMiniComponent.instance .changeDetectorRef.markForCheck, ).toHaveBeenCalled(); }); }); describe('onHover', () => { const initOnHoverData = () => { const browserDetectorService = {} as BrowserDetectorService; browserDetectorService.isIOS = jest.fn().mockReturnValueOnce(false); const tooltipDirective = initTooltipMiniDirective( undefined, undefined, undefined, browserDetectorService, ); tooltipDirective.onClickTriggered = false; tooltipDirective.changeTooltipVisibility = jest.fn(); return { browserDetectorService, tooltipDirective, }; }; test('Calls browserDetectorService.isIOS', () => { const { browserDetectorService, tooltipDirective, } = initOnHoverData(); tooltipDirective.onHover(); expect(browserDetectorService.isIOS).toHaveBeenCalled(); }); // tslint:disable-next-line test('It calls changeTooltipVisibility with true if onClickTriggered is false and browserDetectorService.isIOS returns false', () => { const { tooltipDirective, } = initOnHoverData(); tooltipDirective.onHover(); expect( tooltipDirective.changeTooltipVisibility, ).toHaveBeenCalledWith(true); }); // tslint:disable-next-line test('It does not call changeTooltipVisibility if onClickTriggered is true and browserDetectorService.isIOS returns false', () => { const { tooltipDirective, } = initOnHoverData(); tooltipDirective.onClickTriggered = true; tooltipDirective.onHover(); expect(tooltipDirective.changeTooltipVisibility).not.toHaveBeenCalled(); }); // tslint:disable-next-line test('It does not call changeTooltipVisibility if onClickTriggered is false and browserDetectorService.isIOS returns true', () => { const { browserDetectorService, tooltipDirective, } = initOnHoverData(); browserDetectorService.isIOS = jest.fn().mockReturnValueOnce(true); tooltipDirective.onHover(); expect(tooltipDirective.changeTooltipVisibility).not.toHaveBeenCalled(); }); }); describe('onMouseOut', () => { // tslint:disable-next-line test('It calls changeTooltipVisibility with false if onClickTriggered is false', () => { const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.onClickTriggered = false; tooltipDirective.changeTooltipVisibility = jest.fn(); tooltipDirective.onMouseOut(); expect(tooltipDirective .changeTooltipVisibility, ).toHaveBeenCalledWith(false); }); // tslint:disable-next-line test('It does not call changeTooltipVisibility if onClickTriggered is true', () => { const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.onClickTriggered = true; tooltipDirective.changeTooltipVisibility = jest.fn(); tooltipDirective.onMouseOut(); expect(tooltipDirective .changeTooltipVisibility, ).not.toHaveBeenCalled(); }); }); describe('onClick', () => { // tslint:disable-next-line test('It calls changeTooltipVisibility with true', () => { const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.changeTooltipVisibility = jest.fn(); tooltipDirective.onClick(); expect( tooltipDirective.changeTooltipVisibility, ).toHaveBeenCalledWith(true); }); // tslint:disable-next-line test('It sets onClickTriggered to true', () => { const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.changeTooltipVisibility = jest.fn(); tooltipDirective.onClickTriggered = false; tooltipDirective.onClick(); expect( tooltipDirective.onClickTriggered, ).toBe(true); }); // tslint:disable-next-line test('It calls setTimeout with the onClickVisibleTime', () => { jest.useFakeTimers(); const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.changeTooltipVisibility = jest.fn(); tooltipDirective.onClickVisibleTime = 1; tooltipDirective.onClick(); expect(setTimeout.mock.calls[0][1]) .toBe(1); }); // tslint:disable-next-line test('It calls changeTooltipVisibility with false after the timer has run', () => { jest.useFakeTimers(); const tooltipDirective = initTooltipMiniDirective(); const changeVisiblityMock = jest.fn(); tooltipDirective.changeTooltipVisibility = changeVisiblityMock; tooltipDirective.onClick(); changeVisiblityMock.mockReset(); jest.runAllTimers(); expect( changeVisiblityMock, ).toHaveBeenCalledWith(false); }); // tslint:disable-next-line test('It sets onClickTriggered to false after the timer has run', () => { jest.useFakeTimers(); const tooltipDirective = initTooltipMiniDirective(); tooltipDirective.changeTooltipVisibility = jest.fn(); tooltipDirective.onClick(); tooltipDirective.onClickTriggered = true; jest.runAllTimers(); expect( tooltipDirective.onClickTriggered, ).toBe(false); }); });