Skip to content

fireEvent.change doesn't change input value when using [event.target.name] syntax #891

@yoanndw

Description

@yoanndw

EDIT: I found a solution to the problem. It appears to be a bug in the library. See next comment

Hello, I have a component ConditionBlockComponent, with contains 4 inputs: Name, Input, Operation and Value.

import React from "react";

class ConditionBlockComponent extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            name: props.name,
            input: props.input,
            operation: props.operation,
            value: props.value,

            deleteAction: props.deleteAction,
            changeAction: props.changeAction,
        };
    }

    handleChange = (event) => {
        // Compute the property name dynamically
        this.setState({
            [event.target.name]: event.target.value,
            //...this.state,
        });

        // Change logical block state
        const newCond = {
            name: this.state.name,
            input: this.state.input,
            operation: this.state.operation,
            value: this.state.value,
        };

        this.state.changeAction(newCond);
    };

    render() {
        return (
            <div className="block">
                <form>
                    <label htmlFor="cb-name">Name</label>
                    <input
                        type="text"
                        id="cb-name"
                        name="cb-name"
                        value={this.state.name}
                        onChange={this.handleChange}
                    />

                    <label htmlFor="cb-input">Input</label>
                    <input
                        type="text"
                        id="cb-input"
                        name="cb-input"
                        value={this.state.input}
                        onChange={this.handleChange}
                    />

                    <label htmlFor="cb-operation">Operation</label>
                    <input
                        type="text"
                        id="cb-operation"
                        name="cb-operation"
                        value={this.state.operation}
                        onChange={this.handleChange}
                    />

                    <label htmlFor="cb-value">Value</label>
                    <input
                        type="text"
                        id="cb-value"
                        name="cb-value"
                        value={this.state.value}
                        onChange={this.handleChange}
                    />
                </form>

                <button onClick={this.state.deleteAction}>Delete</button>
            </div>
        );
    }
}

export default ConditionBlockComponent;

What I'm trying to do

I'm testing this component with Jest and React Testing Library. Here are the versions:

"dependencies": {
    "@testing-library/react": "11.2.5",
    "jest": "26.6.3",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-scripts": "4.0.0"
},

The first test I attempt to do is to change the input with fireEvent:

import { fireEvent, render, screen } from "@testing-library/react";

import ConditionBlockComponent from "./ConditionBlockComponent.js";

test("Basic render with RTL", () => {
    const changeFunc = (id) => {};
    const deleteFunc = (id) => {};

    let component = render(
        <ConditionBlockComponent
            name=""
            input=""
            operation=""
            value=""
            changeAction={changeFunc}
            deleteAction={deleteFunc}
        />
    );

    let nameInput = screen.getByLabelText(/name/i);
    fireEvent.change(nameInput, { target: { value: "test name" } });
    //console.log(nameInput);

    screen.debug();
});

Problem

The problem is that screen.debug prints this, and the input value didn't change:

    <body>
      <div>
        <div
          class="block"
        >
          <form>
            <label
              for="cb-name"
            >
              Name
            </label>
            <input
              id="cb-name"
              name="cb-name"
              type="text"
              value=""
            />
            <label
              for="cb-input"
            >
              Input
            </label>
            <input
              id="cb-input"
              name="cb-input"
              type="text"
              value=""
            />
            <label
              for="cb-operation"
            >
              Operation
            </label>
            <input
              id="cb-operation"
              name="cb-operation"
              type="text"
              value=""
            />
            <label
              for="cb-value"
            >
              Value
            </label>
            <input
              id="cb-value"
              name="cb-value"
              type="text"
              value=""
            />
          </form>
          <button>
            Delete
          </button>
        </div>
      </div>
    </body>

Reproduction

Here is a reproduction of my problem on codesandbox: https://codesandbox.io/s/react-tests-condition-block-if59s?file=/src/App.js

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions