Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing react component that makes ajax calls using JEST

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... 
       });
})
like image 407
alok mittal Avatar asked Jun 24 '15 10:06

alok mittal


3 Answers

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.

like image 115
Michael Parker Avatar answered Oct 14 '22 09:10

Michael Parker


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.

like image 23
Slithy Toves Avatar answered Oct 14 '22 09:10

Slithy Toves


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.

like image 31
Luke Willis Avatar answered Oct 14 '22 10:10

Luke Willis