Testing a Semantic UI React Input with React Testing Library

jacobwicks

jacobwicks

Posted on December 4, 2019

Testing a Semantic UI React Input with React Testing Library

I'm working on a React project using Semantic UI React. I'm doing unit testing with Jest and React Testing Library (RTL).

A common situation when testing React components is simulating the user entering text into an input component. React Testing Library uses the fireEvent.change() method. fireEvent.change() takes two parameters. The first is the target node, the second is an object with the value.



fireEvent.change(element, { target: { value: 'desired text' } });


Enter fullscreen mode Exit fullscreen mode

The RTL documentation has an example of how to use fireEvent to change the value of an input.

This works for the normal < input /> element. But we are using Semantic UI React's Input component. The Semantic UI React input doesn't just render an input on the page. It renders an input inside a div. Take a look at the difference:

normal input

React Semantic UI Input

Testing a Normal input

The way to set and test a normal input is to render the component, use a query to find the input, then fireEvent.change on the input.



it('can change the value of an input', () => {
const { getByTestId } = render(<input data-testid='input'/>);

const element = getByTestId('input');

fireEvent.change(element, { target: { value: 'desired text' } });

expect(element).toHaveValue('desired text');
});


Enter fullscreen mode Exit fullscreen mode

Doesn't Work on a Semantic UI React Input

That works fine for a normal input. But try this on the Semantic UI Input:



import { Input } from 'semantic-ui-react';

it('can change the value of a Semantic UI React Input', () => {

const { getByTestId } = render(<Input data-testid='input'/>);

const element = getByTestId('input');

fireEvent.change(element, { target: { value: 'desired text' } });

expect(element).toHaveValue('desired text');
});


Enter fullscreen mode Exit fullscreen mode

and you get an error message:
Error Message

  • The given element does not have a value setter

What's going on here?

The query is returning the < div > that Semantic UI React wraps around the input. It's not getting the input itself. fireEvent.change is telling you that you can't set the value of the div, which makes sense. So how do you get hold of the input inside the div?

The Solution

The variable element has a property children, which is an array of the children of element. The input we want to change is the first child of element, so it's element.children[0]. Now you've got the reference to the input you want to change and test.



import { Input } from 'semantic-ui-react';

it('can change the value of a Semantic UI React Input', () => {

const { getByTestId } = render(<Input data-testid='input'/>);

//this is a reference to <div><input/><div/>
const element = getByTestId('input');

//get a reference to the first child of element
const elementInput = element.children[0];

fireEvent.change(elementInput, { target: { value: 'desired text' } });

expect(elementInput).toHaveValue('desired text');
});


Enter fullscreen mode Exit fullscreen mode

That's how you can target and test the Semantic UI React Input component.

Other Methods

You can use other queries to find the inner input in Input directly. If you assign placeholder text to your input, you can use the query getByPlaceholderText to find the inner input by finding the placeholder text. But in my situation I was looking for an Input that didn't have placeholder text.



import { Input } from 'semantic-ui-react';

it('can get the inner input of a Semantic UI React Input directly', () => {

    const placeholderText = 'placeholder';

    const { debug, getByPlaceholderText } = render(
        <div>
        Here's a div with some text content
        Then a Semantic UI React Input component
    <Input data-testid='input' placeholder={placeholderText}/>
    More text here
    </div>
    );
    const element = getByPlaceholderText(placeholderText);

    const newText = 'new text';
    fireEvent.change(element, { target: { value: newText }});
    expect(element).toHaveValue(newText);
});


Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
jacobwicks
jacobwicks

Posted on December 4, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related