Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mocking jquery $.ajax with jest

Using jest how can I test a function that makes an ajax request in my jQuery app and mock its response? My app is not compiled in nodejs and runs straight in a browser. The example on the jest site https://github.com/facebook/jest/tree/master/examples/jquery assumes ajax function is a separate module and the whole app gets compiled with something like webpack. Here is my app:

(function(root) {
    "use strict";
    // if environment is node then import jquery.
    var $ = (typeof module === "object" && module.exports) ? require('jquery') : jQuery;


    function displayUser() {

        var fetchCurrentUser = function (url) {
            var xhr = $.get(url);
            $.when(xhr)
                .done(function(data) {
                    greet(data);
                })
                .fail(function(jqXHR, textStatus, errorThrown) {
                    console.log(errorThrown);
                });
         };

        var greet = function(data) {
            $('#greet').text('Hello ' + data.name);
        }

        fetchCurrentUser('/my/api');

        return {
            fetchCurrentUser: fetchCurrentUser,
            greet: greet
        };
    }

    // Added this conditional so I can test in jest
    if (typeof module === "object" && module.exports) {
        // Node
        module.exports = displayUser();
    } else {
        // Browser (root is window)
        root.displayUser = displayUser();
    }
})(this);
like image 857
Dmitry Avatar asked Jun 15 '17 15:06

Dmitry


3 Answers

Mock $.ajax by using jest.fn().

 $.ajax = jest.fn().mockImplementation(() => {
        const fakeResponse = {
            id: 1,
            name: "All",
            value: "Dummy Data"
        };
        return Promise.resolve(fakeResponse);
    });
like image 153
Vikas Avatar answered Nov 19 '22 07:11

Vikas


create a __mocks__/jquery.js in your project root to mock the jquery node_module. You can invoke functions in your mock jquery. Here's a simple code snippet:

const $ = {
  ajax(xhr) { return this },
  done(fn) {
    if (fn) fn();
    return this;
  },
  fail(fn) {
    if (fn) fn();
    return this;
  }
};
export default $;

And add some expect in your fn to test your real logic.

like image 29
ycdesu Avatar answered Nov 19 '22 07:11

ycdesu


The easiest setup that I have found to test files without using modules and webpack is to manually create the scripts and to add them to window.document. You can reference relative paths directly inside the test file using the fs and path modules. Once you have everything working you can follow ycavatars answer in order to mock the ajax calls.
Here is a simple snippet testing basic jQuery functionality, you can then add new scripts to test the functions in your own file:

const fs = require('fs');
const path = require('path');

const jQueryFile = fs.readFileSync(path.resolve(__dirname, '../relative/path/to/jquery.js'), { encoding: 'utf-8' });
const srcFile = fs.readFileSync(path.resolve(__dirname, '../relative/path/to/yourScript.js'), { encoding: 'utf-8' });

describe('yourScript.js', () => {
    beforeAll(() => {
        // load the scripts
        const scriptEl = window.document.createElement('script');
        scriptEl.textContent = jQueryFile; // add jQuery file
        window.document.body.appendChild(scriptEl);

        const scriptEl2 = window.document.createElement('script');
        scriptEl2.textContent = srcFile; // add your src file
        window.document.body.appendChild(scriptEl2);
    });

    describe('jQuery behaviour', () => {
        test('creates and find elements', () => {
            const $form = $('<form><input type="text" name="query" class="ff_search_input col-xs-11" autocomplete="off" placeholder="Che cosa stai cercando?"></form>');
            const $input = $form.find('input');
            expect($input.length).toBeGreaterThanOrEqual(1);
        });
    });
});
like image 37
Giorgio Tempesta Avatar answered Nov 19 '22 05:11

Giorgio Tempesta