Skip to content

Commit

Permalink
feat(menu): Fix menu closing on menu item click.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 464533483
  • Loading branch information
joyzhong authored and copybara-github committed Aug 1, 2022
1 parent a885a1f commit d37e23d
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 7 deletions.
20 changes: 20 additions & 0 deletions list/harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {Harness} from '@material/web/testing/harness';

import {List} from './lib/list';
import {ListItemHarness} from './lib/listitem/harness';

/**
* Test harness for list.
*/
export class ListHarness extends Harness<List> {
/** @return List item harnesses. */
getItems() {
return this.element.items.map((item) => new ListItemHarness(item));
}
}
3 changes: 2 additions & 1 deletion list/lib/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export class List extends LitElement {

items: ListItem[] = [];

@queryAssignedElements() protected assignedElements!: HTMLElement[]|null;
@queryAssignedElements({flatten: true})
protected assignedElements!: HTMLElement[]|null;

override firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
Expand Down
19 changes: 19 additions & 0 deletions list/lib/listitem/harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {Harness} from '@material/web/testing/harness';

import {ListItem} from './list-item';

/**
* Test harness for list item.
*/
export class ListItemHarness extends Harness<ListItem> {
override async getInteractiveElement() {
await this.element.updateComplete;
return this.element.renderRoot.querySelector('li') as HTMLElement;
}
}
2 changes: 0 additions & 2 deletions list/list_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import './list-item';
import {Environment} from '@material/web/testing/environment';
import {html} from 'lit';

import {MdList} from './list';

const LIST_TEMPLATE = html`
<md-list>
<md-list-item>One</md-list-item>
Expand Down
21 changes: 21 additions & 0 deletions menu/harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {Harness} from '@material/web/testing/harness';

import {ListItemHarness} from '../list/lib/listitem/harness';

import {Menu} from './lib/menu';

/**
* Test harness for menu.
*/
export class MenuHarness extends Harness<Menu> {
/** @return ListItem harnesses for the menu's items. */
getItems() {
return this.element.items.map((item) => new ListItemHarness(item));
}
}
6 changes: 2 additions & 4 deletions menu/lib/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {MDCMenuFoundation} from './foundation';
export type DefaultFocusState = keyof typeof DefaultFocusStateEnum;

interface ActionDetail {
index: number;
item: ListItem;
}

/**
Expand Down Expand Up @@ -293,9 +293,7 @@ export abstract class Menu extends LitElement {
protected onAction(evt: CustomEvent<ActionDetail>) {
const listElement = this.listElement;
if (this.mdcFoundation && listElement) {
const index = evt.detail.index;

const el = listElement.items[index];
const el = evt.detail.item;

if (el) {
this.mdcFoundation.handleItemAction(el);
Expand Down
105 changes: 105 additions & 0 deletions menu/menu_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import './menu';
import '../list/list-item';

import {Environment} from '@material/web/testing/environment';
import {html} from 'lit';

import {MenuHarness} from './harness';
import {MdMenu} from './menu';

describe('menu tests', () => {
let menu: MdMenu;
let harness: MenuHarness;
const env = new Environment();

beforeEach(async () => {
const el = env.render(getMenuTemplate());
menu = el.querySelector('md-menu')!;
harness = await new MenuHarness(menu);
await env.waitForStability();
});

describe('open/close', () => {
it('`show` method opens menu', async () => {
menu.show();
await menu.updateComplete;
expect(menu.open).toBe(true);
});

it('close method closes menu', async () => {
menu.show();
await menu.updateComplete;

menu.close();
await menu.updateComplete;
expect(menu.open).toBe(false);
});

it('closes the menu on click outside the menu', async () => {
menu.show();
await menu.updateComplete;

document.body.dispatchEvent(new MouseEvent('click'));
await menu.updateComplete;
expect(menu.open).toBe(false);
});

it('closes the menu on click on menu item', async () => {
menu.show();
await menu.updateComplete;

const item = harness.getItems()[0];
await item.clickWithMouse();
expect(menu.open).toBe(false);
});

it('closes the menu on TAB keypress', async () => {
menu.show();
await menu.updateComplete;

const menuSurface = menu.renderRoot.querySelector('md-menu-surface')!;
menuSurface.dispatchEvent(new KeyboardEvent('keydown', {key: 'Tab'}));
expect(menu.open).toBe(false);
});

it('closes the menu on ESC keypress', async () => {
menu.show();
await menu.updateComplete;

const menuSurface = menu.renderRoot.querySelector('md-menu-surface')!;
menuSurface.mdcRoot.dispatchEvent(
new KeyboardEvent('keydown', {key: 'Escape'}));
expect(menu.open).toBe(false);
});
});
});

function getMenuTemplate(propsInit: Partial<MdMenu> = {}) {
return html`
<div class="root" style="position: relative;">
<button @click=${setAnchorAndOpen}>
Open Menu
</button>
<md-menu .quick="${propsInit.quick ?? true}">
<md-list-item>One</md-list-item>
<md-list-item>Two</md-list-item>
<md-list-item>Three</md-list-item>
</md-menu>
</div>
`;
}

function setAnchorAndOpen(e: MouseEvent) {
const target = e.target as HTMLButtonElement;
const menu = target.nextElementSibling as MdMenu;
if (!menu.anchor) {
menu.anchor = target;
}
menu.show();
}

0 comments on commit d37e23d

Please sign in to comment.