Unit testing react component that makes ajax calls using JEST

11.3k views Asked by At

I've a react component that makes AJAX call in componentDidMount method. While I try to render it using React.addons.TestUtils, the component gets rendered without making AJAX call. How would I test react component using jest so that it makes AJAX call? Should I need to use phantomJS (or browser like env) as well to provide DOM abilities to react component?

React Component:

return React.createClass({

  componentDidMount : function() {
    $.ajax({
    ... makes http request
    })
  }

  render : function() {
    <div>
      //view logic based on ajax response...
    </div>
  }
});

TestCase:

jest.dontMock(../MyComponent);

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

var TestUtils = React.addons.TestUtils;

var MyComponent = require(../MyComponent);

describe('Sample Test', function(){     

    it('To Render the component', function() {

       var component = <MyComponent />;

       var DOM = TestUtils.renderIntoDocument(component);

       .... // Some other code... 
       });
})
4

There are 4 answers

0
Michael Parker On

I really like Sinon.js and its ability to create a fake server that can respond to ajax requests for testing purposes. You can use it alongside Jest just fine. Here's an example of what it can do for you:

describe('MyComponent', function() {     

    it('successfully makes ajax call and renders correctly', function() {
        //create fake server
        var server = sinon.fakeServer.create();
        //make sure that server accepts POST requests to /testurl
        server.respondWith('POST', '/testurl', 'foo'); //we are supplying 'foo' for the fake response
        //render component into DOM
        var component = <MyComponent />;
        var DOM = TestUtils.renderIntoDocument(component);
        //allow the server to respond to queued ajax requests
        server.respond();
        //expectations go here
        //restore native XHR constructor
        server.restore();
    });

});

I'm not sure how open you are to including another framework in your test suite so feel free to ignore this answer if it does not suit your purposes.

0
Luke Willis On

If you only need to mock http requests, you can also use nock. Sinon is great, but comes with a lot of additional functionality that you may not need.

describe('MyComponent', function() {     
  it('successfully makes ajax call and renders correctly', function() {
    // mocks a single post request to example.com/testurl
    var server = nock('http://example.com')
      .post('/testurl')
      .reply(200, 'foo');

    var component = <MyComponent />;
    var DOM = TestUtils.renderIntoDocument(component);
  });
});

Note that you should probably call nock.cleanAll() after each test so that any failures or lingering mocks don't mess up the next test.

0
Slithy Toves On

Two of the answers involve mocking servers, which can be overkill in some cases. I'll give a brief explanation of the simpler way to do it.

Jest will mock the $.ajax call, which means $.ajax.calls[0][0] will contain the intercepted $.ajax call. You can then access the success or error callbacks of the call and call them directly, eg $.ajax.calls[0][0].success(/* Returned data here. */).

The default setup for Jest automatically mocks everything except things you specifically set to not mock. So let's say you call $.ajax with a success and an error callback. $.ajax.calls is the jest provided array of calls to the $.ajax function. We get the first call by indexing [0], and then the first argument with another [0] ($.ajax usually only has one argument, a JavaScript dictionary/object). This gives us access to the success and error callbacks, allowing us to pass any arbitrary input we expect on those functions and test them.

Then you can proceed normally with testing the results of your ajax call.

0
Bharanidharan K On

Since your $.ajax is mocked by jest, you are not getting the expected behavor, because you are not getting real $.ajax function in runtime.

You need to mock your $.ajax function such that it changes the state of the react component. You can refer this jest post for details. Use

$.ajax.mock.calls