Skip to content

fix(material/tooltip): match panel to trigger in test harness #26779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/material/tooltip/testing/tooltip-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import {
ComponentHarness,
ComponentHarnessConstructor,
HarnessPredicate,
TestElement,
} from '@angular/cdk/testing';
import {TooltipHarnessFilters} from './tooltip-harness-filters';

/** Harness for interacting with a mat-tooltip in tests. */
export class MatTooltipHarness extends ComponentHarness {
static hostSelector = '.mat-mdc-tooltip-trigger';

private _optionalPanel = this.documentRootLocatorFactory().locatorForOptional('.mat-mdc-tooltip');
private _hiddenClass = 'mat-mdc-tooltip-hide';
private _disabledClass = 'mat-mdc-tooltip-disabled';
private _showAnimationName = 'mat-mdc-tooltip-show';
Expand Down Expand Up @@ -45,7 +45,7 @@ export class MatTooltipHarness extends ComponentHarness {
// element has ripples.
await host.dispatchEvent('touchstart', {changedTouches: []});
await host.hover();
const panel = await this._optionalPanel();
const panel = await this._getPanel();
await panel?.dispatchEvent('animationend', {animationName: this._showAnimationName});
}

Expand All @@ -57,13 +57,13 @@ export class MatTooltipHarness extends ComponentHarness {
// the tooltip binds different events depending on the device.
await host.dispatchEvent('touchend');
await host.mouseAway();
const panel = await this._optionalPanel();
const panel = await this._getPanel();
await panel?.dispatchEvent('animationend', {animationName: this._hideAnimationName});
}

/** Gets whether the tooltip is open. */
async isOpen(): Promise<boolean> {
const panel = await this._optionalPanel();
const panel = await this._getPanel();
return !!panel && !(await panel.hasClass(this._hiddenClass));
}

Expand All @@ -75,7 +75,14 @@ export class MatTooltipHarness extends ComponentHarness {

/** Gets a promise for the tooltip panel's text. */
async getTooltipText(): Promise<string> {
const panel = await this._optionalPanel();
const panel = await this._getPanel();
return panel ? panel.text() : '';
}

/** Gets the tooltip panel associated with the trigger. */
private async _getPanel(): Promise<TestElement | null> {
const host = await this.host();
const locatorFactory = this.documentRootLocatorFactory();
return locatorFactory.locatorForOptional(`#${await host.getAttribute('data-mat-tooltip')}`)();
}
}
9 changes: 9 additions & 0 deletions src/material/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ const MIN_VIEWPORT_TOOLTIP_THRESHOLD = 8;
const UNBOUNDED_ANCHOR_GAP = 8;
const MIN_HEIGHT = 24;
const MAX_WIDTH = 200;
let uniqueId = 0;

/**
* Directive that attaches a material design tooltip to the host element. Animates the showing and
Expand All @@ -184,6 +185,8 @@ const MAX_WIDTH = 200;
host: {
'class': 'mat-mdc-tooltip-trigger',
'[class.mat-mdc-tooltip-disabled]': 'disabled',
// Used by harnesses to match the trigger to its tooltip.
'[attr.data-mat-tooltip]': '_panelId',
},
standalone: true,
})
Expand Down Expand Up @@ -218,6 +221,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit {
private _currentPosition: TooltipPosition;
private readonly _cssClassPrefix: string = 'mat-mdc';
private _ariaDescriptionPending: boolean;
protected readonly _panelId = `mat-tooltip-panel-${uniqueId++}`;

/** Allows the user to define the position of the tooltip relative to the parent element */
@Input('matTooltipPosition')
Expand Down Expand Up @@ -467,6 +471,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit {
const instance = (this._tooltipInstance = overlayRef.attach(this._portal).instance);
instance._triggerElement = this._elementRef.nativeElement;
instance._mouseLeaveHideDelay = this._hideDelay;
instance._id = this._panelId;
instance
.afterHidden()
.pipe(takeUntil(this._destroyed))
Expand Down Expand Up @@ -946,6 +951,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit {
host: {
'(mouseleave)': '_handleMouseLeave($event)',
'aria-hidden': 'true',
'[id]': '_id',
},
standalone: true,
imports: [NgClass],
Expand Down Expand Up @@ -975,6 +981,9 @@ export class TooltipComponent implements OnDestroy {
/** Amount of milliseconds to delay the closing sequence. */
_mouseLeaveHideDelay: number;

/** Unique ID for the panel. Assigned by the trigger. */
_id: string | undefined;

/** Whether animations are currently disabled. */
private _animationsDisabled: boolean;

Expand Down
3 changes: 3 additions & 0 deletions tools/public_api_guard/material/tooltip.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export class MatTooltip implements OnDestroy, AfterViewInit {
ngOnDestroy(): void;
// (undocumented)
_overlayRef: OverlayRef | null;
// (undocumented)
protected readonly _panelId: string;
get position(): TooltipPosition;
set position(value: TooltipPosition);
get positionAtOrigin(): boolean;
Expand Down Expand Up @@ -150,6 +152,7 @@ export class TooltipComponent implements OnDestroy {
// (undocumented)
_handleMouseLeave({ relatedTarget }: MouseEvent): void;
hide(delay: number): void;
_id: string | undefined;
// (undocumented)
_isMultiline: boolean;
isVisible(): boolean;
Expand Down
Loading