/* * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den * Ministerpräsidenten des Landes Schleswig-Holstein * Staatskanzlei * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung * * Lizenziert unter der EUPL, Version 1.2 oder - sobald * diese von der Europäischen Kommission genehmigt wurden - * Folgeversionen der EUPL ("Lizenz"); * Sie dürfen dieses Werk ausschließlich gemäß * dieser Lizenz nutzen. * Eine Kopie der Lizenz finden Sie hier: * * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * * Sofern nicht durch anwendbare Rechtsvorschriften * gefordert oder in schriftlicher Form vereinbart, wird * die unter der Lizenz verbreitete Software "so wie sie * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - * ausdrücklich oder stillschweigend - verbreitet. * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { InteractivityChecker } from '@angular/cdk/a11y'; import { ComponentRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { TooltipComponent } from './tooltip.component'; import { TooltipDirective } from './tooltip.directive'; class MockElementRef extends ElementRef { nativeElement = { contains: jest.fn(), appendChild: jest.fn(), }; } describe('TooltipDirective', () => { let directive: TooltipDirective; const mockComponentRef: ComponentRef<TooltipComponent> = { setInput: jest.fn(), destroy: jest.fn(), onDestroy: jest.fn(), componentType: TooltipComponent, changeDetectorRef: null, location: null, hostView: null, injector: null, instance: { id: '', left: 0, top: 0, text: '', show: false }, }; beforeEach((): void => { TestBed.configureTestingModule({ providers: [ViewContainerRef, { provide: ElementRef, useClass: MockElementRef }, Renderer2, InteractivityChecker], }); TestBed.runInInjectionContext(() => { directive = new TooltipDirective(); }); }); it('should create a directive', () => { expect(directive).toBeTruthy(); }); describe('ngAfterViewInit', () => { it('should create tooltip', () => { directive.createTooltip = jest.fn(); directive.ngAfterViewInit(); expect(directive.createTooltip).toHaveBeenCalled(); }); }); describe('ngOnDestroy', () => { it('should destroy tooltip', () => { directive.destroy = jest.fn(); directive.ngOnDestroy(); expect(directive.destroy).toHaveBeenCalled(); }); }); describe('createTooltip', () => { beforeEach(() => { directive.viewContainerRef.createComponent = jest.fn().mockReturnValue({ location: { nativeElement: {} } }); directive.setAriaLabeledBy = jest.fn(); directive.getFocusableElement = jest.fn().mockReturnValue({ appendChild: jest.fn() }); directive.interactivityChecker.isFocusable = jest.fn(); }); it('should create tooltip component', () => { directive.createTooltip(); expect(directive.viewContainerRef.createComponent).toHaveBeenCalled(); }); it('should check if parent element focusable', () => { directive.createTooltip(); expect(directive.interactivityChecker.isFocusable).toHaveBeenCalled(); }); it('should get focusable element if parent not focusable', () => { directive.createTooltip(); expect(directive.getFocusableElement).toHaveBeenCalled(); }); it('should insert tooltip component to focusable', () => { directive.createTooltip(); expect(directive.focusableElement.appendChild).toHaveBeenCalled(); }); it('should set aria-labeledby attribute to parent', () => { directive.createTooltip(); expect(directive.setAriaLabeledBy).toHaveBeenCalled(); }); }); describe('showTooltip', () => { beforeEach(() => { directive.setTooltipProperties = jest.fn(); directive.elementRef.nativeElement.contains = jest.fn().mockReturnValue(true); }); it('should check if element focused', () => { directive.showTooltip(); expect(directive.elementRef.nativeElement.contains).toHaveBeenCalled(); }); it('should set tooltip properties', () => { directive.showTooltip(); expect(directive.setTooltipProperties).toHaveBeenCalledWith(true); }); }); describe('hideTooltip', () => { it('should hide tooltip', () => { directive.hide = jest.fn(); directive.hideTooltip(); expect(directive.hide).toHaveBeenCalled(); }); }); describe('onKeydown', () => { it('should hide tooltip if escape key pressed', () => { directive.hide = jest.fn(); const escapeEvent: KeyboardEvent = { ...new KeyboardEvent('esc'), key: 'Escape' }; directive.onKeydown(escapeEvent); expect(directive.hide).toHaveBeenCalled(); }); }); describe('setTooltipProperties', () => { beforeEach(() => { directive.componentRef = mockComponentRef; directive.elementRef.nativeElement.getBoundingClientRect = jest .fn() .mockReturnValue({ left: 0, right: 1000, bottom: 1000 }); }); it('should get bounding client rect', () => { directive.setTooltipProperties(); expect(directive.elementRef.nativeElement.getBoundingClientRect).toHaveBeenCalled(); }); it('should set tooltip instance properties', () => { directive.tooltip = 'I am tooltip'; directive.tooltipId = 'tooltip-1'; directive.setTooltipProperties(); expect(directive.componentRef.instance).toStrictEqual({ id: 'tooltip-1', left: 500, text: 'I am tooltip', top: 1000, show: true, }); }); it('should add margin if parent element focused', () => { directive.setTooltipProperties(true); expect(directive.componentRef.instance.top).toBe(1004); }); }); describe('setAriaLabeledBy', () => { beforeEach(() => { directive.renderer.setAttribute = jest.fn(); }); it('should set aria-labeledby attribute', () => { directive.setAriaLabeledBy(); expect(directive.renderer.setAttribute).toHaveBeenCalled(); }); }); describe('removeAriaLabeledBy', () => { beforeEach(() => { directive.renderer.removeAttribute = jest.fn(); }); it('should remove aria-labeledby attribute', () => { directive.removeAriaLabeledBy(); expect(directive.renderer.removeAttribute).toHaveBeenCalled(); }); }); describe('getFocusableElement', () => { it('should return null', () => { const simpleElement = document.createElement('a'); const result: HTMLElement = directive.getFocusableElement(simpleElement); expect(result).toBeNull(); }); it('should return focusable child element', () => { const nestedElement = document.createElement('div'); const buttonElement = document.createElement('button'); nestedElement.appendChild(buttonElement); const result: HTMLElement = directive.getFocusableElement(nestedElement); expect(result).toBe(buttonElement); }); }); describe('hide', () => { beforeEach(() => { directive.componentRef = Object.assign(mockComponentRef, { instance: { ...mockComponentRef.instance, show: true } }); }); it('should hide component', () => { directive.hide(); expect(directive.componentRef.instance.show).toBeFalsy; }); }); describe('destroy', () => { beforeEach(() => { directive.componentRef = mockComponentRef; directive.removeAriaLabeledBy = jest.fn(); }); it('should set component ref to null', () => { directive.destroy(); expect(directive.componentRef).toBeNull(); }); it('should remove aria-labeledby attribute', () => { directive.destroy(); expect(directive.removeAriaLabeledBy).toHaveBeenCalled(); }); it('should set focusable element to null', () => { directive.destroy(); expect(directive.focusableElement).toBeNull(); }); }); });