User-event: userEvent.type not changing when is a empty string

Created on 28 Oct 2019  路  6Comments  路  Source: testing-library/user-event

I am experimenting this lib and may reached a possible bug. I have been writting a test for Input to check if erases it correctly and found something interesting.

import React from 'react';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

function Input(props) {
  return <input {...props} />;
}

it('should handle input erases', async () => {
    let value = '';
    const onChange = jest.fn(e => {
      value = e.target.value;
    });

    const { getByPlaceholderText, rerender } = render(
      <Input placeholder="Name" value={value} onChange={onChange} />
    );
    const input = getByPlaceholderText('Name');

    userEvent.type(input, 'test');

    // In order to see some "value" changes, we need to rerender the component
    rerender(<Input placeholder="Name" value={value} onChange={onChange} />);

    expect(input).toHaveAttribute('value', 'test');

    // When type empty string simulating an erase test will fail
    userEvent.type(input, '');
    // When using { allAtOnce: true } test will pass
    // userEvent.type(input, '', { allAtOnce: true });

    // In order to see some "value" changes, we need to rerender the component
    rerender(<Input placeholder="Name" value={value} onChange={onChange} />);

    expect(input).toHaveAttribute('value', '');
  });

When you use userEvent.type without { allAtOnce: true } on this case, the Input value will not get any updates. Looking at the type implementation I could identify what is possible wrong.

if (opts.allAtOnce) {
  if (element.readOnly) return;
  fireEvent.input(element, { target: { value: text } });
} else {
  let actuallyTyped = '';
  // If text is a empty string, actuallyTyped will never be used inside fireEvent.input
  for (let index = 0; index < text.length; index++) {
    ...
  }
}

If this is a real bug, I can help fix this! Maybe a naive solution could be adding a extra condition

if (opts.allAtOnce || text === '') 

What do you think guys?

Most helpful comment

Terrific ideia! Adding erase and shortcut will be possible to work better with userEvent abstractions!

I will start (maybe tonight) with erase to close this issue!

All 6 comments

Hmm, yeah, guess, an empty string is a specific case as there isn't really anything to type.
Would you expect to happen in this case? Do you expect backspace's to be triggered and then one character getting removed each time? Or do you expect a Select All + Backspace to remove the contents of the input field?

But yes, I can understand that allAtOnce will fix this issue :)

Feel free to make a PR :)

Hi @weyert ! I understand you and I think you are more than right.

userEvent.type(input, '') is more intuitive to think that you are not typing instead of erasing something.

Thinking about that I would like to introduce a new event called erase.

userEvent.erase(input); // erase to empty string
userEvent.erase(input, { keyPressTimes: 3 }); // trigger event 3 times to erase 3 characters.

Using erase we can create all the correct interactions like what type is doing well.

What do you think about this?

Sounds like a brilliant idea! I think this makes totally sense and feels to match the approach of this library (in my opinion). Typing and Erasing seems like a good combination.

I was thinking to write a helper userEvent.shortcut("{ctrl}{alt}m") to allow to type shortcuts easier. Not sure if it can be part of the type helper method.

Terrific ideia! Adding erase and shortcut will be possible to work better with userEvent abstractions!

I will start (maybe tonight) with erase to close this issue!

I'm going to close this, for now, feel free to propose a PR for erase 馃憤

Was this page helpful?
0 / 5 - 0 ratings