user-event: Test fails when using userEvent.type for an input element of type 'number'

Hello, I recently updated the versions for the following dependencies, and I’m now encountering an issue when using userEvent.type to type a number: “@testing-library/jest-dom”: “^5.11.1”, // Used to be 4.2.4 “@testing-library/react”: “^10.4.7”, // Used to be 9.5.0 “@testing-library/user-event”: “^12.0.13”, //Used to be 11.4.2

Here are all of the dependencies in my project: “@testing-library/jest-dom”: “^5.11.1”, “@testing-library/react”: “^10.4.7”, “@testing-library/user-event”: “^12.0.13”, “prop-types”: “^15.7.2”, “react”: “^16.13.1”, “react-dom”: “^16.13.1”, “react-scripts”: “3.4.1”, “react-test-renderer”: “^16.13.1”

Here’s the test that is failing:

let mockCallback;
beforeEach(() => {
  mockCallback = jest.fn();
  render(<CreateProfileForm label='+' callback={mockCallback}/>);
});

it('weight input gets updated as user types in weight', async () => {
  const weightInput = screen.getByLabelText('Weight(lb)');
  await userEvent.type(weightInput, '200');
  expect(weightInput).toHaveAttribute('value', '200');
});

The test fails because the weight input box was not updated:

    expect(element).toHaveAttribute("value", "200") // element.getAttribute("value") === "200"

    Expected the element to have attribute:
      value="200"
    Received:
      value=""

      38 |   const weightInput = screen.getByLabelText('Weight(lb)');
      39 |   await userEvent.type(weightInput, '200');
    > 40 |   expect(weightInput).toHaveAttribute('value', '200');
         |                       ^
      41 | });

The ‘weightInput’ element is of type ‘number’. The issue however, does not occur when using userEvent.type for an input of type ‘text’.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 17 (7 by maintainers)

Most upvoted comments

I ran into this same issue, and managed to get it working by setting { delay: 1 } as the third argument. Probably not ideal, but it’ll do for now

Im having the same issue, with a given form:

 <div
                    class="MuiBox-root MuiBox-root-10 makeStyles-formField-8"
                  >
                    <div
                      class="MuiBox-root MuiBox-root-11"
                    >
                      <label
                        class="makeStyles-root-12 makeStyles-root-13 makeStyles-formFieldLabelRoot-9"
                        for="Account name"
                      >
                        Account name
                      </label>
                      <div
                        class="MuiBox-root MuiBox-root-14"
                      >
                        <div
                          class="MuiInputBase-root OSSTextInput-statusPrimary-15 MuiInputBase-fullWidth Mui-focused"
                        >
                          <input
                            aria-describedby="Account name--helperText"
                            autocomplete="off"
                            class="MuiInputBase-input"
                            data-testid="accountNameField"
                            id="Account name"
                            maxlength="255"
                            name="accountName"
                            placeholder="Ex: Acme Inc."
                            type="text"
                            value=""
                          />
                        </div>
                      </div>
                    </div>

doing the following test:

import { render, fireEvent, screen, within, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';

const user = userEvent.setup();
render(getComponent(props));
const accountName = screen.getByTestId('accountNameField');
await user.type(accountName, 'foo');
    await waitFor(() => {
      expect(screen.getByTestId('accountNameField')).toHaveText('foo');
    });

is not working properly even though I’m using the debug utility function to make sure that the node is present, it returns the correct node, but the input is not filled by a value.

@kentcdodds Correct me if I’m wrong but userEvent still does not handle onChange. For example, I have a input with type number and userEvent.click wouldn’t work for me. I had to resort to using fireEvent.

userEvent uses fireEvent under the code, yet I don’t see any fireEvent.change within userEvent when checking the code. Will there be an update supporting this or maybe I’m just not seeing another way to use userEvent?

I’m my case I’m using findByLabelText but I’ve also tested with getByLabelText as shown here, yet it still doesn’t work.

This is what I have for now, but it would be great to use userEvent instead as I’m using it everywhere else.

const newEvent = {
 ...someDateHere,
  price: 70
};

const priceInput = await findByLabelText('Price');

// doesn't work, a float is expected in Apollo. I wonder if this is related.
// errors is result = ""
// userEvent.type(priceInput, newEvent.price); 

fireEvent.change(priceInput, { target: { value: newEvent.price }}); // works perfect
expect(priceInput.value).toBe(`${newEvent.price}`);

Thanks so much 🙏🏻

i have the same issue with pasword field (using ant design) Other fields it works perfectly.

This is happening to me too. It will take me a long time to make a minimum example that reproduces this, but I can fetch and type default values for all data except for just one field in the form! And it works when it is “text” but fails when it’s a number!!

Correct me if I’m wrong but userEvent still does not handle onChange.

It does handle onChange, but not change. Explained in the the post above.

I’m my case I’m using findByLabelText but I’ve also tested with getByLabelText as shown here, yet it still doesn’t work.

Your test DOES work 😕

v14 also tracks the initial value and automatically triggers the change event when an element loses focus if the value has changed.

Specification and MDN are very clear about when the change event will be triggered.

React facilitates attaching an event handler by creating Synthetic change and input events when input happens in the DOM. Therefore attaching the callback via <input onChange={handleWhatIsInputInTheDom}/> works.

Some third-party libraries attach their handlers directly in the DOM themselves and some users get confused.

I imported the test shared by @jerryfishzz on Codesandbox. It works just fine as the handler is passed per onChange prop. No idea why it was failing for him.

The original issue seems to be resolved by correcting the test to examine the property instead of the attribute.

@robertaird’s solution with delay probably covered an unrelated problem with deferred update per Promise or setTimeout.