diff --git a/e2e/components/menu/menu-page.ts b/e2e/components/menu/menu-page.ts
index 25c4bf01d4e3..7e25d774004c 100644
--- a/e2e/components/menu/menu-page.ts
+++ b/e2e/components/menu/menu-page.ts
@@ -8,6 +8,8 @@ export class MenuPage {
menu() { return element(by.css('.md-menu')); }
+ start() { return element(by.id('start')); }
+
trigger() { return element(by.id('trigger')); }
triggerTwo() { return element(by.id('trigger-two')); }
@@ -32,6 +34,17 @@ export class MenuPage {
combinedMenu() { return element(by.css('.md-menu.combined')); }
+ // TODO(kara): move to common testing utility
+ pressKey(key: any): void {
+ browser.actions().sendKeys(key).perform();
+ }
+
+ // TODO(kara): move to common testing utility
+ expectFocusOn(el: ElementFinder): void {
+ expect(browser.driver.switchTo().activeElement().getInnerHtml())
+ .toBe(el.getInnerHtml());
+ }
+
expectMenuPresent(expected: boolean) {
return browser.isElementPresent(by.css('.md-menu')).then((isPresent) => {
expect(isPresent).toBe(expected);
diff --git a/e2e/components/menu/menu.e2e.ts b/e2e/components/menu/menu.e2e.ts
index fda43f6f8349..b247bc113ef8 100644
--- a/e2e/components/menu/menu.e2e.ts
+++ b/e2e/components/menu/menu.e2e.ts
@@ -12,7 +12,7 @@ describe('menu', () => {
page.trigger().click();
page.expectMenuPresent(true);
- expect(page.menu().getText()).toEqual("One\nTwo\nThree");
+ expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
});
it('should close menu when area outside menu is clicked', () => {
@@ -45,14 +45,14 @@ describe('menu', () => {
it('should support multiple triggers opening the same menu', () => {
page.triggerTwo().click();
- expect(page.menu().getText()).toEqual("One\nTwo\nThree");
+ expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
page.expectMenuAlignedWith(page.menu(), 'trigger-two');
page.body().click();
page.expectMenuPresent(false);
page.trigger().click();
- expect(page.menu().getText()).toEqual("One\nTwo\nThree");
+ expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
page.expectMenuAlignedWith(page.menu(), 'trigger');
page.body().click();
@@ -66,6 +66,84 @@ describe('menu', () => {
});
});
+ describe('keyboard events', () => {
+ beforeEach(() => {
+ // click start button to avoid tabbing past navigation
+ page.start().click();
+ page.pressKey(protractor.Key.TAB);
+ });
+
+ it('should auto-focus the first item when opened with keyboard', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.expectFocusOn(page.items(0));
+ });
+
+ it('should not focus the first item when opened with mouse', () => {
+ page.trigger().click();
+ page.expectFocusOn(page.trigger());
+ });
+
+ it('should focus subsequent items when down arrow is pressed', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.DOWN);
+ page.expectFocusOn(page.items(1));
+ });
+
+ it('should focus previous items when up arrow is pressed', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.DOWN);
+ page.pressKey(protractor.Key.UP);
+ page.expectFocusOn(page.items(0));
+ });
+
+ it('should skip disabled items using arrow keys', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.DOWN);
+ page.pressKey(protractor.Key.DOWN);
+ page.expectFocusOn(page.items(3));
+
+ page.pressKey(protractor.Key.UP);
+ page.expectFocusOn(page.items(1));
+ });
+
+ it('should close the menu when tabbing past items', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.TAB);
+ page.expectMenuPresent(false);
+
+ page.start().click();
+ page.pressKey(protractor.Key.TAB);
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.TAB));
+ page.expectMenuPresent(false);
+ });
+
+ it('should wrap back to menu when arrow keying past items', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.DOWN);
+ page.pressKey(protractor.Key.DOWN);
+ page.pressKey(protractor.Key.DOWN);
+ page.expectFocusOn(page.items(0));
+
+ page.pressKey(protractor.Key.UP);
+ page.expectFocusOn(page.items(3));
+ });
+
+ it('should focus before and after trigger when tabbing past items', () => {
+ page.pressKey(protractor.Key.ENTER);
+ page.pressKey(protractor.Key.TAB);
+ page.expectFocusOn(page.triggerTwo());
+
+ // navigate back to trigger
+ page.pressKey(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.TAB));
+ page.pressKey(protractor.Key.ENTER);
+
+ page.pressKey(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.TAB));
+ page.expectFocusOn(page.start());
+ });
+
+ });
+
describe('position - ', () => {
it('should default menu alignment to "after below" when not set', () => {
diff --git a/src/demo-app/menu/menu-demo.ts b/src/demo-app/menu/menu-demo.ts
index 1d0d04bba99e..aafd42606ce5 100644
--- a/src/demo-app/menu/menu-demo.ts
+++ b/src/demo-app/menu/menu-demo.ts
@@ -12,8 +12,8 @@ export class MenuDemo {
items = [
{text: 'Refresh'},
{text: 'Settings'},
- {text: 'Help'},
- {text: 'Sign Out', disabled: true}
+ {text: 'Help', disabled: true},
+ {text: 'Sign Out'}
];
select(text: string) { this.selected = text; }
diff --git a/src/e2e-app/menu/menu-e2e.html b/src/e2e-app/menu/menu-e2e.html
index b77eee83e80a..057517b9c8fe 100644
--- a/src/e2e-app/menu/menu-e2e.html
+++ b/src/e2e-app/menu/menu-e2e.html
@@ -1,6 +1,7 @@
{{ selected }}
+
@@ -8,6 +9,7 @@
+