import { Component, ElementRef, Input, NgModule, Type, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; import { Subject } from 'rxjs'; import createSpy = jasmine.createSpy; import { NbThemeModule } from '../../theme.module'; import { NbLayoutModule } from '../layout/layout.module'; import { NbAdjustment, NbPosition } from '../cdk/overlay/overlay-position'; import { NbDynamicOverlayHandler } from '../cdk/overlay/dynamic/dynamic-overlay-handler'; import { NbOverlayContent } from '../cdk/overlay/overlay-service'; import { NbRenderableContainer } from '../cdk/overlay/overlay-container'; import { NbTrigger } from '../cdk/overlay/overlay-trigger'; import { NbTooltipDirective } from './tooltip.directive'; import { NbTooltipModule } from './tooltip.module'; import { NbTooltipComponent } from './tooltip.component'; import { NbIconLibraries } from '../icon/icon-libraries'; import { NbOverlayConfig } from '../cdk/overlay/mapping'; @Component({ selector: 'nb-tooltip-default-test', template: ` `, }) export class NbTooltipDefaultTestComponent { @ViewChild('button') button: ElementRef; @ViewChild(NbTooltipDirective) tooltip: NbTooltipDirective; } @Component({ selector: 'nb-tooltip-bindings-test', template: ` `, }) export class NbTooltipBindingsTestComponent { @ViewChild(NbTooltipDirective) tooltip: NbTooltipDirective; @ViewChild('button') button: ElementRef; @Input() content: any = ''; @Input() status = 'primary'; @Input() icon = ''; @Input() trigger = NbTrigger.CLICK; @Input() position = NbPosition.TOP; @Input() adjustment = NbAdjustment.CLOCKWISE; tooltipClass = ''; } @Component({ selector: 'nb-tooltip-instance-test', template: ` Some Template `, }) export class NbTooltipInstanceTestComponent { @ViewChild(NbTooltipDirective) tooltip: NbTooltipDirective; @ViewChild('button') button: ElementRef; } const dynamicOverlayIsShow$ = new Subject(); const dynamicOverlay = { show() {}, hide() {}, toggle() {}, destroy() {}, isShown: dynamicOverlayIsShow$, }; export class NbDynamicOverlayHandlerMock { _componentType: Type; _host: ElementRef; _context: Object = {}; _content: NbOverlayContent; _trigger: NbTrigger = NbTrigger.NOOP; _position: NbPosition = NbPosition.TOP; _adjustment: NbAdjustment = NbAdjustment.NOOP; _offset: number; _overlayConfig: NbOverlayConfig = {}; constructor() { } host(host: ElementRef) { this._host = host; return this; } trigger(trigger: NbTrigger) { this._trigger = trigger; return this; } position(position: NbPosition) { this._position = position; return this; } adjustment(adjustment: NbAdjustment) { this._adjustment = adjustment; return this; } componentType(componentType: Type) { this._componentType = componentType; return this; } content(content: NbOverlayContent) { this._content = content; return this; } context(context: {}) { this._context = context; return this; } offset(offset: number) { this._offset = offset; return this; } overlayConfig(overlayConfig: NbOverlayConfig) { this._overlayConfig = overlayConfig; return this; } build() { return dynamicOverlay; } rebuild() { return dynamicOverlay; } connect() { } disconnect() { } destroy() { } } const TEST_COMPONENTS = [ NbTooltipDefaultTestComponent, NbTooltipBindingsTestComponent, NbTooltipInstanceTestComponent, ]; @NgModule({ imports: [NbLayoutModule, NbTooltipModule], exports: [...TEST_COMPONENTS], declarations: [...TEST_COMPONENTS], }) class PopoverTestModule { } describe('Directive: NbTooltipDirective', () => { const overlayHandler = new NbDynamicOverlayHandlerMock(); beforeEach(waitForAsync(() => { TestBed.resetTestingModule(); TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, RouterTestingModule.withRoutes([]), NbThemeModule.forRoot(), PopoverTestModule, ], }); const iconLibs: NbIconLibraries = TestBed.inject(NbIconLibraries); iconLibs.registerSvgPack('test', { 'some-icon': 'some-icon' }); iconLibs.setDefaultPack('test') })); describe('smoke ', () => { let fixture: ComponentFixture; afterEach(() => { fixture.destroy(); }); it('should render string', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); fixture.componentInstance.tooltip.show(); fixture.detectChanges(); const textContainer = fixture.nativeElement.querySelector('nb-tooltip .content span'); expect(textContainer.textContent).toContain('test'); }); it('should hide', () => fakeAsync(() => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); fixture.componentInstance.tooltip.show(); fixture.detectChanges(); const textContainer = fixture.nativeElement.querySelector('nb-tooltip .content span'); expect(textContainer.textContent).toContain('test'); fixture.componentInstance.tooltip.hide(); fixture.detectChanges(); tick(); // we need this tick for animations const tooltip = fixture.nativeElement.querySelector('nb-tooltip'); expect(tooltip).toBeNull(); })); it('should render different content', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); fixture.componentInstance.tooltip.show(); fixture.detectChanges(); fixture.componentInstance.content = 'new string'; fixture.detectChanges(); const textContainer = fixture.nativeElement.querySelector('nb-tooltip .content span'); expect(textContainer.textContent).toContain('test'); }); it('should display icon', () => { fixture = TestBed.createComponent(NbTooltipBindingsTestComponent); fixture.detectChanges(); fixture.componentInstance.icon = 'some-icon'; fixture.detectChanges(); fixture.componentInstance.tooltip.show(); fixture.detectChanges(); const iconContainer = fixture.nativeElement.querySelector('nb-tooltip .content nb-icon'); expect(iconContainer.textContent).toContain('some-icon'); }); it('should display status', () => { fixture = TestBed.createComponent(NbTooltipBindingsTestComponent); fixture.detectChanges(); fixture.componentInstance.status = 'danger'; fixture.detectChanges(); fixture.componentInstance.tooltip.show(); fixture.detectChanges(); const iconContainer = fixture.nativeElement.querySelector('nb-tooltip'); expect(iconContainer.className).toContain('status-danger'); }); it('should emit show state change event when shows up', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); const tooltip: NbTooltipDirective = fixture.componentInstance.tooltip; const stateChangeSpy = createSpy('stateChangeSpy'); tooltip.nbTooltipShowStateChange.subscribe(stateChangeSpy); tooltip.show(); fixture.detectChanges(); expect(stateChangeSpy).toHaveBeenCalledTimes(1); expect(stateChangeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ isShown: true })); }); it('should emit show state change event when hides', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); const tooltip: NbTooltipDirective = fixture.componentInstance.tooltip; tooltip.show(); fixture.detectChanges(); const stateChangeSpy = createSpy('stateChangeSpy'); tooltip.nbTooltipShowStateChange.subscribe(stateChangeSpy); tooltip.hide(); fixture.detectChanges(); expect(stateChangeSpy).toHaveBeenCalledTimes(1); expect(stateChangeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ isShown: false })); }); it('should set isShown to false when hidden', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); const tooltip: NbTooltipDirective = fixture.componentInstance.tooltip; expect(tooltip.isShown).toEqual(false); }); it('should set isShown to true when shown', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); const tooltip: NbTooltipDirective = fixture.componentInstance.tooltip; tooltip.show(); fixture.detectChanges(); expect(tooltip.isShown).toEqual(true); }); }); describe('mocked services', () => { beforeEach(waitForAsync(() => { TestBed.resetTestingModule(); TestBed.configureTestingModule({ imports: [ RouterTestingModule.withRoutes([]), NbThemeModule.forRoot(), PopoverTestModule, ], }) .overrideDirective(NbTooltipDirective, { set: { providers: [ { provide: NbDynamicOverlayHandler, useValue: overlayHandler }, ], }, }); })); describe('default tooltip', () => { let fixture: ComponentFixture; afterEach(() => { fixture.destroy(); }); it('should build', () => { const componentSpy = spyOn(overlayHandler, 'componentType').and.callThrough(); const hostSpy = spyOn(overlayHandler, 'host').and.callThrough(); const positionSpy = spyOn(overlayHandler, 'position').and.callThrough(); const triggerSpy = spyOn(overlayHandler, 'trigger').and.callThrough(); const adjustmentSpy = spyOn(overlayHandler, 'adjustment').and.callThrough(); const contentSpy = spyOn(overlayHandler, 'content').and.callThrough(); const contextSpy = spyOn(overlayHandler, 'context').and.callThrough(); const offsetSpy = spyOn(overlayHandler, 'offset').and.callThrough(); const buildSpy = spyOn(overlayHandler, 'build').and.callThrough(); const rebuildSpy = spyOn(overlayHandler, 'rebuild').and.callThrough(); fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); expect(componentSpy).toHaveBeenCalledTimes(1); expect(componentSpy).toHaveBeenCalledWith(NbTooltipComponent); expect(hostSpy).toHaveBeenCalledWith(fixture.componentInstance.button); expect(hostSpy).toHaveBeenCalledTimes(1); expect(offsetSpy).toHaveBeenCalledTimes(1); expect(offsetSpy).toHaveBeenCalledWith(8); expect(positionSpy).toHaveBeenCalledTimes(2); expect(positionSpy).toHaveBeenCalledWith(NbPosition.TOP); expect(triggerSpy).toHaveBeenCalledTimes(2); expect(triggerSpy).toHaveBeenCalledWith(NbTrigger.HINT); expect(adjustmentSpy).toHaveBeenCalledTimes(2); expect(adjustmentSpy).toHaveBeenCalledWith(NbAdjustment.CLOCKWISE); expect(contentSpy).toHaveBeenCalledTimes(2); expect(contentSpy).toHaveBeenCalledWith('test'); expect(contextSpy).toHaveBeenCalledTimes(2); expect(contextSpy).toHaveBeenCalledWith({}); expect(buildSpy).toHaveBeenCalledTimes(1); expect(rebuildSpy).toHaveBeenCalledTimes(1); }); it('should show/hide/toggle', () => { fixture = TestBed.createComponent(NbTooltipDefaultTestComponent); fixture.detectChanges(); const showSpy = spyOn(dynamicOverlay, 'show').and.callThrough(); const hideSpy = spyOn(dynamicOverlay, 'hide').and.callThrough(); const toggleSpy = spyOn(dynamicOverlay, 'toggle').and.callThrough(); fixture.componentInstance.tooltip.show(); fixture.detectChanges(); expect(showSpy).toHaveBeenCalledTimes(1); expect(hideSpy).toHaveBeenCalledTimes(0); expect(toggleSpy).toHaveBeenCalledTimes(0); fixture.componentInstance.tooltip.hide(); fixture.detectChanges(); expect(showSpy).toHaveBeenCalledTimes(1); expect(hideSpy).toHaveBeenCalledTimes(1); expect(toggleSpy).toHaveBeenCalledTimes(0); fixture.componentInstance.tooltip.toggle(); fixture.detectChanges(); expect(showSpy).toHaveBeenCalledTimes(1); expect(hideSpy).toHaveBeenCalledTimes(1); expect(toggleSpy).toHaveBeenCalledTimes(1); }); }); describe('binding tooltip', () => { let fixture: ComponentFixture; afterEach(() => { fixture.destroy(); }); it('should rebuild', () => { const componentSpy = spyOn(overlayHandler, 'componentType').and.callThrough(); const hostSpy = spyOn(overlayHandler, 'host').and.callThrough(); const positionSpy = spyOn(overlayHandler, 'position').and.callThrough(); const triggerSpy = spyOn(overlayHandler, 'trigger').and.callThrough(); const adjustmentSpy = spyOn(overlayHandler, 'adjustment').and.callThrough(); const contentSpy = spyOn(overlayHandler, 'content').and.callThrough(); const contextSpy = spyOn(overlayHandler, 'context').and.callThrough(); const offsetSpy = spyOn(overlayHandler, 'offset').and.callThrough(); const buildSpy = spyOn(overlayHandler, 'build').and.callThrough(); const rebuildSpy = spyOn(overlayHandler, 'rebuild').and.callThrough(); fixture = TestBed.createComponent(NbTooltipBindingsTestComponent); fixture.detectChanges(); fixture.componentInstance.adjustment = NbAdjustment.HORIZONTAL; fixture.componentInstance.trigger = NbTrigger.CLICK; fixture.componentInstance.content = 'new string'; fixture.componentInstance.status = 'success'; fixture.componentInstance.icon = 'home'; fixture.componentInstance.position = NbPosition.LEFT; fixture.detectChanges(); expect(componentSpy).toHaveBeenCalledTimes(1); expect(componentSpy).toHaveBeenCalledWith(NbTooltipComponent); expect(hostSpy).toHaveBeenCalledWith(fixture.componentInstance.button); expect(hostSpy).toHaveBeenCalledTimes(1); expect(offsetSpy).toHaveBeenCalledTimes(1); expect(offsetSpy).toHaveBeenCalledWith(8); expect(positionSpy).toHaveBeenCalledTimes(3); expect(positionSpy).toHaveBeenCalledWith(NbPosition.LEFT); expect(triggerSpy).toHaveBeenCalledTimes(3); expect(triggerSpy).toHaveBeenCalledWith(NbTrigger.CLICK); expect(adjustmentSpy).toHaveBeenCalledTimes(3); expect(adjustmentSpy).toHaveBeenCalledWith(NbAdjustment.HORIZONTAL); expect(contentSpy).toHaveBeenCalledTimes(3); expect(contentSpy).toHaveBeenCalledWith('new string'); expect(contextSpy).toHaveBeenCalledTimes(3); expect(contextSpy).toHaveBeenCalledWith({ status: 'success', icon: 'home' }); expect(buildSpy).toHaveBeenCalledTimes(1); expect(rebuildSpy).toHaveBeenCalledTimes(2); }); it('should accept different content', () => { const contentSpy = spyOn(overlayHandler, 'content').and.callThrough(); fixture = TestBed.createComponent(NbTooltipBindingsTestComponent); fixture.detectChanges(); fixture.componentInstance.content = 'new string'; fixture.detectChanges(); expect(contentSpy).toHaveBeenCalledTimes(3); expect(contentSpy).toHaveBeenCalledWith('new string'); }); it('should set overlay config', () => { const tooltipClass = 'custom-popover-class'; const overlayConfigSpy = spyOn(overlayHandler, 'overlayConfig').and.callThrough(); fixture = TestBed.createComponent(NbTooltipBindingsTestComponent); fixture.componentInstance.tooltipClass = tooltipClass; fixture.detectChanges(); expect(overlayConfigSpy).toHaveBeenCalledWith(jasmine.objectContaining({ panelClass: tooltipClass })); }); }); describe('instance tooltip', () => { let fixture: ComponentFixture; afterEach(() => { fixture.destroy(); }); it('should rebuild', () => { const componentSpy = spyOn(overlayHandler, 'componentType').and.callThrough(); const hostSpy = spyOn(overlayHandler, 'host').and.callThrough(); const positionSpy = spyOn(overlayHandler, 'position').and.callThrough(); const triggerSpy = spyOn(overlayHandler, 'trigger').and.callThrough(); const adjustmentSpy = spyOn(overlayHandler, 'adjustment').and.callThrough(); const contentSpy = spyOn(overlayHandler, 'content').and.callThrough(); const contextSpy = spyOn(overlayHandler, 'context').and.callThrough(); const offsetSpy = spyOn(overlayHandler, 'offset').and.callThrough(); const buildSpy = spyOn(overlayHandler, 'build').and.callThrough(); const rebuildSpy = spyOn(overlayHandler, 'rebuild').and.callThrough(); fixture = TestBed.createComponent(NbTooltipInstanceTestComponent); fixture.detectChanges(); fixture.componentInstance.tooltip.adjustment = NbAdjustment.HORIZONTAL; fixture.componentInstance.tooltip.trigger = NbTrigger.CLICK; fixture.componentInstance.tooltip.content = 'new string'; fixture.componentInstance.tooltip.status = 'success'; fixture.componentInstance.tooltip.icon = 'home'; fixture.componentInstance.tooltip.position = NbPosition.LEFT; fixture.componentInstance.tooltip.rebuild(); expect(componentSpy).toHaveBeenCalledTimes(1); expect(componentSpy).toHaveBeenCalledWith(NbTooltipComponent); expect(hostSpy).toHaveBeenCalledWith(fixture.componentInstance.button); expect(hostSpy).toHaveBeenCalledTimes(1); expect(positionSpy).toHaveBeenCalledTimes(3); expect(positionSpy).toHaveBeenCalledWith(NbPosition.LEFT); expect(triggerSpy).toHaveBeenCalledTimes(3); expect(triggerSpy).toHaveBeenCalledWith(NbTrigger.CLICK); expect(offsetSpy).toHaveBeenCalledTimes(1); expect(offsetSpy).toHaveBeenCalledWith(8); expect(adjustmentSpy).toHaveBeenCalledTimes(3); expect(adjustmentSpy).toHaveBeenCalledWith(NbAdjustment.HORIZONTAL); expect(contentSpy).toHaveBeenCalledTimes(3); expect(contentSpy).toHaveBeenCalledWith('new string'); expect(contextSpy).toHaveBeenCalledTimes(3); expect(contextSpy).toHaveBeenCalledWith({ status: 'success', icon: 'home' }); expect(buildSpy).toHaveBeenCalledTimes(1); expect(rebuildSpy).toHaveBeenCalledTimes(2); }); }); }); });