Skip to content
Merged
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
18 changes: 11 additions & 7 deletions src/cdk/menu/menu-bar.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {
Component,
ElementRef,
Expand Down Expand Up @@ -149,15 +149,15 @@ describe('MenuBar', () => {
expect(document.activeElement).toEqual(menuBarNativeItems[menuBarNativeItems.length - 1]);
});

it('should focus the edit MenuItem on E, D character keys', fakeAsync(() => {
it('should focus the edit MenuItem on E, D character keys', async () => {
focusMenuBar();
dispatchKeyboardEvent(nativeMenuBar, 'keydown', E);
dispatchKeyboardEvent(nativeMenuBar, 'keydown', D);
tick(500);
await wait(600);
detectChanges();

expect(document.activeElement).toEqual(menuBarNativeItems[1]);
}));
});

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

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

dispatchKeyboardEvent(nativeMenus[0], 'keydown', S);
dispatchKeyboardEvent(nativeMenus[0], 'keydown', H);
tick(500);
await wait(600);
detectChanges();

expect(document.activeElement).toEqual(fileMenuNativeItems[1]);
}));
});

it('should handle keyboard actions if initial menu is opened programmatically', () => {
fixture.debugElement
Expand Down Expand Up @@ -1062,6 +1062,10 @@ describe('MenuBar', () => {
});
});

function wait(milliseconds: number) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}

@Component({
template: `
<ul cdkMenuBar>
Expand Down
7 changes: 3 additions & 4 deletions src/cdk/menu/menu-trigger.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ViewChildren,
ChangeDetectionStrategy,
} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {dispatchKeyboardEvent} from '../../cdk/testing/private';
import {CdkMenu} from './menu';
Expand Down Expand Up @@ -522,20 +522,19 @@ describe('MenuTrigger', () => {
});
});

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

fixture.componentInstance.nativeTriggers.first.nativeElement.click();
fixture.detectChanges();
tick();

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

expect(firstItem).toBeTruthy();
expect(document.activeElement).toBe(firstItem);
}));
});
});

@Component({
Expand Down
97 changes: 50 additions & 47 deletions src/cdk/menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,7 @@ import {
ViewChildren,
ChangeDetectionStrategy,
} from '@angular/core';
import {
ComponentFixture,
TestBed,
fakeAsync,
flush,
tick,
waitForAsync,
} from '@angular/core/testing';
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {
createMouseEvent,
Expand Down Expand Up @@ -87,6 +80,12 @@ describe('Menu', () => {
});

describe('menu aim', () => {
// TODO(crisbeto): update the component to clear timeouts on destroy.
// Give some time for timeouts to be cleaned up.
afterEach(async () => {
await wait(350);
});

/** A coordinate in the browser window */
type Point = {x: number; y: number};

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

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

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

let numEnters = 0;
while (currentPoint) {
Expand All @@ -209,7 +208,9 @@ describe('Menu', () => {
fixture.detectChanges();
}
currentPoint = getNextPoint();
tick(timeout);
if (timeout > 0) {
await wait(timeout);
}
}
return numEnters;
}
Expand All @@ -231,31 +232,31 @@ describe('Menu', () => {
};
}

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

const numEnterEvents = hover(
const numEnterEvents = await hover(
{x: editPosition.x, y: editPosition.y + 1},
{x: printPosition.x + 5, y: printPosition.y + 1},
nativeMenus[0],
100,
0,
);
detectChanges();

expect(numEnterEvents).toBe(4);
expect(nativeMenus.length).toBe(1);
}));
});

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

const numEnters = hover(
const numEnters = await hover(
{
x: editPosition.x + editPosition.width / 2,
y: editPosition.y + editPosition.height - 10,
Expand All @@ -265,44 +266,43 @@ describe('Menu', () => {
y: sharePosition.y + sharePosition.height - 10,
},
nativeMenus[0],
100,
0,
);
tick(2000);
await wait(2100);
detectChanges();

expect(numEnters).toBe(1);
expect(nativeMenus.length).toBe(2);
expect(nativeMenus[1].id).toBe('share_menu');
}));
});

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

const numEnters = hover(editPosition, pastePosition, nativeMenus[0], 100);
const numEnters = await hover(editPosition, pastePosition, nativeMenus[0], 0);
detectChanges();
flush();
await fixture.whenStable();

expect(numEnters).toBeGreaterThan(2);
expect(nativeMenus.length).toBe(2);
expect(nativeMenus[1].id).toBe('edit_menu');
}));
});

it('should close the edit menu when hovering into its items slowly', fakeAsync(() => {
it('should close the edit menu when hovering into its items slowly', async () => {
openFileMenu();
openMenuOnHover(nativeEditTrigger!);
const editPosition = nativeEditTrigger!.getBoundingClientRect();
const pastePosition = nativeEditButtons![4].getBoundingClientRect();

const numEnters = hover(editPosition, pastePosition, nativeMenus[0], 4000);
const numEnters = await hover(editPosition, pastePosition, nativeMenus[0], 1100);
detectChanges();
flush();

expect(numEnters).toBeGreaterThan(2);
expect(nativeMenus.length).toBe(1);
}));
});
});

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

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

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

let numEnters = 0;
while (currPoint) {
Expand All @@ -403,7 +403,9 @@ describe('Menu', () => {
fixture.detectChanges();
}
currPoint = getNextPoint();
tick(timeout);
if (timeout) {
await wait(timeout);
}
}
return numEnters;
}
Expand All @@ -425,66 +427,63 @@ describe('Menu', () => {
};
}

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

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

const numEnterEvents = hover(
const numEnterEvents = await hover(
{x: editPosition.x + editPosition.width / 2, y: editPosition.y + 5},
{x: printPosition.x + 10, y: printPosition.y - 10},
nativeMenus[0],
100,
0,
);
detectChanges();
flush();

expect(numEnterEvents).toBe(4);
expect(nativeMenus.length).toBe(1);
}));
});

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

const numEnters = hover(
const numEnters = await hover(
{x: editPosition.x + editPosition.width / 2, y: editPosition.y + 5},
{
x: sharePosition.x + 10,
y: sharePosition.y + 10,
},
nativeMenus[0],
100,
0,
);
tick(2000);
await wait(2100);
detectChanges();

expect(numEnters).toBe(1);
expect(nativeMenus.length).toBe(2);
expect(nativeMenus[1].id).toBe('share_menu');
}));
});

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

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

const numEnters = hover(editPosition, undoPosition, nativeMenus[0], 100);
const numEnters = await hover(editPosition, undoPosition, nativeMenus[0], 0);
detectChanges();
flush();
await fixture.whenStable();

expect(numEnters).toBeGreaterThan(2);
expect(nativeMenus.length).toBe(2);
expect(nativeMenus[1].id).toBe('edit_menu');
}));
});
});
});

Expand Down Expand Up @@ -518,6 +517,10 @@ describe('Menu', () => {
});
});

function wait(milliseconds: number) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}

@Component({
template: `
<div cdkMenuBar>
Expand Down
Loading