Skip to content

Commit

Permalink
[base-ui][useMenuButton] Fix non native button triggers (mui#40645)
Browse files Browse the repository at this point in the history
  • Loading branch information
DiegoAndai authored Jan 22, 2024
1 parent 27cbef2 commit e0ab9be
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 28 deletions.
84 changes: 57 additions & 27 deletions packages/mui-base/src/MenuButton/MenuButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import userEvent from '@testing-library/user-event';
import {
act,
createMount,
createRenderer,
describeConformanceUnstyled,
fireEvent,
} from '@mui-internal/test-utils';
import { MenuButton, menuButtonClasses } from '@mui/base/MenuButton';
import { DropdownContext, DropdownContextValue, DropdownActionTypes } from '@mui/base/useDropdown';

// TODO v6: initialize @testing-library/user-event using userEvent.setup() instead of directly calling methods e.g. userEvent.click() for all related tests in this file
// currently the setup() method uses the ClipboardEvent constructor which is incompatible with our lowest supported version of iOS Safari (12.2) https://github.com/mui/material-ui/blob/master/.browserslistrc#L44
// userEvent.setup() requires Safari 14 or up to work

const testContext: DropdownContextValue = {
dispatch: () => {},
popupId: 'menu-popup',
Expand Down Expand Up @@ -131,32 +135,58 @@ describe('<MenuButton />', () => {
});

describe('keyboard navigation', () => {
['ArrowUp', 'ArrowDown'].forEach((key) =>
it(`opens the menu when pressing ${key}`, () => {
const dispatchSpy = spy();
const context = {
...testContext,
state: { open: false },
dispatch: dispatchSpy,
};

const { getByRole } = render(
<DropdownContext.Provider value={context}>
<MenuButton />
</DropdownContext.Provider>,
);
const button = getByRole('button');

act(() => {
button.focus();
});

fireEvent.keyDown(button, { key });

expect(dispatchSpy.calledOnce).to.equal(true);
expect(dispatchSpy.args[0][0]).to.contain({ type: DropdownActionTypes.open });
}),
);
[<MenuButton />, <MenuButton slots={{ root: 'span' }} />].forEach((buttonComponent) => {
const buttonType = buttonComponent.props.slots?.root ? 'non-native' : 'native';
['ArrowUp', 'ArrowDown'].forEach((key) =>
it(`opens the menu when pressing "${key}" on a ${buttonType} button`, async () => {
const dispatchSpy = spy();
const context = {
...testContext,
state: { open: false },
dispatch: dispatchSpy,
};

const { getByRole } = render(
<DropdownContext.Provider value={context}>{buttonComponent}</DropdownContext.Provider>,
);

const button = getByRole('button');
act(() => {
button.focus();
});

await userEvent.keyboard(`{${key}}`);

expect(dispatchSpy.calledOnce).to.equal(true);
expect(dispatchSpy.args[0][0]).to.contain({ type: DropdownActionTypes.open });
}),
);

['Enter', ' '].forEach((key) =>
it(`opens the menu when pressing "${key}" on a ${buttonType} button`, async () => {
const dispatchSpy = spy();
const context = {
...testContext,
state: { open: false },
dispatch: dispatchSpy,
};

const { getByRole } = render(
<DropdownContext.Provider value={context}>{buttonComponent}</DropdownContext.Provider>,
);

const button = getByRole('button');
act(() => {
button.focus();
});

await userEvent.keyboard(`{${key}}`);

expect(dispatchSpy.calledOnce).to.equal(true);
expect(dispatchSpy.args[0][0]).to.contain({ type: DropdownActionTypes.toggle });
}),
);
});
});

describe('accessibility attributes', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useMenuButton/useMenuButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function useMenuButton(parameters: UseMenuButtonParameters = {}): UseMenu
externalProps: ExternalProps = {} as ExternalProps,
) => {
const externalEventHandlers = extractEventHandlers(externalProps);
const getCombinedProps = combineHooksSlotProps(getButtonRootProps, getOwnRootProps);
const getCombinedProps = combineHooksSlotProps(getOwnRootProps, getButtonRootProps);

return {
'aria-haspopup': 'menu' as const,
Expand Down

0 comments on commit e0ab9be

Please sign in to comment.