From 87baf9bad5106b410b7d55380f38a67124ab70f2 Mon Sep 17 00:00:00 2001 From: Gildas Garcia Date: Sat, 15 Jun 2019 14:32:49 +0200 Subject: [PATCH] Migrate SelectInput --- .../ra-ui-materialui/src/input/SelectInput.js | 10 +- .../src/input/SelectInput.spec.js | 299 ++++++++---------- 2 files changed, 147 insertions(+), 162 deletions(-) diff --git a/packages/ra-ui-materialui/src/input/SelectInput.js b/packages/ra-ui-materialui/src/input/SelectInput.js index 90131e86d7e..5c7ff7df959 100644 --- a/packages/ra-ui-materialui/src/input/SelectInput.js +++ b/packages/ra-ui-materialui/src/input/SelectInput.js @@ -4,7 +4,7 @@ import get from 'lodash/get'; import MenuItem from '@material-ui/core/MenuItem'; import { withStyles, createStyles } from '@material-ui/core/styles'; import compose from 'recompose/compose'; -import { addField, translate, FieldTitle } from 'ra-core'; +import { addField, translate, FieldTitle, ValidationError } from 'ra-core'; import ResettableTextField from './ResettableTextField'; const sanitizeRestProps = ({ @@ -209,6 +209,7 @@ export class SelectInput extends Component { options, resource, source, + helperText, ...rest } = this.props; if (typeof meta === 'undefined') { @@ -216,7 +217,7 @@ export class SelectInput extends Component { "The SelectInput component wasn't called within a redux-form . Did you decorate it and forget to add the addField prop to your component? See https://marmelab.com/react-admin/Inputs.html#writing-your-own-input-component for details." ); } - const { touched, error, helperText = false } = meta; + const { touched, error } = meta; return ( + : helperText + } {...options} {...sanitizeRestProps(rest)} onChange={this.handleChange} diff --git a/packages/ra-ui-materialui/src/input/SelectInput.spec.js b/packages/ra-ui-materialui/src/input/SelectInput.spec.js index 93ec9c4f1a1..29de14a8a69 100644 --- a/packages/ra-ui-materialui/src/input/SelectInput.spec.js +++ b/packages/ra-ui-materialui/src/input/SelectInput.spec.js @@ -1,40 +1,34 @@ import React from 'react'; import assert from 'assert'; import { shallow } from 'enzyme'; +import { render, cleanup, fireEvent, within } from 'react-testing-library'; + import { SelectInput } from './SelectInput'; describe('', () => { + afterEach(cleanup); + const defaultProps = { + // We have to specify the id ourselves here because the + // TextInput is not wrapped inside a FormInput + id: 'foo', source: 'foo', + resource: 'bar', meta: {}, - input: {}, + input: { value: '' }, translate: x => x, }; - it('should use a ResettableTextField', () => { - const wrapper = shallow( - - ); - const SelectFieldElement = wrapper.find( - 'translate(WithStyles(ResettableTextField))' - ); - - assert.equal(SelectFieldElement.length, 1); - assert.equal(SelectFieldElement.prop('value'), 'hello'); - }); - it('should use the input parameter value as the initial input value', () => { - const wrapper = shallow( + const { getByLabelText } = render( ); - const SelectFieldElement = wrapper - .find('translate(WithStyles(ResettableTextField))') - .first(); - assert.equal(SelectFieldElement.prop('value'), '2'); + const TextFieldElement = getByLabelText('resources.bar.fields.foo'); + assert.equal(TextFieldElement.getAttribute('value'), '2'); }); it('should render choices as mui MenuItem components', () => { - const wrapper = shallow( + const { getByRole, getByText, queryAllByRole } = render( ', () => { ]} /> ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - assert.equal(MenuItemElements.length, 2); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); - const MenuItemElement2 = MenuItemElements.at(1); - assert.equal(MenuItemElement2.prop('value'), 'F'); - assert.equal(MenuItemElement2.childAt(0).text(), 'Female'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + const options = queryAllByRole('option'); + assert.equal(options.length, 2); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); + + const optionMale = getByText('Female'); + assert.equal(optionMale.getAttribute('data-value'), 'F'); }); it('should render disable choices marked so', () => { - const wrapper = shallow( + const { getByRole, getByText } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement = MenuItemElements.at(1); - assert.equal(!!MenuItemElement.prop('disabled'), false); - const MenuItemElement2 = MenuItemElements.at(2); - assert.equal(MenuItemElement2.prop('disabled'), true); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + const option1 = getByText('Leo Tolstoi'); + assert.equal(option1.getAttribute('aria-disabled'), 'false'); + + const option2 = getByText('Jane Austen'); + assert.equal(option2.getAttribute('aria-disabled'), 'false'); + + const option3 = getByText('System Administrator'); + assert.equal(option3.getAttribute('aria-disabled'), 'true'); }); it('should add an empty menu when allowEmpty is true', () => { - const wrapper = shallow( + const { getByRole, queryAllByRole } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - assert.equal(MenuItemElements.length, 3); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), ''); - assert.equal(MenuItemElement1.children().length, 0); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const options = queryAllByRole('option'); + assert.equal(options.length, 3); + assert.equal(options[0].getAttribute('data-value'), ''); }); it('should add an empty menu with custom value when allowEmpty is true', () => { const emptyValue = 'test'; - const wrapper = shallow( + + const { getByRole, queryAllByRole } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - assert.equal(MenuItemElements.length, 3); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), emptyValue); - assert.equal(MenuItemElement1.children().length, 0); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const options = queryAllByRole('option'); + assert.equal(options.length, 3); + assert.equal(options[0].getAttribute('data-value'), emptyValue); }); it('should not add a falsy (null or false) element when allowEmpty is false', () => { - const wrapper = shallow( + const { getByRole, queryAllByRole } = render( ', () => { ]} /> ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - assert.equal(MenuItemElements.length, 2); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + const options = queryAllByRole('option'); + assert.equal(options.length, 2); }); it('should use optionValue as value identifier', () => { - const wrapper = shallow( + const { getByRole, getByText } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); }); it('should use optionValue including "." as value identifier', () => { - const wrapper = shallow( + const { getByRole, getByText } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); }); it('should use optionText with a string value as text identifier', () => { - const wrapper = shallow( + const { getByRole, getByText } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); }); it('should use optionText with a string value including "." as text identifier', () => { - const wrapper = shallow( + const { getByRole, getByText } = render( ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); }); it('should use optionText with a function value as text identifier', () => { - const wrapper = shallow( + const { getByRole, getByText } = render( choice.foobar} choices={[{ id: 'M', foobar: 'Male' }]} /> ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); }); it('should use optionText with an element value as text identifier', () => { - const Foobar = ({ record }) => {record.foobar}; - const wrapper = shallow( + const Foobar = ({ record }) => ; + + const { getByRole, getByLabelText } = render( } choices={[{ id: 'M', foobar: 'Male' }]} /> ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).type(), Foobar); - assert.deepEqual(MenuItemElement1.childAt(0).prop('record'), { - id: 'M', - foobar: 'Male', - }); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + + const optionMale = getByLabelText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); }); it('should translate the choices by default', () => { - const wrapper = shallow( + const { getByRole, getByText, queryAllByRole } = render( ', () => { translate={x => `**${x}**`} /> ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), '**Male**'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + const options = queryAllByRole('option'); + assert.equal(options.length, 2); + + const optionMale = getByText('**Male**'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); + + const optionMale = getByText('**Female**'); + assert.equal(optionMale.getAttribute('data-value'), 'F'); }); it('should not translate the choices if translateChoice is false', () => { - const wrapper = shallow( + const { getByRole, getByText, queryAllByRole } = render( ', () => { translateChoice={false} /> ); - const MenuItemElements = wrapper.find( - 'WithStyles(ForwardRef(MenuItem))' - ); - const MenuItemElement1 = MenuItemElements.first(); - assert.equal(MenuItemElement1.prop('value'), 'M'); - assert.equal(MenuItemElement1.childAt(0).text(), 'Male'); + const TextFieldElement = getByRole('button'); + fireEvent.click(TextFieldElement); + const options = queryAllByRole('option'); + assert.equal(options.length, 2); + + const optionMale = getByText('Male'); + assert.equal(optionMale.getAttribute('data-value'), 'M'); + + const optionMale = getByText('Female'); + assert.equal(optionMale.getAttribute('data-value'), 'F'); }); it('should displayed helperText if prop is present in meta', () => { - const wrapper = shallow( + const { getByText } = render( ); - const SelectFieldElement = wrapper.find( - 'translate(WithStyles(ResettableTextField))' - ); - assert.equal(SelectFieldElement.prop('helperText'), 'Can i help you?'); + const helperText = getByText('Can i help you?'); + assert.ok(helperText); }); describe('error message', () => { it('should not be displayed if field is pristine', () => { - const wrapper = shallow( - - ); - const SelectFieldElement = wrapper.find( - 'translate(WithStyles(ResettableTextField))' + const { queryAllByText } = render( + ); - assert.equal(SelectFieldElement.prop('helperText'), false); + const error = queryAllByText('Required field.'); + assert.equal(error.length, 0); }); it('should not be displayed if field has been touched but is valid', () => { - const wrapper = shallow( + const { queryAllByText } = render( ); - const SelectFieldElement = wrapper.find( - 'translate(WithStyles(ResettableTextField))' - ); - assert.equal(SelectFieldElement.prop('helperText'), false); + const error = queryAllByText('Required field.'); + assert.equal(error.length, 0); }); it('should be displayed if field has been touched and is invalid', () => { - const wrapper = shallow( + const { getByText } = render( ); - const SelectFieldElement = wrapper.find( - 'translate(WithStyles(ResettableTextField))' - ); - assert.equal( - SelectFieldElement.prop('helperText'), - 'Required field.' - ); + const error = getByText('Required field.'); + assert.ok(error); }); it('should display the error even if helperText is present', () => { - const wrapper = shallow( + const { getByText } = render( ); - const SelectFieldElement = wrapper.find( - 'translate(WithStyles(ResettableTextField))' - ); - assert.equal( - SelectFieldElement.prop('helperText'), - 'Required field.' - ); - }); + const error = getByText('Required field.'); + assert.ok(error); + }); }); });