Michael Parker
Michael Parker

Reputation: 12966

React's TestUtils.Simulate.keyDown does not work

I have a lot of components in my application that respond to different key presses, and so far, none of my tests that use TestUtils.Simulate.keyDown work at all. It seems like keyDown just plain and simple does not work.

Here's the component I'm trying to test:

description.js

var React = require('react/addons');

var Description = React.createClass({
    render : function () {
        return (
            <div className="description">
                <input type="text" ref="input"/>
            </div>
        )
    }
});

module.exports = Description;

And here is a simple test that is failing:

description-test.js

var React = require('react/addons');
var TestUtils = React.addons.TestUtils;
var expect = require('expect');
var Description = require('../description');

describe('Description', function () {
    it('updates input value on key press', function () {
        var description = TestUtils.renderIntoDocument(<Description/>);
        var input = React.findDOMNode(description.refs.input);
        expect(input.value).toEqual(''); //This passes
        TestUtils.Simulate.keyDown(input, {key : "a"});
        expect(input.value).toEqual('a'); //This fails
    });
});

I have multiple tests that rely on TestUtils.Simulate.keyDown. These tests try a multitude of different keys to press (with Enter being the most prominent), but none of them work. I've tried using keyPress and keyUp, not knowing if those functions even exist at all (shoutout to the surprisingly incomplete documentation).

Am I just using the function incorrectly? Or is there something else wrong here?

I'm using karma-cli via npm to run my tests, if that makes a difference.

Upvotes: 9

Views: 8657

Answers (3)

mario.ecc
mario.ecc

Reputation: 150

Just for the record, I had a very similar problem from a SearchInput component that send the text introduced when hitting enter. I had some tests as follows:

describe('SearchInput functionality,', () => {
  let mockData, component, input;

  beforeAll(() => {
    mockData = {
      searchCriteria: "something",
      emptyString: "       ",
      submitHandler: function(filter) {
        // storing filter param in mockData, it means SearchInput called handler successfully
        mockData.filter = filter;
      }
    };

    spyOn(mockData, 'submitHandler').and.callThrough();

    component = ReactTestUtils.renderIntoDocument(
      <SearchInput placeholder="Search..." onSubmit={mockData.submitHandler}/>
    );
    input = ReactTestUtils.findRenderedDOMComponentWithTag(component, 'input');
  });

  it('user writes a search criteria and hits enter', () => {
    input.value = mockData.searchCriteria;
    ReactTestUtils.Simulate.change(input);
    ReactTestUtils.Simulate.keyDown(input, {key: "Enter", keyCode: 13, which: 13});

    expect(mockData.filter).toEqual(mockData.searchCriteria);
    expect(mockData.submitHandler).toHaveBeenCalled();
    expect(mockData.submitHandler).toHaveBeenCalledTimes(1);
  });
});

And it didn't work.

But after some research I changed the keyDown by keyPress and everything worked perfectly. The reason, enter key was never actually pressed, then input value was never sent and all the assertions failed.

Upvotes: 0

Michael Parker
Michael Parker

Reputation: 12966

I ended up figuring out the issue.

TestUtils.Simulate.keyDown(input, {key : "a"});

This line sends an event to the correct DOM node, but the event data doesn't actually contain a keyCode, which is what the code is looking for. Why the official documentation specifically says you should use key is beyond me.

For it to function correctly, the following modification needed to be made:

TestUtils.Simulate.keyDown(input, {keyCode : 65});

I hope this helps out someone else with a similar issue.

Upvotes: 10

glortho
glortho

Reputation: 13200

TestUtils.Simulate does not actually change values, but rather simulates events on the targeted elements. So if you had an onKeyDown handler on your input, simulating keyDown with TestUtils would let you see if that handler works correctly.

To change the value of the input you can try changing it directly with this.refs.input.value = 'a', or simulate a change event if you have an onChange handler that you want to test:

TestUtils.Simulate.change(input, { target: { value: 'a' } })

Upvotes: 3

Related Questions