Skip to content

Commit a3479f7

Browse files
authored
refactor(cdk/overlay): switch tests away from fakeAsync (#33192)
Reworks the overlay tests not to depend on `fakeAsync`.
1 parent 4558279 commit a3479f7

5 files changed

Lines changed: 61 additions & 94 deletions

File tree

src/cdk/overlay/overlay-directives.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
WritableSignal,
88
ChangeDetectionStrategy,
99
} from '@angular/core';
10-
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
10+
import {ComponentFixture, TestBed} from '@angular/core/testing';
1111
import {Subject} from 'rxjs';
1212
import {Direction} from '../bidi';
1313
import {A, ESCAPE} from '../keycodes';
@@ -178,7 +178,7 @@ describe('Overlay directives', () => {
178178
expect(event.defaultPrevented).toBe(false);
179179
});
180180

181-
it('should prevent closing via clicks on the backdrop by default', fakeAsync(() => {
181+
it('should prevent closing via clicks on the backdrop by default', () => {
182182
fixture.componentInstance.hasBackdrop = true;
183183
fixture.componentInstance.isOpen = true;
184184
fixture.changeDetectorRef.markForCheck();
@@ -189,7 +189,7 @@ describe('Overlay directives', () => {
189189
fixture.detectChanges();
190190

191191
expect(overlayContainerElement.textContent!.trim()).toBeTruthy();
192-
}));
192+
});
193193

194194
it('should prevent closing via the escape key with disableClose option', () => {
195195
fixture.componentInstance.isOpen = true;
@@ -204,7 +204,7 @@ describe('Overlay directives', () => {
204204
expect(event.defaultPrevented).toBe(false);
205205
});
206206

207-
it('should not depend on the order in which the `origin` and `open` are set', waitForAsync(() => {
207+
it('should not depend on the order in which the `origin` and `open` are set', () => {
208208
fixture.destroy();
209209

210210
const propOrderFixture = TestBed.createComponent(ConnectedOverlayPropertyInitOrder);
@@ -217,7 +217,7 @@ describe('Overlay directives', () => {
217217
overlayDirective.origin = propOrderFixture.componentInstance.trigger;
218218
propOrderFixture.detectChanges();
219219
}).not.toThrow();
220-
}));
220+
});
221221

222222
describe('inputs', () => {
223223
it('should set the width', () => {
@@ -321,7 +321,7 @@ describe('Overlay directives', () => {
321321
expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeNull();
322322
});
323323

324-
it('should be able to change hasBackdrop after the overlay has been initialized', fakeAsync(() => {
324+
it('should be able to change hasBackdrop after the overlay has been initialized', async () => {
325325
// Open once with a backdrop
326326
fixture.componentInstance.hasBackdrop = true;
327327
fixture.componentInstance.isOpen = true;
@@ -333,7 +333,7 @@ describe('Overlay directives', () => {
333333
fixture.componentInstance.isOpen = false;
334334
fixture.changeDetectorRef.markForCheck();
335335
fixture.detectChanges();
336-
tick(500);
336+
await new Promise(resolve => setTimeout(resolve, 500));
337337

338338
// Open again without a backdrop.
339339
fixture.componentInstance.hasBackdrop = false;
@@ -342,7 +342,7 @@ describe('Overlay directives', () => {
342342
fixture.detectChanges();
343343

344344
expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeFalsy();
345-
}));
345+
});
346346

347347
it('should set the custom backdrop class', () => {
348348
fixture.componentInstance.hasBackdrop = true;

src/cdk/overlay/overlay.spec.ts

Lines changed: 42 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,7 @@ import {
1515
signal,
1616
ChangeDetectionStrategy,
1717
} from '@angular/core';
18-
import {
19-
ComponentFixture,
20-
TestBed,
21-
fakeAsync,
22-
flush,
23-
tick,
24-
waitForAsync,
25-
} from '@angular/core/testing';
18+
import {ComponentFixture, TestBed} from '@angular/core/testing';
2619
import {Direction, Directionality} from '../bidi';
2720
import {CdkPortal, ComponentPortal, TemplatePortal} from '../portal';
2821
import {dispatchFakeEvent} from '../testing/private';
@@ -77,7 +70,11 @@ describe('Overlay', () => {
7770
overlayContainer.ngOnDestroy();
7871
}
7972

80-
beforeEach(waitForAsync(setup));
73+
function wait(milliseconds: number) {
74+
return new Promise(resolve => setTimeout(resolve, milliseconds));
75+
}
76+
77+
beforeEach(setup);
8178
afterEach(cleanup);
8279

8380
it('should load a component into an overlay', () => {
@@ -299,7 +296,7 @@ describe('Overlay', () => {
299296
expect(overlayRef.getConfig().direction).toBe('ltr');
300297
});
301298

302-
it('should clear out all DOM element references on dispose', fakeAsync(() => {
299+
it('should clear out all DOM element references on dispose', async () => {
303300
const overlayRef = createOverlayRef(injector, {hasBackdrop: true});
304301
overlayRef.attach(componentPortal);
305302

@@ -312,7 +309,7 @@ describe('Overlay', () => {
312309
.toBeTruthy();
313310

314311
overlayRef.dispose();
315-
tick(500);
312+
await wait(500);
316313

317314
expect(overlayRef.hostElement)
318315
.withContext('Expected overlay host not to be referenced.')
@@ -323,30 +320,7 @@ describe('Overlay', () => {
323320
expect(overlayRef.backdropElement)
324321
.withContext('Expected backdrop element not to be referenced.')
325322
.toBeFalsy();
326-
}));
327-
328-
it('should clear the backdrop timeout if the transition finishes first', fakeAsync(() => {
329-
const overlayRef = createOverlayRef(injector, {hasBackdrop: true});
330-
331-
overlayRef.attach(componentPortal);
332-
overlayRef.detach();
333-
334-
const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop')!;
335-
dispatchFakeEvent(backdrop, 'transitionend');
336-
337-
// Note: we don't `tick` or `flush` here. The assertion is that
338-
// `fakeAsync` will throw if we have an unflushed timer.
339-
}));
340-
341-
it('should clear the backdrop timeout if the overlay is disposed', fakeAsync(() => {
342-
const overlayRef = createOverlayRef(injector, {hasBackdrop: true});
343-
overlayRef.attach(componentPortal);
344-
overlayRef.detach();
345-
overlayRef.dispose();
346-
347-
// Note: we don't `tick` or `flush` here. The assertion is that
348-
// `fakeAsync` will throw if we have an unflushed timer.
349-
}));
323+
});
350324

351325
it('should be able to use the `Overlay` provider during app initialization', () => {
352326
/** Dummy provider that depends on `Overlay`. */
@@ -466,7 +440,7 @@ describe('Overlay', () => {
466440
expect(() => overlayRef.removePanelClass([''])).not.toThrow();
467441
});
468442

469-
it('should detach a component-based overlay when the view is destroyed', fakeAsync(() => {
443+
it('should detach a component-based overlay when the view is destroyed', async () => {
470444
const overlayRef = createOverlayRef(injector);
471445
const paneElement = overlayRef.overlayElement;
472446

@@ -476,25 +450,26 @@ describe('Overlay', () => {
476450
expect(paneElement.childNodes.length).not.toBe(0);
477451

478452
viewContainerFixture.destroy();
479-
flush();
453+
await viewContainerFixture.whenStable();
480454

481455
expect(paneElement.childNodes.length).toBe(0);
482-
}));
456+
});
483457

484-
it('should detach a template-based overlay when the view is destroyed', fakeAsync(() => {
458+
it('should detach a template-based overlay when the view is destroyed', async () => {
485459
const overlayRef = createOverlayRef(injector);
486460
const paneElement = overlayRef.overlayElement;
487461

488462
overlayRef.attach(templatePortal);
489463
viewContainerFixture.detectChanges();
464+
await viewContainerFixture.whenStable();
490465

491466
expect(paneElement.childNodes.length).not.toBe(0);
492467

493468
viewContainerFixture.destroy();
494-
flush();
469+
await wait(100);
495470

496471
expect(paneElement.childNodes.length).toBe(0);
497-
}));
472+
});
498473

499474
it('should do nothing when trying to attach a disposed overlay', () => {
500475
const overlayRef = createOverlayRef(injector);
@@ -510,17 +485,17 @@ describe('Overlay', () => {
510485
config = new OverlayConfig();
511486
});
512487

513-
it('should apply the positioning strategy', fakeAsync(() => {
488+
it('should apply the positioning strategy', async () => {
514489
config.positionStrategy = new FakePositionStrategy();
515490

516491
createOverlayRef(injector, config).attach(componentPortal);
517492
viewContainerFixture.detectChanges();
518-
tick();
493+
await viewContainerFixture.whenStable();
519494

520495
expect(overlayContainerElement.querySelectorAll('.fake-positioned').length).toBe(1);
521-
}));
496+
});
522497

523-
it('should have the overlay in the DOM in position strategy when reattaching', fakeAsync(() => {
498+
it('should have the overlay in the DOM in position strategy when reattaching', async () => {
524499
let overlayPresentInDom = false;
525500

526501
config.positionStrategy = {
@@ -537,17 +512,17 @@ describe('Overlay', () => {
537512
.toBeTruthy();
538513

539514
overlayRef.detach();
540-
tick();
515+
await wait(0);
541516

542517
overlayRef.attach(componentPortal);
543-
tick();
518+
await wait(0);
544519

545520
expect(overlayPresentInDom)
546521
.withContext('Expected host element to be attached to the DOM.')
547522
.toBeTruthy();
548-
}));
523+
});
549524

550-
it('should not apply the position if it detaches before the zone stabilizes', fakeAsync(() => {
525+
it('should not apply the position if it detaches before the zone stabilizes', async () => {
551526
config.positionStrategy = new FakePositionStrategy();
552527

553528
const overlayRef = createOverlayRef(injector, config);
@@ -557,12 +532,12 @@ describe('Overlay', () => {
557532
overlayRef.attach(componentPortal);
558533
overlayRef.detach();
559534
viewContainerFixture.detectChanges();
560-
tick();
535+
await viewContainerFixture.whenStable();
561536

562537
expect(config.positionStrategy.apply).not.toHaveBeenCalled();
563-
}));
538+
});
564539

565-
it('should be able to swap position strategies', fakeAsync(() => {
540+
it('should be able to swap position strategies', async () => {
566541
const firstStrategy = new FakePositionStrategy();
567542
const secondStrategy = new FakePositionStrategy();
568543

@@ -577,7 +552,7 @@ describe('Overlay', () => {
577552
const overlayRef = createOverlayRef(injector, config);
578553
overlayRef.attach(componentPortal);
579554
viewContainerFixture.detectChanges();
580-
tick();
555+
await viewContainerFixture.whenStable();
581556

582557
expect(firstStrategy.attach).toHaveBeenCalledTimes(1);
583558
expect(firstStrategy.apply).toHaveBeenCalledTimes(1);
@@ -587,17 +562,17 @@ describe('Overlay', () => {
587562

588563
overlayRef.updatePositionStrategy(secondStrategy);
589564
viewContainerFixture.detectChanges();
590-
tick();
565+
await viewContainerFixture.whenStable();
591566

592567
expect(firstStrategy.attach).toHaveBeenCalledTimes(1);
593568
expect(firstStrategy.apply).toHaveBeenCalledTimes(1);
594569
expect(firstStrategy.dispose).toHaveBeenCalledTimes(1);
595570

596571
expect(secondStrategy.attach).toHaveBeenCalledTimes(1);
597572
expect(secondStrategy.apply).toHaveBeenCalledTimes(1);
598-
}));
573+
});
599574

600-
it('should not do anything when trying to swap a positioning strategy with itself', fakeAsync(() => {
575+
it('should not do anything when trying to swap a positioning strategy with itself', async () => {
601576
const strategy = new FakePositionStrategy();
602577

603578
spyOn(strategy, 'attach');
@@ -609,20 +584,20 @@ describe('Overlay', () => {
609584
const overlayRef = createOverlayRef(injector, config);
610585
overlayRef.attach(componentPortal);
611586
viewContainerFixture.detectChanges();
612-
tick();
587+
await viewContainerFixture.whenStable();
613588

614589
expect(strategy.attach).toHaveBeenCalledTimes(1);
615590
expect(strategy.apply).toHaveBeenCalledTimes(1);
616591
expect(strategy.dispose).not.toHaveBeenCalled();
617592

618593
overlayRef.updatePositionStrategy(strategy);
619594
viewContainerFixture.detectChanges();
620-
tick();
595+
await viewContainerFixture.whenStable();
621596

622597
expect(strategy.attach).toHaveBeenCalledTimes(1);
623598
expect(strategy.apply).toHaveBeenCalledTimes(1);
624599
expect(strategy.dispose).not.toHaveBeenCalled();
625-
}));
600+
});
626601

627602
it('should not throw when disposing multiple times in a row', () => {
628603
const overlayRef = createOverlayRef(injector);
@@ -636,15 +611,6 @@ describe('Overlay', () => {
636611
overlayRef.dispose();
637612
}).not.toThrow();
638613
});
639-
640-
it('should not trigger timers when disposing of an overlay', fakeAsync(() => {
641-
const overlayRef = createOverlayRef(injector, {hasBackdrop: true});
642-
overlayRef.attach(templatePortal);
643-
overlayRef.dispose();
644-
645-
// The assertion here is that `fakeAsync` doesn't flag
646-
// any pending timeouts after the test is done.
647-
}));
648614
});
649615

650616
describe('size', () => {
@@ -1050,7 +1016,7 @@ describe('Overlay', () => {
10501016
expect(fakeScrollStrategy.overlayRef).toBeNull();
10511017
});
10521018

1053-
it('should be able to swap scroll strategies', fakeAsync(() => {
1019+
it('should be able to swap scroll strategies', async () => {
10541020
const firstStrategy = new FakeScrollStrategy();
10551021
const secondStrategy = new FakeScrollStrategy();
10561022

@@ -1065,7 +1031,7 @@ describe('Overlay', () => {
10651031

10661032
overlayRef.attach(componentPortal);
10671033
viewContainerFixture.detectChanges();
1068-
tick();
1034+
await viewContainerFixture.whenStable();
10691035

10701036
expect(firstStrategy.attach).toHaveBeenCalledTimes(1);
10711037
expect(firstStrategy.enable).toHaveBeenCalledTimes(1);
@@ -1075,7 +1041,7 @@ describe('Overlay', () => {
10751041

10761042
overlayRef.updateScrollStrategy(secondStrategy);
10771043
viewContainerFixture.detectChanges();
1078-
tick();
1044+
await viewContainerFixture.whenStable();
10791045

10801046
expect(firstStrategy.attach).toHaveBeenCalledTimes(1);
10811047
expect(firstStrategy.enable).toHaveBeenCalledTimes(1);
@@ -1084,9 +1050,9 @@ describe('Overlay', () => {
10841050

10851051
expect(secondStrategy.attach).toHaveBeenCalledTimes(1);
10861052
expect(secondStrategy.enable).toHaveBeenCalledTimes(1);
1087-
}));
1053+
});
10881054

1089-
it('should not do anything when trying to swap a scroll strategy with itself', fakeAsync(() => {
1055+
it('should not do anything when trying to swap a scroll strategy with itself', async () => {
10901056
const strategy = new FakeScrollStrategy();
10911057

10921058
spyOn(strategy, 'attach');
@@ -1098,7 +1064,7 @@ describe('Overlay', () => {
10981064

10991065
overlayRef.attach(componentPortal);
11001066
viewContainerFixture.detectChanges();
1101-
tick();
1067+
await viewContainerFixture.whenStable();
11021068

11031069
expect(strategy.attach).toHaveBeenCalledTimes(1);
11041070
expect(strategy.enable).toHaveBeenCalledTimes(1);
@@ -1107,13 +1073,13 @@ describe('Overlay', () => {
11071073

11081074
overlayRef.updateScrollStrategy(strategy);
11091075
viewContainerFixture.detectChanges();
1110-
tick();
1076+
await viewContainerFixture.whenStable();
11111077

11121078
expect(strategy.attach).toHaveBeenCalledTimes(1);
11131079
expect(strategy.enable).toHaveBeenCalledTimes(1);
11141080
expect(strategy.disable).not.toHaveBeenCalled();
11151081
expect(strategy.detach).not.toHaveBeenCalled();
1116-
}));
1082+
});
11171083
});
11181084
});
11191085

0 commit comments

Comments
 (0)