Testing a Semantic UI React Input with React Testing Library
Tags: javascript, react, testing
Published: 2019-12-04 21:27:18

I'm working on a React project using [Semantic UI React](https://react.semantic-ui.com/). I'm doing unit testing with [Jest](https://jestjs.io/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro) \(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.
```javascript
fireEvent.change(element, { target: { value: 'desired text' } });
```

The RTL documentation has an [example of how to use fireEvent to change the value of an input](https://testing-library.com/docs/example-input-event#__docusaurus).

This works for the normal < input /> element. But we are using Semantic UI React's [Input](https://react.semantic-ui.com/elements/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](https://thepracticaldev.s3.amazonaws.com/i/l2mlh3hcjwfwd3zclwck.png)

![React Semantic UI Input](https://thepracticaldev.s3.amazonaws.com/i/94rl94eji66w14ke5oae.png)


###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.

```javascript
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');
});
```

###Doesn't Work on a Semantic UI React Input
That works fine for a normal input. But try this on the Semantic UI Input:
```javascript
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');
});
```
 and you get an error message:
![Error Message](https://thepracticaldev.s3.amazonaws.com/i/h91dozv2c6oo07a4i1vp.png)

* 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.

```javascript
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');
});
```

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.

```javascript
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);
});
```