diff --git a/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts index 7cf7de163ef2166b97814f4151a4d787bcc6c894..673ea2c47571873cc69795547f6dc5359609e99a 100644 --- a/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts +++ b/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts @@ -100,11 +100,11 @@ export class BenutzerE2EComponent { private readonly userBenutzername: string = 'Benutzername-text-input'; private readonly userMail: string = 'E-Mail-text-input'; - private readonly adminCheckbox: string = 'Admin-checkbox-editor'; - private readonly loeschenCheckbox: string = 'Loschen-checkbox-editor'; - private readonly userCheckbox: string = 'User-checkbox-editor'; - private readonly postCheckbox: string = 'Poststelle-checkbox-editor'; - private readonly datenbeauftragungCheckbox: string = 'Datenbeauftragung-checkbox-editor'; + private readonly adminCheckboxLabel: string = 'Admin'; + private readonly loeschenCheckboxLabel: string = 'Löschen'; + private readonly userCheckboxLabel: string = 'User'; + private readonly postCheckboxLabel: string = 'Poststelle'; + private readonly datenbeauftragungLabel: string = 'Datenbeauftragung'; private readonly organisationsEinheitCheckboxSuffix: string = '-checkbox-editor'; @@ -135,24 +135,24 @@ export class BenutzerE2EComponent { return cy.getTestElement(this.userMail); } - public getAdminCheckbox(): Cypress.Chainable<Element> { - return cy.getTestElement(this.adminCheckbox); + public getAdminCheckbox(): BenutzerCheckboxE2EComponent { + return new BenutzerCheckboxE2EComponent(this.adminCheckboxLabel); } - public getLoeschenCheckbox(): Cypress.Chainable<Element> { - return cy.getTestElement(this.loeschenCheckbox); + public getLoeschenCheckbox(): BenutzerCheckboxE2EComponent { + return new BenutzerCheckboxE2EComponent(this.loeschenCheckboxLabel); } - public getUserCheckbox(): Cypress.Chainable<Element> { - return cy.getTestElement(this.userCheckbox); + public getUserCheckbox(): BenutzerCheckboxE2EComponent { + return new BenutzerCheckboxE2EComponent(this.userCheckboxLabel); } - public getPostCheckbox(): Cypress.Chainable<Element> { - return cy.getTestElement(this.postCheckbox); + public getPostCheckbox(): BenutzerCheckboxE2EComponent { + return new BenutzerCheckboxE2EComponent(this.postCheckboxLabel); } - public getDatenbeauftragungCheckbox(): Cypress.Chainable<Element> { - return cy.getTestElement(this.datenbeauftragungCheckbox); + public getDatenbeauftragungCheckbox(): BenutzerCheckboxE2EComponent { + return new BenutzerCheckboxE2EComponent(this.datenbeauftragungLabel); } public getOrganisationsEinheitCheckbox(einheit: string): Cypress.Chainable<Element> { @@ -180,3 +180,29 @@ export class BenutzerDeleteDialogE2EComponent { return cy.getTestElement(this.deleteButton); } } + +export class BenutzerCheckboxE2EComponent { + private rootPrefix: string; + private prefix: string; + + private readonly adminCheckbox: string = '-checkbox-editor'; + private readonly adminInfoButtonSuffix: string = '-role-info-button'; + private readonly adminInfoButtonTooltipSuffix: string = '-role-info-button-tooltip'; + + constructor(label: string) { + this.rootPrefix = convertToDataTestId(label); + this.prefix = convertToDataTestId(label.toLocaleLowerCase()); + } + + public getRoot(): Cypress.Chainable<Element> { + return cy.getTestElement(`${this.rootPrefix}${this.adminCheckbox}`); + } + + public getInfoButton(): Cypress.Chainable<Element> { + return cy.getTestElement(`${this.prefix}${this.adminInfoButtonSuffix}`); + } + + public getInfoButtonTooltip(): Cypress.Chainable<Element> { + return cy.getTestElement(`${this.prefix}${this.adminInfoButtonTooltipSuffix}`); + } +} diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts index 0d4a3c538f90b3621783a7f8ccc750429823434f..e2cbf35c6a1488905f98fa26df189a6fe1425ccd 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts @@ -57,4 +57,9 @@ describe('Benutzer anlegen', () => { it('should show created user in list', () => { benutzerVerifier.verifyUserInList(newUser); }); + + it('should remove benutzer', () => { + benutzerHelper.deleteBenutzer(newUser.username); + benutzerVerifier.verifyUserNotInList(newUser.username); + }); }); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts index f39ed75f138024cdb3f0273716714e75134aade1..205d661f91365f4bea89867b41ae673a7f1e2c4a 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts @@ -21,15 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BenutzerE2EComponent, BenutzerListE2EComponent, BenutzerListItemE2EComponent, } from 'apps/admin-e2e/src/components/benutzer/benutzer.e2e.component'; import { E2EBenutzerHelper } from 'apps/admin-e2e/src/helper/benutzer/benutzer.helper'; import { OrganisationsEinheitE2E } from 'apps/admin-e2e/src/model/organisations-einheit'; -import { - BenutzerE2EComponent, - BenutzerListE2EComponent, - BenutzerListItemE2EComponent, -} from '../../../components/benutzer/benutzer.e2e.component'; -import { beChecked, beEnabled, contains, exist, notBeChecked, notBeEnabled } from '../../../support/cypress.util'; -import { AlfaRollen, AlfaUsers, loginAsAriane } from '../../../support/user-util'; +import { beChecked, beEnabled, contains, exist, mouseEnter, notBeChecked, notBeEnabled, visible, } from 'apps/admin-e2e/src/support/cypress.util'; +import { AlfaRollen, AlfaUsers, loginAsAriane } from 'apps/admin-e2e/src/support/user-util'; describe('Benutzer und Rollen', () => { const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); @@ -79,58 +75,90 @@ describe('Benutzer und Rollen', () => { it('should show checkbox for each role', () => { helper.openNewBenutzerPage(); - notBeChecked(benutzerPage.getAdminCheckbox()); - notBeChecked(benutzerPage.getDatenbeauftragungCheckbox()); - notBeChecked(benutzerPage.getLoeschenCheckbox()); - notBeChecked(benutzerPage.getUserCheckbox()); - notBeChecked(benutzerPage.getPostCheckbox()); + notBeChecked(benutzerPage.getAdminCheckbox().getRoot()); + notBeChecked(benutzerPage.getDatenbeauftragungCheckbox().getRoot()); + notBeChecked(benutzerPage.getLoeschenCheckbox().getRoot()); + notBeChecked(benutzerPage.getUserCheckbox().getRoot()); + notBeChecked(benutzerPage.getPostCheckbox().getRoot()); }); it('should deactivate other alfa roles if "loeschen" role is selected', () => { - benutzerPage.getLoeschenCheckbox().click(); - beChecked(benutzerPage.getLoeschenCheckbox()); - notBeEnabled(benutzerPage.getUserCheckbox()); - notBeEnabled(benutzerPage.getPostCheckbox()); - - benutzerPage.getLoeschenCheckbox().click(); - notBeChecked(benutzerPage.getLoeschenCheckbox()); - beEnabled(benutzerPage.getUserCheckbox()); - beEnabled(benutzerPage.getPostCheckbox()); + benutzerPage.getLoeschenCheckbox().getRoot().click(); + beChecked(benutzerPage.getLoeschenCheckbox().getRoot()); + notBeEnabled(benutzerPage.getUserCheckbox().getRoot()); + notBeEnabled(benutzerPage.getPostCheckbox().getRoot()); + + benutzerPage.getLoeschenCheckbox().getRoot().click(); + notBeChecked(benutzerPage.getLoeschenCheckbox().getRoot()); + beEnabled(benutzerPage.getUserCheckbox().getRoot()); + beEnabled(benutzerPage.getPostCheckbox().getRoot()); }); it('should deactivate other alfa roles if "user" role is selected', () => { - benutzerPage.getUserCheckbox().click(); - beChecked(benutzerPage.getUserCheckbox()); - notBeEnabled(benutzerPage.getLoeschenCheckbox()); - notBeEnabled(benutzerPage.getPostCheckbox()); - - benutzerPage.getUserCheckbox().click(); - notBeChecked(benutzerPage.getUserCheckbox()); - beEnabled(benutzerPage.getLoeschenCheckbox()); - beEnabled(benutzerPage.getPostCheckbox()); + benutzerPage.getUserCheckbox().getRoot().click(); + beChecked(benutzerPage.getUserCheckbox().getRoot()); + notBeEnabled(benutzerPage.getLoeschenCheckbox().getRoot()); + notBeEnabled(benutzerPage.getPostCheckbox().getRoot()); + + benutzerPage.getUserCheckbox().getRoot().click(); + notBeChecked(benutzerPage.getUserCheckbox().getRoot()); + beEnabled(benutzerPage.getLoeschenCheckbox().getRoot()); + beEnabled(benutzerPage.getPostCheckbox().getRoot()); }); it('should deactivate other alfa roles if "poststelle" role is selected', () => { - benutzerPage.getPostCheckbox().click(); - beChecked(benutzerPage.getPostCheckbox()); - notBeEnabled(benutzerPage.getLoeschenCheckbox()); - notBeEnabled(benutzerPage.getUserCheckbox()); - - benutzerPage.getPostCheckbox().click(); - notBeChecked(benutzerPage.getPostCheckbox()); - beEnabled(benutzerPage.getLoeschenCheckbox()); - beEnabled(benutzerPage.getUserCheckbox()); + benutzerPage.getPostCheckbox().getRoot().click(); + beChecked(benutzerPage.getPostCheckbox().getRoot()); + notBeEnabled(benutzerPage.getLoeschenCheckbox().getRoot()); + notBeEnabled(benutzerPage.getUserCheckbox().getRoot()); + + benutzerPage.getPostCheckbox().getRoot().click(); + notBeChecked(benutzerPage.getPostCheckbox().getRoot()); + beEnabled(benutzerPage.getLoeschenCheckbox().getRoot()); + beEnabled(benutzerPage.getUserCheckbox().getRoot()); }); it('should activate and deactivate admin roles', () => { - benutzerPage.getAdminCheckbox().click(); - benutzerPage.getDatenbeauftragungCheckbox().click(); - beChecked(benutzerPage.getAdminCheckbox()); - beChecked(benutzerPage.getDatenbeauftragungCheckbox()); - - benutzerPage.getAdminCheckbox().click(); - benutzerPage.getDatenbeauftragungCheckbox().click(); - notBeChecked(benutzerPage.getAdminCheckbox()); - notBeChecked(benutzerPage.getDatenbeauftragungCheckbox()); + benutzerPage.getAdminCheckbox().getRoot().click(); + benutzerPage.getDatenbeauftragungCheckbox().getRoot().click(); + beChecked(benutzerPage.getAdminCheckbox().getRoot()); + beChecked(benutzerPage.getDatenbeauftragungCheckbox().getRoot()); + + benutzerPage.getAdminCheckbox().getRoot().click(); + benutzerPage.getDatenbeauftragungCheckbox().getRoot().click(); + notBeChecked(benutzerPage.getAdminCheckbox().getRoot()); + notBeChecked(benutzerPage.getDatenbeauftragungCheckbox().getRoot()); + }); + + describe('hint text', () => { + it('should be visible on admin role mouse hover', () => { + mouseEnter(benutzerPage.getAdminCheckbox().getInfoButton()); + + visible(benutzerPage.getAdminCheckbox().getInfoButtonTooltip()); + }); + + it('should be visible on loeschen role mouse hover', () => { + mouseEnter(benutzerPage.getLoeschenCheckbox().getInfoButton()); + + visible(benutzerPage.getLoeschenCheckbox().getInfoButtonTooltip()); + }); + + it('should be visible on user role mouse hover', () => { + mouseEnter(benutzerPage.getUserCheckbox().getInfoButton()); + + visible(benutzerPage.getUserCheckbox().getInfoButtonTooltip()); + }); + + it('should be visible on poststellt role mouse hover', () => { + mouseEnter(benutzerPage.getPostCheckbox().getInfoButton()); + + visible(benutzerPage.getPostCheckbox().getInfoButtonTooltip()); + }); + + it('should be visible on datenbeauftragung role mouse hover', () => { + mouseEnter(benutzerPage.getDatenbeauftragungCheckbox().getInfoButton()); + + visible(benutzerPage.getDatenbeauftragungCheckbox().getInfoButtonTooltip()); + }); }); }); diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts index 320db78e13e0fee0cae8dad0cd94969ad7b0e2de..f0ed339c63bbb596e72915d346b97c8390bf35c1 100644 --- a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts @@ -21,16 +21,16 @@ export class E2EBenutzerExecutor { this.benutzerPage.getMailInput().type(user.email); if (user.isAdmin) { - this.benutzerPage.getAdminCheckbox().click(); + this.benutzerPage.getAdminCheckbox().getRoot().click(); } if (user.isUser) { - this.benutzerPage.getUserCheckbox().click(); + this.benutzerPage.getUserCheckbox().getRoot().click(); } if (user.isLoeschen) { - this.benutzerPage.getLoeschenCheckbox().click(); + this.benutzerPage.getLoeschenCheckbox().getRoot().click(); } if (user.isPoststelle) { - this.benutzerPage.getPostCheckbox().click(); + this.benutzerPage.getPostCheckbox().getRoot().click(); } this.modifyOrganisationsEinheiten(user.organisationseinheiten); diff --git a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts index 498a30cf734696be13b3b2e999edc4df176fc74b..63f3c24872ebea08644aa85eead331dac07f1b40 100644 --- a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts +++ b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts @@ -60,10 +60,6 @@ export function mouseEnter(element: Cypress.Chainable<Element>): void { element.trigger('mouseenter'); } -export function mouseOver(element: Cypress.Chainable<Element>): void { - element.trigger('mouseover'); -} - export function contains(element: Cypress.Chainable<Element>, containing: string): void { element.should('exist').contains(containing); } diff --git a/alfa-client/apps/admin-e2e/src/support/tech-util.ts b/alfa-client/apps/admin-e2e/src/support/tech-util.ts index a1bbcb74ae2b53c9fc3fc05bbcab81896c4e183e..6e6c57d156a011e83fe53bee52ad26a56a384ad2 100644 --- a/alfa-client/apps/admin-e2e/src/support/tech-util.ts +++ b/alfa-client/apps/admin-e2e/src/support/tech-util.ts @@ -10,6 +10,6 @@ export function replaceAllWhitespaces(value: string, replaceWith: string): strin return value.replace(/ /g, replaceWith); } -export function simpleTransliteration(value: string) { +export function simpleTransliteration(value: string): string { return value.normalize('NFKD').replace(/[^-A-Za-z0-9_]/g, ''); } diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html index 63a4d3fc44e4f6b0b4c3590cc8e63c43e3073eb9..a8931fbcb6be03bbd9b0a5c97b7194e2e9605453 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html @@ -6,7 +6,8 @@ <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.ADMIN" label="Admin" inputId="admin" /> <button - tooltip='Wird nur in Kombination mit "User" verwendet. Diese Rolle kann Funktionen in Keycloak und der Administration konfigurieren, z.B. Benutzer anlegen, Gruppen erstellen bzw. Organisationseinheiten hinzufügen und Rollen zuweisen.' + data-test-id="admin-role-info-button" + tooltip="Diese Rolle kann Funktionen der OZG-Cloud konfigurieren, z.B. Benutzer anlegen, Organisationseinheiten hinzufügen und Rollen zuweisen." > <ods-info-icon /> </button> @@ -17,9 +18,12 @@ label="Datenbeauftragung" inputId="datenbeauftragung" /> - <ods-info-icon + <button + data-test-id="datenbeauftragung-role-info-button" tooltip='Diese Rolle kann in der Administration unter dem Menüpunkt "Statistik" Felder zur Auswertung konfigurieren. Sie ist mit allen anderen Rollen kompatibel.' - /> + > + <ods-info-icon /> + </button> </div> </div> <div [formGroupName]="UserFormService.ALFA_GROUP" class="flex flex-col gap-2"> @@ -27,7 +31,8 @@ <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.LOESCHEN" label="Löschen" inputId="delete" /> <button - tooltip='Diese Rolle hat dieselben Rechte wie die Rolle "User". Zusätzlich kann "Löschen" ausgewählte Vorgänge aus Alfa löschen. Diese Rolle sollten zwei Benutzer haben, da das Löschen einem Vieraugen-Prinzip folgt.' + data-test-id="loschen-role-info-button" + tooltip='Diese Rolle hat dieselben Rechte wie die Rolle "User". Zusätzlich kann "Löschen" Löschanträge aus Alfa bestätigen. ' > <ods-info-icon /> </button> @@ -35,16 +40,15 @@ <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.USER" label="User" inputId="user" /> <button - tooltip='Diese Rolle kann alle Vorgänge sehen und bearbeiten, wenn diese seiner Organisationseinheit zugewiesen sind. Ist kompatibel mit "Löschen" und "Admin".' + data-test-id="user-role-info-button" + tooltip="Diese Rolle kann alle Vorgänge sehen und bearbeiten, wenn diese seiner Organisationseinheit zugewiesen sind." > <ods-info-icon /> </button> </div> <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.POSTSTELLE" label="Poststelle" inputId="post_office" /> - <button - tooltip='Diese Rolle kann ausschließlich alle neu eingegangenen Vorgänge sehen und anderen Benutzern zuweisen. Sie sollte nur einem Benutzer zugewiesen sein. Dieser sollte keine weiteren Rollen besitzen. (Sie ist aber kompatibel mit der "Admin")' - > + <button data-test-id="poststelle-role-info-button" tooltip="Diese Rolle kann alle neu eingegangenen Vorgänge sehen."> <ods-info-icon /> </button> </div> 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; diff --git a/alfa-client/libs/test-utils/src/lib/mocking.ts b/alfa-client/libs/test-utils/src/lib/mocking.ts index 20ac6152a4230849892a5f6e5599670b24e05165..d42ae2de44f2a37bec9daeed0388f20812b04364 100644 --- a/alfa-client/libs/test-utils/src/lib/mocking.ts +++ b/alfa-client/libs/test-utils/src/lib/mocking.ts @@ -59,3 +59,7 @@ export function mockWindowError(): any { window.onerror = errorHandler; return errorHandler; } + +export function assignValue<T>(object: any, attributeName: string, toAssignValue: any): T { + return Object.assign(object, { [attributeName]: toAssignValue }); +}