Skip to content

Commit

Permalink
[test] Convert Menu tests to testing-library (#26915)
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Jun 24, 2021
1 parent 46ebf5a commit b38c9f9
Showing 1 changed file with 131 additions and 97 deletions.
228 changes: 131 additions & 97 deletions packages/material-ui/src/Menu/Menu.test.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import * as React from 'react';
import { spy } from 'sinon';
import { spy, useFakeTimers } from 'sinon';
import { expect } from 'chai';
import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import {
createMount,
createClientRender,
describeConformanceV5,
screen,
fireEvent,
} from 'test/utils';
import Menu, { menuClasses as classes } from '@material-ui/core/Menu';
import MenuList from '@material-ui/core/MenuList';
import Popover from '@material-ui/core/Popover';

const MENU_LIST_HEIGHT = 100;

describe('<Menu />', () => {
// StrictModeViolation: Not using act(), prefer using createClientRender from test/utils
const mount = createMount({ strict: false });
/**
* @type {ReturnType<typeof useFakeTimers>}
*/
let clock;
beforeEach(() => {
clock = useFakeTimers();
});
afterEach(() => {
clock.restore();
});

const mount = createMount();
const render = createClientRender();
const defaultProps = {
open: false,
anchorEl: () => document.createElement('div'),
};

describeConformanceV5(<Menu {...defaultProps} open />, () => ({
describeConformanceV5(<Menu anchorEl={() => document.createElement('div')} open />, () => ({
classes,
inheritComponent: Popover,
render,
Expand All @@ -38,176 +47,201 @@ describe('<Menu />', () => {

describe('event callbacks', () => {
describe('entering', () => {
it('should fire callbacks', (done) => {
it('should fire callbacks', () => {
const handleEnter = spy();
const handleEntering = spy();

const wrapper = mount(
render(
<Menu
anchorEl={document.createElement('div')}
open
TransitionProps={{
onEnter: handleEnter,
onEntering: handleEntering,
onEntered: () => {
expect(handleEnter.callCount).to.equal(1);
expect(handleEnter.args[0].length).to.equal(2);
expect(handleEntering.callCount).to.equal(1);
expect(handleEntering.args[0].length).to.equal(2);
done();
},
}}
{...defaultProps}
/>,
);

wrapper.setProps({
open: true,
});
expect(handleEnter.callCount).to.equal(1);
expect(handleEnter.args[0].length).to.equal(2);
expect(handleEntering.callCount).to.equal(1);
expect(handleEntering.args[0].length).to.equal(2);
});
});

describe('exiting', () => {
it('should fire callbacks', (done) => {
it('should fire callbacks', () => {
const handleExit = spy();
const handleExiting = spy();

const wrapper = mount(
const { setProps } = render(
<Menu
TransitionProps={{
onExit: handleExit,
onExiting: handleExiting,
onExited: () => {
expect(handleExit.callCount).to.equal(1);
expect(handleExit.args[0].length).to.equal(1);
expect(handleExiting.callCount).to.equal(1);
expect(handleExiting.args[0].length).to.equal(1);
done();
},
}}
{...defaultProps}
anchorEl={document.createElement('div')}
open
/>,
);

wrapper.setProps({
setProps({
open: false,
});

expect(handleExit.callCount).to.equal(1);
expect(handleExit.args[0].length).to.equal(1);
expect(handleExiting.callCount).to.equal(1);
expect(handleExiting.args[0].length).to.equal(1);
});
});
});

it('should pass `classes.paper` to the Popover', () => {
const wrapper = mount(<Menu {...defaultProps} />);
expect(wrapper.find(Popover).props().PaperProps.classes.root).to.equal(classes.paper);
it('should pass `classes.paper` to the Paper', () => {
render(
<Menu
anchorEl={document.createElement('div')}
open
PaperProps={{ 'data-testid': 'paper' }}
/>,
);

expect(screen.getByTestId('paper')).to.have.class(classes.paper);
});

describe('prop: PopoverClasses', () => {
it('should be able to change the Popover style', () => {
const wrapper = mount(<Menu {...defaultProps} PopoverClasses={{ paper: 'bar' }} />);
expect(wrapper.find(Popover).props().classes.paper).to.equal('bar');
render(
<Menu
anchorEl={document.createElement('div')}
open
PaperProps={{ 'data-testid': 'paper' }}
PopoverClasses={{ paper: 'bar' }}
/>,
);

expect(screen.getByTestId('paper')).to.have.class('bar');
});
});

it('should pass onClose prop to Popover', () => {
const fn = () => {};
const wrapper = mount(<Menu {...defaultProps} onClose={fn} />);
expect(wrapper.find(Popover).props().onClose).to.equal(fn);
});
const handleClose = spy();
render(<Menu anchorEl={document.createElement('div')} open onClose={handleClose} />);

fireEvent.keyDown(screen.getByRole('menu'), { key: 'Escape' });

it('should pass anchorEl prop to Popover', () => {
const el = document.createElement('div');
const wrapper = mount(<Menu {...defaultProps} anchorEl={el} />);
expect(wrapper.find(Popover).props().anchorEl).to.equal(el);
expect(handleClose.callCount).to.equal(1);
});

it('should pass through the `open` prop to Popover', () => {
const wrapper = mount(<Menu {...defaultProps} />);
expect(wrapper.find(Popover).props().open).to.equal(false);
wrapper.setProps({ open: true });
expect(wrapper.find(Popover).props().open).to.equal(true);
it('renders its children only when open', () => {
const { setProps } = render(
<Menu anchorEl={document.createElement('div')} open={false}>
<div data-testid="children" />
</Menu>,
);

expect(screen.queryByTestId('children')).to.equal(null);

setProps({ open: true });

expect(screen.getByTestId('children')).not.to.equal(null);
});

describe('list node', () => {
it('should render a MenuList inside the Popover', () => {
const wrapper = mount(<Menu {...defaultProps} className="test-class" data-test="hi" open />);
expect(wrapper.find(Popover).find(MenuList).exists()).to.equal(true);
it('should render a menu inside the Popover', () => {
render(<Menu anchorEl={document.createElement('div')} open data-testid="popover" />);

expect(screen.getByTestId('popover').querySelector('[role="menu"]')).not.to.equal(null);
});
});

it('should open during the initial mount', () => {
const wrapper = mount(
<Menu {...defaultProps} open>
<div role="menuitem" tabIndex={-1}>
one
function MenuItem(props) {
const { autoFocus, children } = props;
return (
<div role="menuitem" tabIndex={-1} data-autofocus={autoFocus}>
{children}
</div>
);
}
render(
<Menu anchorEl={document.createElement('div')} open>
<MenuItem>one</MenuItem>
</Menu>,
);
const popover = wrapper.find(Popover);
expect(popover.props().open).to.equal(true);
expect(wrapper.find('[role="menuitem"]').props().autoFocus).to.equal(true);

expect(screen.getByRole('menuitem')).to.have.attribute('data-autofocus', 'true');
});

it('should not focus list if autoFocus=false', () => {
const wrapper = mount(
<Menu {...defaultProps} autoFocus={false} open>
render(
<Menu anchorEl={document.createElement('div')} autoFocus={false} open>
<div tabIndex={-1} />
</Menu>,
);
const popover = wrapper.find(Popover);
expect(popover.props().open).to.equal(true);
const menuEl = document.querySelector('[role="menu"]');
expect(document.activeElement).not.to.equal(menuEl);
expect(false).to.equal(menuEl.contains(document.activeElement));

expect(screen.getByRole('menu')).not.toHaveFocus();
});

it('should call TransitionProps.onEntering with element if exists', () => {
it('should call TransitionProps.onEntering', () => {
const onEnteringSpy = spy();
const wrapper = mount(
<Menu {...defaultProps} TransitionProps={{ onEntering: onEnteringSpy }} />,
render(
<Menu
anchorEl={document.createElement('div')}
open
TransitionProps={{ onEntering: onEnteringSpy }}
/>,
);
const popover = wrapper.find(Popover);

const elementForHandleEnter = { clientHeight: MENU_LIST_HEIGHT };

popover.props().TransitionProps.onEntering(elementForHandleEnter);
expect(onEnteringSpy.callCount).to.equal(1);
expect(onEnteringSpy.args[0][0]).to.equal(elementForHandleEnter);
});

it('should call TransitionProps.onEntering, disableAutoFocusItem', () => {
const onEnteringSpy = spy();
const wrapper = mount(
render(
<Menu
anchorEl={document.createElement('div')}
disableAutoFocusItem
{...defaultProps}
open
TransitionProps={{ onEntering: onEnteringSpy }}
/>,
);
const popover = wrapper.find(Popover);

const elementForHandleEnter = { clientHeight: MENU_LIST_HEIGHT };

popover.props().TransitionProps.onEntering(elementForHandleEnter);
expect(onEnteringSpy.callCount).to.equal(1);
expect(onEnteringSpy.args[0][0]).to.equal(elementForHandleEnter);
});

it('should call onClose on tab', () => {
function MenuItem(props) {
const { autoFocus, children } = props;

const ref = React.useRef(null);
React.useEffect(() => {
if (autoFocus) {
ref.current.focus();
}
}, [autoFocus]);

return (
<div ref={ref} role="menuitem" tabIndex={-1}>
{children}
</div>
);
}
const onCloseSpy = spy();
const wrapper = mount(
<Menu {...defaultProps} open onClose={onCloseSpy}>
<span>hello</span>
render(
<Menu anchorEl={document.createElement('div')} open onClose={onCloseSpy}>
<MenuItem>hello</MenuItem>
</Menu>,
);
wrapper.find('span').simulate('keyDown', {
key: 'Tab',
});

fireEvent.keyDown(screen.getByRole('menuitem'), { key: 'Tab' });

expect(onCloseSpy.callCount).to.equal(1);
expect(onCloseSpy.args[0][1]).to.equal('tabKeyDown');
});

it('ignores invalid children', () => {
const wrapper = mount(
<Menu {...defaultProps} open>
render(
<Menu anchorEl={document.createElement('div')} open>
{null}
<span role="menuitem">hello</span>
{/* testing conditional rendering */}
Expand All @@ -217,13 +251,13 @@ describe('<Menu />', () => {
</Menu>,
);

expect(wrapper.find('span[role="menuitem"]')).to.have.length(1);
expect(screen.getAllByRole('menuitem')).to.have.length(1);
});

describe('warnings', () => {
it('warns a Fragment is passed as a child', () => {
expect(() => {
mount(
render(
<Menu anchorEl={document.createElement('div')} open>
<React.Fragment />
</Menu>,
Expand Down

0 comments on commit b38c9f9

Please sign in to comment.