How to use test-id in Material UI Textfield
Asked Answered
M

2

23

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;
Maida answered 27/5, 2020 at 17:44 Comment(0)
M
18

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"
/>
Maida answered 27/5, 2020 at 18:30 Comment(0)
C
-5

If your version doesnt supply inputProps, use it just like

<TextField data-testid=

It's a workaround for the case when MUI version doesnt supply inputProps. Get the Div by testId and then find the input inside it.

Cryosurgery answered 16/5, 2023 at 12:21 Comment(3)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Affiance
Unfortunatelly it add the data-testid on the div wrapper to level upBauer
As I said before, it's a workaround for the case when MUI version doesnt supply inputProps. Get the Div by testId and then find the input inside it.Cryosurgery

© 2022 - 2024 — McMap. All rights reserved.