@activelylearn/material-ui
Version:
Material-UI's workspace package
331 lines (292 loc) • 10.9 kB
JavaScript
import React from 'react';
import { assert } from 'chai';
import { spy } from 'sinon';
import keycode from 'keycode';
import { createShallow, createMount } from '../test-utils';
import Menu from '../Menu';
import MenuItem from '../MenuItem';
import SelectInput from './SelectInput';
describe('<SelectInput />', () => {
let shallow;
let mount;
const defaultProps = {
classes: { select: 'select' },
autoWidth: false,
value: 10,
multiple: false,
displayEmpty: false,
IconComponent: 'div',
children: [
<MenuItem key={1} value={10}>
Ten
</MenuItem>,
<MenuItem key={2} value={20}>
Twenty
</MenuItem>,
<MenuItem key={3} value={30}>
Thirty
</MenuItem>,
],
};
before(() => {
shallow = createShallow();
mount = createMount();
});
after(() => {
mount.cleanUp();
});
it('should render a correct top element', () => {
const wrapper = shallow(<SelectInput {...defaultProps} />);
assert.strictEqual(wrapper.name(), 'div');
assert.strictEqual(
wrapper
.find(MenuItem)
.at(0)
.props()['data-value'],
10,
);
});
it('should accept invalid child', () => {
shallow(
<SelectInput {...defaultProps}>
{null}
<MenuItem />
</SelectInput>,
);
});
describe('prop: readOnly', () => {
it('should not trigger any event with readOnly', () => {
const wrapper = shallow(<SelectInput {...defaultProps} readOnly />);
wrapper
.find(`.${defaultProps.classes.select}`)
.simulate('keyDown', { which: keycode('down') });
assert.strictEqual(wrapper.state().open, false);
});
});
describe('prop: MenuProps', () => {
it('should apply additional properties to the Menu component', () => {
const wrapper = shallow(
<SelectInput {...defaultProps} MenuProps={{ transitionDuration: 100 }} />,
);
assert.strictEqual(wrapper.find(Menu).props().transitionDuration, 100);
});
it('should be able to override PaperProps minWidth', () => {
const wrapper = shallow(
<SelectInput {...defaultProps} MenuProps={{ PaperProps: { style: { minWidth: 12 } } }} />,
);
assert.strictEqual(wrapper.find(Menu).props().PaperProps.style.minWidth, 12);
});
});
describe('prop: SelectDisplayProps', () => {
it('should apply additional properties to the clickable div element', () => {
const wrapper = shallow(
<SelectInput {...defaultProps} SelectDisplayProps={{ 'data-test': 'SelectDisplay' }} />,
);
const selectDisplay = wrapper.find('[data-mui-test="SelectDisplay"]');
assert.strictEqual(selectDisplay.props()['data-test'], 'SelectDisplay');
});
});
describe('prop: type', () => {
it('should be hidden by default', () => {
const wrapper = shallow(<SelectInput {...defaultProps} />);
assert.strictEqual(wrapper.find('input').props().type, 'hidden');
});
it('should be able to override it', () => {
const wrapper = shallow(<SelectInput {...defaultProps} type="text" />);
assert.strictEqual(wrapper.find('input').props().type, 'text');
});
});
describe('prop: displayEmpty', () => {
it('should display the selected item even if its value is empty', () => {
const wrapper = shallow(
<SelectInput {...defaultProps} value="" displayEmpty>
<MenuItem value="">Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</SelectInput>,
);
assert.strictEqual(wrapper.find(`.${defaultProps.classes.select}`).text(), 'Ten');
});
});
describe('prop: renderValue', () => {
it('should use the property to render the value', () => {
const renderValue = x => String(-x);
const wrapper = shallow(<SelectInput {...defaultProps} renderValue={renderValue} />);
assert.strictEqual(wrapper.find(`.${defaultProps.classes.select}`).text(), '-10');
});
});
describe('prop: onChange', () => {
let wrapper;
let handleChange;
let instance;
beforeEach(() => {
handleChange = spy();
wrapper = mount(
<SelectInput
{...defaultProps}
onChange={handleChange}
MenuProps={{ transitionDuration: 0 }}
/>,
);
instance = wrapper.instance();
});
it('should call onChange when clicking an item', () => {
wrapper.find(`.${defaultProps.classes.select}`).simulate('click');
assert.strictEqual(wrapper.state().open, true);
const portalLayer = wrapper
.find('Portal')
.instance()
.getMountNode();
portalLayer.querySelectorAll('li')[1].click();
assert.strictEqual(wrapper.state().open, false);
assert.strictEqual(handleChange.callCount, 1);
assert.strictEqual(handleChange.args[0][0].target.value, 20);
});
it('should ignore onBlur the first time the menu is open', () => {
const handleBlur = spy();
wrapper.setProps({ onBlur: handleBlur });
wrapper.find(`.${defaultProps.classes.select}`).simulate('click');
assert.strictEqual(wrapper.state().open, true);
assert.strictEqual(instance.ignoreNextBlur, true);
wrapper.find(`.${defaultProps.classes.select}`).simulate('blur');
assert.strictEqual(handleBlur.callCount, 0);
assert.strictEqual(instance.ignoreNextBlur, false);
wrapper.find(`.${defaultProps.classes.select}`).simulate('blur');
assert.strictEqual(handleBlur.callCount, 1);
});
['space', 'up', 'down'].forEach(key => {
it(`'should open menu when pressed ${key} key on select`, () => {
wrapper
.find(`.${defaultProps.classes.select}`)
.simulate('keyDown', { which: keycode(key) });
assert.strictEqual(wrapper.state().open, true);
assert.strictEqual(instance.ignoreNextBlur, true);
});
});
it('should call handleClose', () => {
wrapper.find(`.${defaultProps.classes.select}`).simulate('click');
assert.strictEqual(wrapper.state().open, true);
const portalLayer = wrapper
.find('Portal')
.instance()
.getMountNode();
const backdrop = portalLayer.querySelector('[data-mui-test="Backdrop"]');
backdrop.click();
assert.strictEqual(wrapper.state().open, false);
});
});
describe('prop: open (controlled)', () => {
class ControlledWrapper extends React.Component {
state = {
open: false,
};
render() {
return (
<SelectInput
{...defaultProps}
open={this.state.open}
onClose={() => this.setState({ open: false })}
onOpen={() => this.setState({ open: true })}
>
<MenuItem onClick={() => this.setState({ open: false })}>close</MenuItem>
</SelectInput>
);
}
}
it('should allow to control closing by passing onClose props', () => {
const wrapper = mount(<ControlledWrapper />);
wrapper.find(`.${defaultProps.classes.select}`).simulate('click');
assert.strictEqual(wrapper.state().open, true);
wrapper.find(MenuItem).simulate('click');
assert.strictEqual(wrapper.state().open, false);
});
it('should work when open is initially true', () => {
const element = (
<SelectInput {...defaultProps} open>
<MenuItem>Hello</MenuItem>
</SelectInput>
);
const wrapper1 = shallow(element, { disableLifecycleMethods: true });
assert.strictEqual(wrapper1.find(Menu).props().open, false);
const wrapper2 = mount(element);
assert.strictEqual(wrapper2.find(Menu).props().open, true);
});
});
describe('prop: autoWidth', () => {
it('should take the anchor width into account', () => {
const wrapper = shallow(<SelectInput {...defaultProps} />);
wrapper.instance().displayNode = { clientWidth: 14 };
wrapper.setProps({});
assert.strictEqual(wrapper.find(Menu).props().PaperProps.style.minWidth, 14);
});
it('should not take the anchor width into account', () => {
const wrapper = shallow(<SelectInput {...defaultProps} autoWidth />);
wrapper.instance().displayNode = { clientWidth: 14 };
wrapper.setProps({});
assert.strictEqual(wrapper.find(Menu).props().PaperProps.style.minWidth, undefined);
});
});
describe('prop: multiple', () => {
it('should take precedence', () => {
const wrapper = shallow(<SelectInput {...defaultProps} disabled tabIndex={0} />);
assert.strictEqual(wrapper.find('[data-mui-test="SelectDisplay"]').props().tabIndex, 0);
});
});
describe('prop: multiple', () => {
it('should serialize multiple select value', () => {
const wrapper = shallow(<SelectInput {...defaultProps} value={[10, 30]} multiple />);
assert.strictEqual(wrapper.find('input').props().value, '10,30');
assert.deepEqual(wrapper.find(MenuItem).map(wrapper2 => wrapper2.props().selected), [
true,
false,
true,
]);
});
it('should throw if non array', () => {
assert.throw(() => {
shallow(<SelectInput {...defaultProps} multiple />);
}, /the `value` property must be an array/);
});
describe('prop: onChange', () => {
let wrapper;
let handleChange;
beforeEach(() => {
handleChange = spy();
wrapper = mount(
<SelectInput
{...defaultProps}
multiple
value={[20, 30]}
name="age"
onChange={handleChange}
MenuProps={{ transitionDuration: 0 }}
/>,
);
});
it('should call onChange when clicking an item', () => {
wrapper.find(`.${defaultProps.classes.select}`).simulate('click');
assert.strictEqual(wrapper.state().open, true);
const portalLayer = wrapper
.find('Portal')
.instance()
.getMountNode();
portalLayer.querySelectorAll('li')[1].click();
assert.strictEqual(wrapper.state().open, true);
assert.strictEqual(handleChange.callCount, 1);
assert.deepEqual(handleChange.args[0][0].target.value, [30]);
assert.deepEqual(handleChange.args[0][0].target.name, 'age');
wrapper.setProps({ value: [30] });
portalLayer.querySelectorAll('li')[0].click();
assert.strictEqual(wrapper.state().open, true);
assert.strictEqual(handleChange.callCount, 2);
assert.deepEqual(handleChange.args[1][0].target.value, [30, 10]);
});
});
describe('prop: autoFocus', () => {
it('should focus select after SelectInput did mount', () => {
mount(<SelectInput {...defaultProps} autoFocus />);
assert.strictEqual(document.activeElement.className, `${defaultProps.classes.select}`);
});
});
});
});