Skip to content

Commit b959014

Browse files
crisbetojelbourn
authored andcommitted
chore(tooltip): unit test failures (#8385)
* Fixes a regression in the tooltip that was introduced by 0719c38 which caused the tests to fail. * Avoids issues in the future where failures in some tooltip tests can cause Jasmine to throw the browser into an infinite loop by trying to stringify a circular object.
1 parent 33edff5 commit b959014

File tree

2 files changed

+29
-20
lines changed

2 files changed

+29
-20
lines changed

src/lib/tooltip/tooltip.spec.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ describe('MatTooltip', () => {
5353
return {getContainerElement: () => overlayContainerElement};
5454
}},
5555
{provide: Directionality, useFactory: () => {
56-
return dir = { value: 'ltr' };
56+
return dir = {value: 'ltr'};
5757
}}
5858
]
5959
});
@@ -80,7 +80,7 @@ describe('MatTooltip', () => {
8080
});
8181

8282
it('should show and hide the tooltip', fakeAsync(() => {
83-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
83+
assertTooltipInstance(tooltipDirective, false);
8484

8585
tooltipDirective.show();
8686
tick(0); // Tick for the show delay (default is 0)
@@ -110,7 +110,7 @@ describe('MatTooltip', () => {
110110

111111
// On animation complete, should expect that the tooltip has been detached.
112112
flushMicrotasks();
113-
expect(tooltipDirective._tooltipInstance).toBeNull();
113+
assertTooltipInstance(tooltipDirective, false);
114114
}));
115115

116116
it('should be able to re-open a tooltip if it was closed by detaching the overlay',
@@ -126,15 +126,15 @@ describe('MatTooltip', () => {
126126
fixture.detectChanges();
127127
expect(tooltipDirective._isTooltipVisible()).toBe(false);
128128
flushMicrotasks();
129-
expect(tooltipDirective._tooltipInstance).toBeNull();
129+
assertTooltipInstance(tooltipDirective, false);
130130

131131
tooltipDirective.show();
132132
tick(0);
133133
expect(tooltipDirective._isTooltipVisible()).toBe(true);
134134
}));
135135

136136
it('should show with delay', fakeAsync(() => {
137-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
137+
assertTooltipInstance(tooltipDirective, false);
138138

139139
const tooltipDelay = 1000;
140140
tooltipDirective.show(tooltipDelay);
@@ -192,7 +192,7 @@ describe('MatTooltip', () => {
192192
}));
193193

194194
it('should not show if hide is called before delay finishes', async(() => {
195-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
195+
assertTooltipInstance(tooltipDirective, false);
196196

197197
const tooltipDelay = 1000;
198198

@@ -209,27 +209,27 @@ describe('MatTooltip', () => {
209209
}));
210210

211211
it('should not show tooltip if message is not present or empty', () => {
212-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
212+
assertTooltipInstance(tooltipDirective, false);
213213

214214
tooltipDirective.message = undefined!;
215215
fixture.detectChanges();
216216
tooltipDirective.show();
217-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
217+
assertTooltipInstance(tooltipDirective, false);
218218

219219
tooltipDirective.message = null!;
220220
fixture.detectChanges();
221221
tooltipDirective.show();
222-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
222+
assertTooltipInstance(tooltipDirective, false);
223223

224224
tooltipDirective.message = '';
225225
fixture.detectChanges();
226226
tooltipDirective.show();
227-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
227+
assertTooltipInstance(tooltipDirective, false);
228228

229229
tooltipDirective.message = ' ';
230230
fixture.detectChanges();
231231
tooltipDirective.show();
232-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
232+
assertTooltipInstance(tooltipDirective, false);
233233
});
234234

235235
it('should not follow through with hide if show is called after', fakeAsync(() => {
@@ -252,7 +252,7 @@ describe('MatTooltip', () => {
252252
const initialPosition: TooltipPosition = 'below';
253253
const changedPosition: TooltipPosition = 'above';
254254

255-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
255+
assertTooltipInstance(tooltipDirective, false);
256256

257257
tooltipDirective.position = initialPosition;
258258
tooltipDirective.show();
@@ -264,12 +264,12 @@ describe('MatTooltip', () => {
264264

265265
// Different position value should destroy the tooltip
266266
tooltipDirective.position = changedPosition;
267-
expect(tooltipDirective._tooltipInstance).toBeNull();
267+
assertTooltipInstance(tooltipDirective, false);
268268
expect(tooltipDirective._overlayRef).toBeNull();
269269
});
270270

271271
it('should be able to modify the tooltip message', fakeAsync(() => {
272-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
272+
assertTooltipInstance(tooltipDirective, false);
273273

274274
tooltipDirective.show();
275275
tick(0); // Tick for the show delay (default is 0)
@@ -286,7 +286,7 @@ describe('MatTooltip', () => {
286286
}));
287287

288288
it('should allow extra classes to be set on the tooltip', fakeAsync(() => {
289-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
289+
assertTooltipInstance(tooltipDirective, false);
290290

291291
tooltipDirective.show();
292292
tick(0); // Tick for the show delay (default is 0)
@@ -510,7 +510,7 @@ describe('MatTooltip', () => {
510510
}));
511511

512512
it('should not show the tooltip on progammatic focus', fakeAsync(() => {
513-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
513+
assertTooltipInstance(tooltipDirective, false);
514514

515515
buttonElement.focus();
516516
tick(0);
@@ -585,7 +585,7 @@ describe('MatTooltip', () => {
585585
});
586586

587587
it('should hide tooltip if clipped after changing positions', fakeAsync(() => {
588-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
588+
assertTooltipInstance(tooltipDirective, false);
589589

590590
// Show the tooltip and tick for the show delay (default is 0)
591591
tooltipDirective.show();
@@ -626,7 +626,7 @@ describe('MatTooltip', () => {
626626
});
627627

628628
it('should show and hide the tooltip', fakeAsync(() => {
629-
expect(tooltipDirective._tooltipInstance).toBeUndefined();
629+
assertTooltipInstance(tooltipDirective, false);
630630

631631
tooltipDirective.show();
632632
tick(0); // Tick for the show delay (default is 0)
@@ -654,7 +654,7 @@ describe('MatTooltip', () => {
654654

655655
// On animation complete, should expect that the tooltip has been detached.
656656
flushMicrotasks();
657-
expect(tooltipDirective._tooltipInstance).toBeNull();
657+
assertTooltipInstance(tooltipDirective, false);
658658
}));
659659

660660
it('should have rendered the tooltip text on init', fakeAsync(() => {
@@ -751,3 +751,11 @@ class DynamicTooltipsDemo {
751751
return this._elementRef.nativeElement.querySelectorAll('button');
752752
}
753753
}
754+
755+
/** Asserts whether a tooltip directive has a tooltip instance. */
756+
function assertTooltipInstance(tooltip: MatTooltip, shouldExist: boolean): void {
757+
// Note that we have to cast this to a boolean, because Jasmine will go into an infinite loop
758+
// if it tries to stringify the `_tooltipInstance` when an assertion fails. The infinite loop
759+
// happens due to the `_tooltipInstance` having a circular structure.
760+
expect(!!tooltip._tooltipInstance).toBe(shouldExist);
761+
}

src/lib/tooltip/tooltip.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
import {Platform} from '@angular/cdk/platform';
2626
import {ComponentPortal} from '@angular/cdk/portal';
2727
import {first} from 'rxjs/operators/first';
28+
import {merge} from 'rxjs/observable/merge';
2829
import {ScrollDispatcher} from '@angular/cdk/scrolling';
2930
import {
3031
ChangeDetectionStrategy,
@@ -261,7 +262,7 @@ export class MatTooltip implements OnDestroy {
261262
this._tooltipInstance = overlayRef.attach(portal).instance;
262263

263264
// Dispose of the tooltip when the overlay is detached.
264-
overlayRef.detachments().subscribe(() => {
265+
merge(this._tooltipInstance!.afterHidden(), overlayRef.detachments()).subscribe(() => {
265266
// Check first if the tooltip has already been removed through this components destroy.
266267
if (this._tooltipInstance) {
267268
this._disposeTooltip();

0 commit comments

Comments
 (0)