Files
clients/libs/components/src/tooltip/tooltip.spec.ts
Bryan Cunningham 963a9156fb [CL-910] Use tooltip in title directive (#17084)
* use tooltip in a11y directive

* remove commented code

* add deprecation warning to appA11yTitle directive

* use label for tooltip in carousel nav

* wait for timeout before assertion

* remove unnecessary title directive use

* fix private variable lint errors

* increase tooltip show delay

* fix spec delay and export as constant

* use delay constant

---------

Co-authored-by: Vicki League <vleague@bitwarden.com>
2025-12-01 11:59:20 -05:00

115 lines
3.8 KiB
TypeScript

import {
ConnectedOverlayPositionChange,
ConnectionPositionPair,
OverlayConfig,
Overlay,
} from "@angular/cdk/overlay";
import { ComponentPortal } from "@angular/cdk/portal";
import { Component } from "@angular/core";
import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { Observable, Subject } from "rxjs";
import { TooltipDirective, TOOLTIP_DELAY_MS } from "./tooltip.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
standalone: true,
imports: [TooltipDirective],
template: ` <button [bitTooltip]="tooltipText" type="button">Hover or focus me</button> `,
})
class TooltipHostComponent {
tooltipText = "Hello Tooltip";
}
/** Minimal strategy shape the directive expects */
interface StrategyLike {
withFlexibleDimensions: (flex: boolean) => StrategyLike;
withPush: (push: boolean) => StrategyLike;
withPositions: (positions: ReadonlyArray<ConnectionPositionPair>) => StrategyLike;
readonly positionChanges: Observable<ConnectedOverlayPositionChange>;
}
/** Minimal Overlay service shape */
interface OverlayLike {
position: () => { flexibleConnectedTo: (_: unknown) => StrategyLike };
create: (_: OverlayConfig) => OverlayRefStub;
scrollStrategies: { reposition: () => unknown };
}
interface OverlayRefStub {
attach: (portal: ComponentPortal<unknown>) => unknown;
updatePosition: () => void;
}
describe("TooltipDirective (visibility only)", () => {
let fixture: ComponentFixture<TooltipHostComponent>;
beforeEach(() => {
const positionChanges$ = new Subject<ConnectedOverlayPositionChange>();
const strategy: StrategyLike = {
withFlexibleDimensions: jest.fn(() => strategy),
withPush: jest.fn(() => strategy),
withPositions: jest.fn(() => strategy),
get positionChanges() {
return positionChanges$.asObservable();
},
};
const overlayRefStub: OverlayRefStub = {
attach: jest.fn(() => ({
changeDetectorRef: { detectChanges: jest.fn() },
location: {
nativeElement: {
querySelector: jest.fn().mockReturnValue({ id: "tip-123" }),
},
},
})),
updatePosition: jest.fn(),
};
const overlayMock: OverlayLike = {
position: () => ({ flexibleConnectedTo: () => strategy }),
create: (_: OverlayConfig) => overlayRefStub,
scrollStrategies: { reposition: () => ({}) },
};
TestBed.configureTestingModule({
imports: [TooltipHostComponent],
providers: [{ provide: Overlay, useValue: overlayMock as unknown as Overlay }],
});
fixture = TestBed.createComponent(TooltipHostComponent);
fixture.detectChanges();
});
function getDirective(): TooltipDirective {
const hostDE = fixture.debugElement.query(By.directive(TooltipDirective));
return hostDE.injector.get(TooltipDirective);
}
it("sets isVisible to true on mouseenter", fakeAsync(() => {
const button: HTMLButtonElement = fixture.debugElement.query(By.css("button")).nativeElement;
const directive = getDirective();
const isVisible = (directive as unknown as { isVisible: () => boolean }).isVisible;
button.dispatchEvent(new Event("mouseenter"));
tick(TOOLTIP_DELAY_MS);
expect(isVisible()).toBe(true);
}));
it("sets isVisible to true on focus", fakeAsync(() => {
const button: HTMLButtonElement = fixture.debugElement.query(By.css("button")).nativeElement;
const directive = getDirective();
const isVisible = (directive as unknown as { isVisible: () => boolean }).isVisible;
button.dispatchEvent(new Event("focus"));
tick(TOOLTIP_DELAY_MS);
expect(isVisible()).toBe(true);
}));
});