fix(select): close select on menu close

There are some situations where the menu can close when the outer select
is still open and unaware.

For example, clicking the field will open the menu, then clicking it
again will close the menu **but not the select**.

This is because the menu observes outside clicks in order to close
itself. We don't currently observe those closes to update our own state
inside `md-select`, so the UI still shows as if it is open but without a
menu.

The fix here is to always reflect the state of the menu on `closed`.
This commit is contained in:
43081j 2023-09-10 18:28:32 +01:00
parent ec0a8ebf6e
commit 58bea9ce07
2 changed files with 45 additions and 1 deletions

View File

@ -20,6 +20,9 @@ export class SelectHarness extends Harness<Select> {
protected getField() {
return this.element.renderRoot.querySelector('.field') as Field;
}
protected getMenu() {
return this.element.renderRoot.querySelector('md-menu')!;
}
/**
* Shows the menu and returns the first list item element.
*/
@ -48,6 +51,18 @@ export class SelectHarness extends Harness<Select> {
field.click();
}
async clickAndWaitForMenu() {
const menu = this.getMenu();
const menuOpen = menu.open === true;
const waitForMenu = new Promise<void>((resolve) => {
menu.addEventListener(menuOpen ? 'closed' : 'opened', () => {
resolve();
}, {once: true});
});
await this.click();
await waitForMenu;
}
async clickOption(index: number) {
const menu = this.element.renderRoot.querySelector('md-menu')!;
if (!menu.open) {

View File

@ -47,7 +47,9 @@ describe('<md-outlined-select>', () => {
const selectEl = root.querySelector('md-outlined-select')!;
await selectEl.updateComplete;
await new SelectHarness(selectEl).clickOption(1);
const harness = new SelectHarness(selectEl);
await harness.clickAndWaitForMenu();
await harness.clickOption(1);
expect(changed).toBeTrue();
});
@ -177,6 +179,33 @@ describe('<md-outlined-select>', () => {
],
});
});
it('closes select when field re-clicked', async () => {
render(
html`
<md-outlined-select>
<md-select-option selected></md-select-option>
<md-select-option></md-select-option>
</md-outlined-select>`,
root);
const selectEl = root.querySelector('md-outlined-select')!;
await selectEl.updateComplete;
const spanEl = selectEl.shadowRoot!.querySelector<HTMLElement>(
'span.select'
)!;
const menuEl = selectEl.shadowRoot!.querySelector('md-menu')!;
const harness = new SelectHarness(selectEl);
await harness.clickAndWaitForMenu();
expect(spanEl.classList.contains('open')).toBeTrue();
expect(menuEl.open).toBeTrue();
await harness.clickAndWaitForMenu();
expect(menuEl.open).toBeFalse();
expect(spanEl.classList.contains('open')).toBeFalse();
});
});
describe('<md-filled-select>', () => {