I'm trying to test a material ui text field using react-testing-library.
The issue im facing is that in order to test the material ui textField i would have to use this property method
screen.getByLabelText()
which works, however i do not want to display the label on the UI, i want the label to remain hidden, as im already using Material UI <FormLabel>
.
I tried using inputProps and passing data-testId
on the element, using the getByTestId()
method. but i get this error
TestingLibraryElementError: Found multiple elements by: [data-testid="bio"]
(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).
editForm.test.tsx
import "@testing-library/jest-dom";
import React from "react";
import { createMount } from "@material-ui/core/test-utils";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import EditProfileForm from "./editForm";
import { render as testRender, fireEvent, screen, getByText } from "@testing-library/react";
const props = {
handleBio: jest.fn(),
};
describe("<EditProfileForm/>", () => {
let wrapper;
let mount;
beforeEach(() => {
mount = createMount();
wrapper = mount(<EditProfileForm {...props} />);
});
it("should render <EditProfileForm/>", () => {
expect(wrapper).toHaveLength(1);
});
it("calls handleBio on bio TextField change", () => {
const input = screen.getByLabelText("bio");
fireEvent.change(input, { target: { value: "new value" } });
expect(props.handleBio).toHaveBeenCalledTimes(1);
});
});
editForm.tsx
import Button from "@material-ui/core/Button";
import FormGroup from "@material-ui/core/FormGroup";
import FormLabel from "@material-ui/core/FormLabel";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import React from "react";
const EditProfileForm = (props: any) => (
<form onSubmit={props.onSubmit}>
<Typography variant="h5">Edit Profile</Typography>
<FormGroup style={{ padding: "30px 0px" }}>
<FormLabel style={{ display: "block" }}>Bio</FormLabel>
<TextField
id="outlined-name"
style={{
width: "100%",
}}
name="bio"
label="bio"
multiline={true}
rows="3"
defaultValue={props.bio}
onChange={props.handleBio}
margin="normal"
variant="outlined"
/>
</FormGroup>
<Button className="subBtn" variant="outlined" color="primary" type="submit">
Submit
</Button>
</form>
);
export default EditProfileForm;
I was able to resolve this issue by first moving the test function after beforeEach been called.
so it will now be
import "@testing-library/jest-dom";
import React from "react";
import { createMount } from "@material-ui/core/test-utils";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import EditProfileForm from "./editForm";
import { render as testRender, fireEvent, screen, getByText } from "@testing-library/react";
const props = {
handleChange: jest.fn(),
onSubmit: jest.fn(),
bio: "test",
gravatar: "https://i.pravatar.cc/150?img=3",
handleBio: jest.fn(),
handleGravatar: jest.fn(),
};
describe("<EditProfileForm/>", () => {
let wrapper;
let mount;
beforeEach(() => {
mount = createMount();
wrapper = mount(<EditProfileForm {...props} />);
});
// must be called first
it("calls handleBio on bio TextField change", () => {
const input = screen.getByTestId("bio");
fireEvent.change(input, { target: { value: "new value" } });
expect(props.handleBio).toHaveBeenCalledTimes(1);
});
it("should render <EditProfileForm/>", () => {
expect(wrapper).toHaveLength(1);
});
it("should check header title ", () => {
expect(wrapper.find(Typography).at(0)).toHaveLength(1);
expect(
wrapper
.find(Typography)
.at(0)
.text(),
).toContain("Edit Profile");
});
it("should test bio prop", () => {
expect(wrapper.props().bio).toContain("test");
});
it("should test gravtar prop", () => {
const link = "https://i.pravatar.cc/150?img=3";
expect(wrapper.props().gravatar).toContain(link);
});
it("should test handleChange props", () => {
const title = "Test";
expect(
wrapper.props().handleChange({
target: {
value: title,
},
}),
);
expect(props.handleChange).toHaveBeenCalled();
});
it("should test onSubmit prop", () => {
// console.log(wrapper.find(TextField).debug());
const submit = jest.fn();
wrapper.simulate("submit", { submit });
expect(props.onSubmit).toBeCalled();
});
it("should test button click", () => {
const button = wrapper.find(Button);
button.simulate("click");
expect(props.onSubmit).toBeCalled();
});
});
And then passing data-testid as an input prop on text field like this
<TextField
id="outlined-name"
className="bio-test"
style={{
width: "100%",
}}
name="bio"
inputProps={{
"data-testid": "bio",
}}
multiline={true}
rows="3"
defaultValue={props.bio}
onChange={props.handleBio}
margin="normal"
variant="outlined"
/>