mocking jquery $.ajax with jest

2020-06-23 05:44发布

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);

3条回答
Anthone
2楼-- · 2020-06-23 05:52

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);
        });
    });
});
查看更多
Ridiculous、
3楼-- · 2020-06-23 05:57

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.

查看更多
家丑人穷心不美
4楼-- · 2020-06-23 06:02

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

 $.ajax = jest.fn().mockImplementation(() => {
        const fakeResponse = {
            id: 1,
            name: "All",
            value: "Dummy Data"
        };
        return Promise.resolve(fakeResponse);
    });
查看更多
登录 后发表回答