diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts index 671af957965555f680862dad37081cc00c537c9d..f62b0e92488cc33d05bbc61112556850a74766e9 100644 --- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts +++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts @@ -29,6 +29,7 @@ import { TooltipPosition } from './tooltip.directive'; selector: 'ods-tooltip', imports: [NgClass], template: `<span + [attr.data-test-id]="dataTestId" class="tooltip fixed z-[100] animate-fadeIn cursor-default break-words rounded bg-ozggray-900 px-3 py-2 text-sm font-normal text-whitetext before:absolute before:border-l-[0.5rem] before:border-r-[0.5rem] before:border-l-transparent before:border-r-transparent dark:bg-white" [ngClass]="class" [class.visible]="show" @@ -58,6 +59,8 @@ export class TooltipComponent { class: string; leftOffset: number; + dataTestId: string; + set position(value: TooltipPosition) { if (value === TooltipPosition.ABOVE) { this.class = diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts index 76c569e4245841930a5387dc5c8a2e34e6328c1b..3b775dd56d43e4247a3de4cf06fe0a3e4d64bc76 100644 --- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts +++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts @@ -21,6 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { assignValue, mock, useFromMock } from '@alfa-client/test-utils'; import { InteractivityChecker } from '@angular/cdk/a11y'; import { ComponentRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core'; import { fakeAsync, TestBed, tick } from '@angular/core/testing'; @@ -37,6 +38,18 @@ class MockElementRef extends ElementRef { describe('TooltipDirective', () => { let directive: TooltipDirective; + const mockComponentRefInstance: TooltipComponent = { + id: '', + left: 0, + top: 0, + text: '', + show: false, + position: TooltipPosition.BELOW, + class: '', + leftOffset: 0, + width: null, + dataTestId: undefined, + }; const mockComponentRef: ComponentRef<TooltipComponent> = { setInput: jest.fn(), destroy: jest.fn(), @@ -46,17 +59,7 @@ describe('TooltipDirective', () => { location: null, hostView: null, injector: null, - instance: { - id: '', - left: 0, - top: 0, - text: '', - show: false, - position: TooltipPosition.BELOW, - class: '', - leftOffset: 0, - width: null, - }, + instance: mockComponentRefInstance, }; const parentRect: DOMRect = { bottom: 0, top: 0, height: 0, left: 0, right: 0, toJSON: jest.fn(), width: 0, x: 0, y: 0 }; @@ -119,6 +122,7 @@ describe('TooltipDirective', () => { directive.setInitialTooltipProperties = jest.fn(); directive.getParentElement = jest.fn().mockReturnValue({ appendChild: jest.fn() }); directive.interactivityChecker.isFocusable = jest.fn(); + directive._addDataTestId = jest.fn(); }); it('should create tooltip component', () => { @@ -156,6 +160,43 @@ describe('TooltipDirective', () => { expect(directive.getParentElement).not.toHaveBeenCalled(); }); + + it('should call add data test id', () => { + directive.createTooltip(tooltipText); + + expect(directive._addDataTestId).toHaveBeenCalled(); + }); + }); + + describe('add data test id', () => { + const dataTestId: string = 'dummyDataTestId'; + + beforeEach(() => { + directive.componentRef = assignValue(mockComponentRef, 'instance', { ...mockComponentRef.instance, dataTestId: undefined }); + }); + + it('should set attribute to tooltip component if exists', () => { + directive.parentElement = mockParentAttribute(dataTestId); + + directive._addDataTestId(); + + expect(directive.componentRef.instance.dataTestId).toBe(dataTestId + directive.dataTestIdTooltipSuffix); + }); + + it('should NOT set attribute to tooltip component if undefined', () => { + directive.parentElement = mockParentAttribute(undefined); + + directive._addDataTestId(); + + expect(directive.componentRef.instance.dataTestId).toBeUndefined(); + }); + + function mockParentAttribute(value: any): HTMLElement { + return useFromMock<HTMLElement>({ + ...mock(HTMLElement), + getAttribute: jest.fn().mockReturnValue(value), + }); + } }); describe('showTooltip', () => { diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts index d8f42d4ab8dd4e8bdab6e49031a00fbbbddbb480..10cca117f0ab929c71c43dc0a33482a57a5c19de 100644 --- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts +++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { isEscapeKey, isNotNull } from '@alfa-client/tech-shared'; +import { isEscapeKey, isNotNull, isNotUndefined } from '@alfa-client/tech-shared'; import { InteractivityChecker } from '@angular/cdk/a11y'; import { ComponentRef, @@ -80,6 +80,10 @@ export class TooltipDirective implements OnDestroy { public readonly renderer: Renderer2 = inject(Renderer2); public readonly interactivityChecker: InteractivityChecker = inject(InteractivityChecker); + dataTestIdParentAttribute: string = 'data-test-id'; + dataTestIdAttribute: string = 'dataTestId'; + dataTestIdTooltipSuffix: string = '-tooltip'; + ngOnDestroy(): void { this.destroy(); } @@ -120,12 +124,18 @@ export class TooltipDirective implements OnDestroy { const nativeElement: HTMLElement = this.elementRef.nativeElement; this.componentRef = this.viewContainerRef.createComponent(TooltipComponent); this.parentElement = this.getParentElement(nativeElement); + this._addDataTestId(); this.parentElement.appendChild(this.componentRef.location.nativeElement); this.tooltipId = uniqueId('tooltip'); this.setInitialTooltipProperties(tooltipText, this.tooltipId); this.setAriaAttribute(this.tooltipAriaType); } + _addDataTestId(): void { + const dataTestId: string = this.parentElement.getAttribute(this.dataTestIdParentAttribute); + if (isNotUndefined(dataTestId)) this.componentRef.instance.dataTestId = dataTestId + this.dataTestIdTooltipSuffix; + } + setInitialTooltipProperties(text: string, id: string) { this.componentRef.instance.text = text; this.componentRef.instance.id = id;