Skip to content

Commit 1305fe0

Browse files
authored
test(cdk/menu): switch away from fakeAsync (#33550)
Reworks the CDK menu tests not to depend on `fakeAsync` anymore.
1 parent a15b754 commit 1305fe0

3 files changed

Lines changed: 64 additions & 58 deletions

File tree

src/cdk/menu/menu-bar.spec.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
1+
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
22
import {
33
Component,
44
ElementRef,
@@ -149,15 +149,15 @@ describe('MenuBar', () => {
149149
expect(document.activeElement).toEqual(menuBarNativeItems[menuBarNativeItems.length - 1]);
150150
});
151151

152-
it('should focus the edit MenuItem on E, D character keys', fakeAsync(() => {
152+
it('should focus the edit MenuItem on E, D character keys', async () => {
153153
focusMenuBar();
154154
dispatchKeyboardEvent(nativeMenuBar, 'keydown', E);
155155
dispatchKeyboardEvent(nativeMenuBar, 'keydown', D);
156-
tick(500);
156+
await wait(600);
157157
detectChanges();
158158

159159
expect(document.activeElement).toEqual(menuBarNativeItems[1]);
160-
}));
160+
});
161161

162162
it(
163163
'should toggle and wrap when cycling the right/left arrow keys on menu bar ' +
@@ -450,16 +450,16 @@ describe('MenuBar', () => {
450450
expect(nativeMenus.length).toBe(0);
451451
});
452452

453-
it('should focus share MenuItem on S, H character key press', fakeAsync(() => {
453+
it('should focus share MenuItem on S, H character key press', async () => {
454454
openFileMenu();
455455

456456
dispatchKeyboardEvent(nativeMenus[0], 'keydown', S);
457457
dispatchKeyboardEvent(nativeMenus[0], 'keydown', H);
458-
tick(500);
458+
await wait(600);
459459
detectChanges();
460460

461461
expect(document.activeElement).toEqual(fileMenuNativeItems[1]);
462-
}));
462+
});
463463

464464
it('should handle keyboard actions if initial menu is opened programmatically', () => {
465465
fixture.debugElement
@@ -1062,6 +1062,10 @@ describe('MenuBar', () => {
10621062
});
10631063
});
10641064

1065+
function wait(milliseconds: number) {
1066+
return new Promise(resolve => setTimeout(resolve, milliseconds));
1067+
}
1068+
10651069
@Component({
10661070
template: `
10671071
<ul cdkMenuBar>

src/cdk/menu/menu-trigger.spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
ViewChildren,
88
ChangeDetectionStrategy,
99
} from '@angular/core';
10-
import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
10+
import {ComponentFixture, TestBed} from '@angular/core/testing';
1111
import {By} from '@angular/platform-browser';
1212
import {dispatchKeyboardEvent} from '../../cdk/testing/private';
1313
import {CdkMenu} from './menu';
@@ -522,20 +522,19 @@ describe('MenuTrigger', () => {
522522
});
523523
});
524524

525-
it('should focus the first item when opening on click', fakeAsync(() => {
525+
it('should focus the first item when opening on click', () => {
526526
const fixture = TestBed.createComponent(TriggersWithSameMenuDifferentMenuBars);
527527
fixture.detectChanges();
528528

529529
fixture.componentInstance.nativeTriggers.first.nativeElement.click();
530530
fixture.detectChanges();
531-
tick();
532531

533532
const firstItem =
534533
fixture.componentInstance.nativeMenus.first.nativeElement.querySelector('.cdk-menu-item');
535534

536535
expect(firstItem).toBeTruthy();
537536
expect(document.activeElement).toBe(firstItem);
538-
}));
537+
});
539538
});
540539

541540
@Component({

src/cdk/menu/menu.spec.ts

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,7 @@ import {
77
ViewChildren,
88
ChangeDetectionStrategy,
99
} from '@angular/core';
10-
import {
11-
ComponentFixture,
12-
TestBed,
13-
fakeAsync,
14-
flush,
15-
tick,
16-
waitForAsync,
17-
} from '@angular/core/testing';
10+
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
1811
import {By} from '@angular/platform-browser';
1912
import {
2013
createMouseEvent,
@@ -87,6 +80,12 @@ describe('Menu', () => {
8780
});
8881

8982
describe('menu aim', () => {
83+
// TODO(crisbeto): update the component to clear timeouts on destroy.
84+
// Give some time for timeouts to be cleaned up.
85+
afterEach(async () => {
86+
await wait(350);
87+
});
88+
9089
/** A coordinate in the browser window */
9190
type Point = {x: number; y: number};
9291

@@ -189,13 +188,13 @@ describe('Menu', () => {
189188
*
190189
* @return the number of elements the mouse entered into.
191190
*/
192-
function hover(from: Point, to: Point, inMenu: HTMLElement, duration: number) {
191+
async function hover(from: Point, to: Point, inMenu: HTMLElement, duration: number) {
193192
const getNextPoint = getNextPointIterator(from, to);
194193

195194
let currentPoint: Point | null = from;
196195
let currElement = getElementAt(currentPoint);
197196

198-
const timeout = duration / (to.x - from.x);
197+
const timeout = duration / Math.abs(to.x - from.x);
199198

200199
let numEnters = 0;
201200
while (currentPoint) {
@@ -209,7 +208,9 @@ describe('Menu', () => {
209208
fixture.detectChanges();
210209
}
211210
currentPoint = getNextPoint();
212-
tick(timeout);
211+
if (timeout > 0) {
212+
await wait(timeout);
213+
}
213214
}
214215
return numEnters;
215216
}
@@ -231,31 +232,31 @@ describe('Menu', () => {
231232
};
232233
}
233234

234-
it('should close the edit menu when hovering directly down from the edit menu trigger to the print item without waiting', fakeAsync(() => {
235+
it('should close the edit menu when hovering directly down from the edit menu trigger to the print item without waiting', async () => {
235236
openFileMenu();
236237
openMenuOnHover(nativeEditTrigger!);
237238
const editPosition = nativeEditTrigger!.getBoundingClientRect();
238239
const printPosition = nativeFileButtons![4].getBoundingClientRect();
239240

240-
const numEnterEvents = hover(
241+
const numEnterEvents = await hover(
241242
{x: editPosition.x, y: editPosition.y + 1},
242243
{x: printPosition.x + 5, y: printPosition.y + 1},
243244
nativeMenus[0],
244-
100,
245+
0,
245246
);
246247
detectChanges();
247248

248249
expect(numEnterEvents).toBe(4);
249250
expect(nativeMenus.length).toBe(1);
250-
}));
251+
});
251252

252-
it('should close the edit menu after moving towards submenu and stopping', fakeAsync(() => {
253+
it('should close the edit menu after moving towards submenu and stopping', async () => {
253254
openFileMenu();
254255
openMenuOnHover(nativeEditTrigger!);
255256
const editPosition = nativeEditTrigger!.getBoundingClientRect();
256257
const sharePosition = nativeShareTrigger!.getBoundingClientRect();
257258

258-
const numEnters = hover(
259+
const numEnters = await hover(
259260
{
260261
x: editPosition.x + editPosition.width / 2,
261262
y: editPosition.y + editPosition.height - 10,
@@ -265,44 +266,43 @@ describe('Menu', () => {
265266
y: sharePosition.y + sharePosition.height - 10,
266267
},
267268
nativeMenus[0],
268-
100,
269+
0,
269270
);
270-
tick(2000);
271+
await wait(2100);
271272
detectChanges();
272273

273274
expect(numEnters).toBe(1);
274275
expect(nativeMenus.length).toBe(2);
275276
expect(nativeMenus[1].id).toBe('share_menu');
276-
}));
277+
});
277278

278-
it('should not close the edit submenu when hovering into its items in time', fakeAsync(() => {
279+
it('should not close the edit submenu when hovering into its items in time', async () => {
279280
openFileMenu();
280281
openMenuOnHover(nativeEditTrigger!);
281282
const editPosition = nativeEditTrigger!.getBoundingClientRect();
282283
const pastePosition = nativeEditButtons![4].getBoundingClientRect();
283284

284-
const numEnters = hover(editPosition, pastePosition, nativeMenus[0], 100);
285+
const numEnters = await hover(editPosition, pastePosition, nativeMenus[0], 0);
285286
detectChanges();
286-
flush();
287+
await fixture.whenStable();
287288

288289
expect(numEnters).toBeGreaterThan(2);
289290
expect(nativeMenus.length).toBe(2);
290291
expect(nativeMenus[1].id).toBe('edit_menu');
291-
}));
292+
});
292293

293-
it('should close the edit menu when hovering into its items slowly', fakeAsync(() => {
294+
it('should close the edit menu when hovering into its items slowly', async () => {
294295
openFileMenu();
295296
openMenuOnHover(nativeEditTrigger!);
296297
const editPosition = nativeEditTrigger!.getBoundingClientRect();
297298
const pastePosition = nativeEditButtons![4].getBoundingClientRect();
298299

299-
const numEnters = hover(editPosition, pastePosition, nativeMenus[0], 4000);
300+
const numEnters = await hover(editPosition, pastePosition, nativeMenus[0], 1100);
300301
detectChanges();
301-
flush();
302302

303303
expect(numEnters).toBeGreaterThan(2);
304304
expect(nativeMenus.length).toBe(1);
305-
}));
305+
});
306306
});
307307

308308
describe('with rtl layout and menu at bottom of page moving up and left', () => {
@@ -383,13 +383,13 @@ describe('Menu', () => {
383383
*
384384
* @return the number of elements the mouse entered into.
385385
*/
386-
function hover(from: Point, to: Point, inMenu: HTMLElement, duration: number) {
386+
async function hover(from: Point, to: Point, inMenu: HTMLElement, duration: number) {
387387
const getNextPoint = getNextPointIterator(from, to);
388388

389389
let currPoint: Point | null = from;
390390
let currElement = getElementAt(currPoint);
391391

392-
const timeout = duration / (to.x - from.x);
392+
const timeout = duration / Math.abs(to.x - from.x);
393393

394394
let numEnters = 0;
395395
while (currPoint) {
@@ -403,7 +403,9 @@ describe('Menu', () => {
403403
fixture.detectChanges();
404404
}
405405
currPoint = getNextPoint();
406-
tick(timeout);
406+
if (timeout) {
407+
await wait(timeout);
408+
}
407409
}
408410
return numEnters;
409411
}
@@ -425,66 +427,63 @@ describe('Menu', () => {
425427
};
426428
}
427429

428-
it('should close the edit menu when hovering directly up from the edit menu trigger to the print item without waiting', fakeAsync(() => {
430+
it('should close the edit menu when hovering directly up from the edit menu trigger to the print item without waiting', async () => {
429431
openFileMenu();
430432
openMenuOnHover(nativeEditTrigger!);
431-
tick();
432433

433434
const editPosition = nativeEditTrigger!.getBoundingClientRect();
434435
const printPosition = nativeFileButtons![0].getBoundingClientRect();
435436

436-
const numEnterEvents = hover(
437+
const numEnterEvents = await hover(
437438
{x: editPosition.x + editPosition.width / 2, y: editPosition.y + 5},
438439
{x: printPosition.x + 10, y: printPosition.y - 10},
439440
nativeMenus[0],
440-
100,
441+
0,
441442
);
442443
detectChanges();
443-
flush();
444444

445445
expect(numEnterEvents).toBe(4);
446446
expect(nativeMenus.length).toBe(1);
447-
}));
447+
});
448448

449-
it('should close the edit menu after moving towards submenu and stopping', fakeAsync(() => {
449+
it('should close the edit menu after moving towards submenu and stopping', async () => {
450450
openFileMenu();
451451
openMenuOnHover(nativeEditTrigger!);
452452
const editPosition = nativeEditTrigger!.getBoundingClientRect();
453453
const sharePosition = nativeShareTrigger!.getBoundingClientRect();
454454

455-
const numEnters = hover(
455+
const numEnters = await hover(
456456
{x: editPosition.x + editPosition.width / 2, y: editPosition.y + 5},
457457
{
458458
x: sharePosition.x + 10,
459459
y: sharePosition.y + 10,
460460
},
461461
nativeMenus[0],
462-
100,
462+
0,
463463
);
464-
tick(2000);
464+
await wait(2100);
465465
detectChanges();
466466

467467
expect(numEnters).toBe(1);
468468
expect(nativeMenus.length).toBe(2);
469469
expect(nativeMenus[1].id).toBe('share_menu');
470-
}));
470+
});
471471

472-
it('should not close the edit submenu when hovering into its items in time', fakeAsync(() => {
472+
it('should not close the edit submenu when hovering into its items in time', async () => {
473473
openFileMenu();
474474
openMenuOnHover(nativeEditTrigger!);
475-
tick();
476475

477476
const editPosition = nativeEditTrigger!.getBoundingClientRect();
478477
const undoPosition = nativeEditButtons![0].getBoundingClientRect();
479478

480-
const numEnters = hover(editPosition, undoPosition, nativeMenus[0], 100);
479+
const numEnters = await hover(editPosition, undoPosition, nativeMenus[0], 0);
481480
detectChanges();
482-
flush();
481+
await fixture.whenStable();
483482

484483
expect(numEnters).toBeGreaterThan(2);
485484
expect(nativeMenus.length).toBe(2);
486485
expect(nativeMenus[1].id).toBe('edit_menu');
487-
}));
486+
});
488487
});
489488
});
490489

@@ -518,6 +517,10 @@ describe('Menu', () => {
518517
});
519518
});
520519

520+
function wait(milliseconds: number) {
521+
return new Promise(resolve => setTimeout(resolve, milliseconds));
522+
}
523+
521524
@Component({
522525
template: `
523526
<div cdkMenuBar>

0 commit comments

Comments
 (0)