I'm building a React app. I use Material-UI version 3.9.3 for my components and Cypress with Cypress Testing Library for my E2E tests.
I have a multiline <TextField /> for which I want to write some tests. When you give the multiline prop to TextField it renders for some reason three textarea tags. One of these has a visibility of hidden, but still contains a value. There is also a visible one containing the value, but further down in the tree.
<TextField
id="outlined-name"
label="Name"
className={classes.textField}
value={this.state.name}
onChange={this.handleChange('name')}
margin="normal"
variant="outlined"
multiline={true}
/>
When I try to target it with the cypress tests, they fail because they say the element isn't visible:
it('inputs some new values but resets them', () => {
cy.visit('/');
cy.getByDisplayValue(/lena/i).type('{backspace}nard');
cy.getByDisplayValue(/inner five/i).select('Distants');
cy.queryByDisplayValue(/lena/i).should('not.exist');
cy.getByDisplayValue(/lennard/i).should('exist');
cy.getByText(/saving/i).should('exist');
cy.getByDisplayValue(/lena/i).should('exist');
cy.queryByDisplayValue(/lennard/i).should('not.exist');
cy.getByText(/saved/i).should('exist');
});
Throws:
Error: CypressError: Timed out retrying: cy.type() failed because this element is not visible:
<textarea aria-hidden="true" class="MuiPrivateTextarea-textarea-221 MuiPrivateTextarea-shadow-222" readonly="" rows="1" tabindex="-1">Lena</textarea>
This element '<textarea.MuiPrivateTextarea-textarea-221.MuiPrivateTextarea-shadow-222>' is not visible because it has CSS property: 'visibility: hidden'
Fix this problem, or use {force: true} to disable error checking.
How can I get this test to pass while still providing reliable information?
You have a couple main options. One option is to primarily leverage getByLabelText to get the element. The label is tied to the appropriate, visible element of the three so it works reliably. Then just verify the value of the textarea rather than using the value to get the element.
Example:
it('inputs some new values but resets them', () => {
cy.visit('https://50wv5x5p1x.codesandbox.io/');
cy.getByLabelText("Name").invoke("val").should("eq", "lena");
cy.getByLabelText("Name").type('{backspace}nard');
cy.getByLabelText("Name").invoke("val").should("eq", "lennard");
});
Another option would be to use version 4 of Material-UI. The first beta version was released today and the first stable release is targeted for mid-May. Textareas have been completely reworked in v4 and no longer render the two hidden textareas, so the following just works:
it('inputs some new values but resets them', () => {
cy.visit('https://6lj3ymm9qw.codesandbox.io/');
cy.getByDisplayValue(/lena/i).type('{backspace}nard');
cy.queryByDisplayValue(/lena/i).should('not.exist');
cy.getByDisplayValue(/lennard/i).should('exist');
});
Try with inputProps:
<TextField
inputProps={{
'id': "outlined-name"
}}
label="Name"
className={classes.textField}
value={this.state.name}
onChange={this.handleChange('name')}
margin="normal"
variant="outlined"
multiline={true}
/>
and then you get it with the id:
cy.get('[id="outlined-name"]')
Related
I have a MUI DateTimePicker in my react app, and I would like to disable the text input so that it is only possible to change the date/time by clicking on the icon and launching the overlays to edit them.
I have tried a few things, such as adding disabled={true} to the renderInput, like this:
renderInput={(params: any) => <TextField
{...params}
disabled={true}
InputProps={{...params.InputProps, disableUnderline: true}}
variant="standard"/>}
Doesn't quite work as expected though. I have tried a lot of other things too, but not sure how that detail would support my question.
Suggestions?
Adding readOnly to the inputProps which will be passed down to the native html input element will do the trick. This also leaves the MUI component in its "normal" visual state.
<TextField
{...params}
disabled={true}
InputProps={{...params.InputProps, disableUnderline: true}}
inputProps={{ ...params.inputProps, readOnly: true }}
variant="standard"
/>
I was able to do exactly what you're asking by just adding the disabled prop to the TextField in renderInput.
<DateTimePicker
label="Date&Time picker"
value={value}
onChange={handleChange}
renderInput={(params) => <TextField {...params} disabled />}
/>
It's possible that you are trying to set the disabled property to true when it just assumes the property being on the component means it is disabled.
I am trying to add a regex pattern in inputProps for validation of Textfield and required but both not working, on click of next the empty or wrong input is also getting entered.
<TextField
id="outlined-basic"
name="s_firstName"
label="First Name"
variant="outlined"
defaultValue={user.s_firstName}
onChange={handleChange}
inputProps={{pattern: "[a-z]"}
required />
Please can you help what wrong is there validation not working?
Your code seems fine, and required is working if you submit the form. It shows which field is required with a mark on the label.
In material ui,
required bool
If true, the label is displayed as required and the input element is required.
You will notice a warning popup as you type in your input.
For validation, you could write your own function with onChange.
const handleValidation = (e) => {
const reg = new RegExp("[a-z]");
setValid(reg.test(e.target.value));
setValue(e.target.value);
};
With the error prop of <Textfield>, you could do something like this,
<TextField
id="outlined-basic"
name="s_firstName"
label="First Name"
variant="outlined"
value={value}
onChange={(e) => handleValidation(e)}
error={!valid}
required={true}
/>
Check out this demo for code of two scenarios.
If you want to show error message then use "helperText"
<TextField
error={value=== ""}
helperText={value=== "" ? 'Please enter a value!' : ' '}
>
I am using material-ui autocomplete ( https://mui.com/components/autocomplete/#free-solo ).
It's working fine, demo is here : https://codesandbox.io/s/0v9v9?file=/demo.tsx
by default Text input is showing autoComplete='off' but i want to change it to autoComplete='new-something' but it's not working and autoComplete='new-something' is showing as parent dev attribute instead of Input
I used this code
<TextField
{...params}
inputProps={{
...params.inputProps,
autoComplete: 'new-something',
}}
/>
But it's not working. In input it's still showing autocomplete="off" as input attribute.
As you can see in the doc https://mui.com/api/text-field/#props there is two props with the same name
inputProps: Attributes applied to the input element.
InputProps: Props applied to the Input element.
For autocomplete attribute you need inputProps
<TextField
{...params}
label="Search input"
InputProps={
...params.InputProps,
type: 'search',
}}
inputProps={{
autocomplete: 'something'
}}
/>
Here a working exanple in the codesanbox https://codesandbox.io/s/freesolo-material-demo-forked-8g2n1?file=/demo.tsx
I have a material-ui Textfield which is amount field
I want to format it so that upon typing, the Textfield has thousands separator and decimal. And bonus, if the input is on the right side (just like in calculators)
e.g.
user types 1000000
textfield should show 1,000,000.00
See code below:
<TextField
variant="outlined"
margin="normal"
required
fullWidth
type="text"
id="debitAmount"
label="Amount"
value={debitAmount}
onChange={(e) => setDebitAmount(e.target.value)}
InputProps={{
classes: { input: classes.textfield1 },
}}
/>
I'm trying to use a library called react-number-format but I'm having a hard time to apply it onto my textfield since the documentation lacks samples
I also tried to use toLocaleString("en") which was effective however the textfield can only show up to 4 numbers and I'm not sure why
Ciao, here a working example. I have used exactly the same example reported in Material-ui docs (simplyfied) using react-number-format, and to show a fixed number of decimal I used toFixed(2).
react-number-format can be integrated with MaterialUI TextField like this:
<NumberFormat
customInput={TextField}
onValueChange={(values) => setNumberFormatState(values.value)}
value={numberFormatState}
// you can define additional custom props that are all forwarded to the customInput e. g.
variant="outlined"
/>
Be aware that I use onValueChange from react-number-format. Here you get the values object which has both the unformatted value and the formatted formattedValue. Most likely you want the bare value in state.
If anyone is coming across this, IMO the #alexanderdavide solution is the simplest and can also be used with the react-currency-format library as well:
import { TextField } from '#mui/material';
<CurrencyFormat
customInput={TextField}
thousandSeparator
prefix="$"
decimalScale={0}
placeholder="Amount"
label="Amount"
onChange={handleNewAmount}
/>
Goal: Get the input values from a material UI component and pass them to an action creator in a handleSubmit function.
<Field name='email'
component={email =>
<TextField
fullWidth
autoComplete='off'
className={classes.textField}
id='email-text-field'
label='Email'
value={email} />
} />
<Field name='password'
component={password =>
<TextField
type='password'
fullWidth
autoComplete='off'
className={classes.textField}
id='password-text-field'
label='Password'
value={password} />
} />
This is how it is being connected to Redux:
#reduxForm({form: 'loginForm', fields: ['email', 'password']})
The warnings I'm getting in my chrome dev tools console is:
Failed prop type: Invalid prop value supplied to TextField.
Warning: Failed prop type: Invalid prop value supplied to Input.`
Additionally, the email field in my login form shows [Object, object}
My guess is that this is happening due to the fact that props are being passed from the
Any ideas on where I've gone wrong?
When you want to use a custom field for Redux-Form, Redux-form gives you access to both props like onChange etc, but also other meta-data (like if the form has been touched or not). These different kinds of props are grouped depending on type.
The interesting part for you is that all the attributes associated with a normal input element (like onChange, value, type) are grouped in props.input. So the argument you call password is actually the whole props object that is sent down to the component. It looks something like this {input:{ value: 'someValue', onChange: somFunction.. etc. etc}, meta: { touched: false, etc. etc.}}.
That means that if you want to use the TextField like you do now, you need to do something like:
<Field name='email'
component={({input}) =>
<TextField
value={input.value}
onChange={input.onChange}
fullWidth
autoComplete='off'
className={classes.textField}
id='email-text-field'
label='Email'
/>
} />
This can get pretty messy, especially if you want to use the meta props, so it's often worth it to break the custom component logic out into its own function, like they do in the example in the docs: https://redux-form.com/7.0.4/examples/material-ui/
You may also be interested to know that for material-ui components, there actually already exists a library that has done most of that manual work for you: redux-form-material-ui.