How To Mock Jquery .done() So It Executes Correctly With Jest?
Solution 1:
You want that .done
or .error
methods are executed but don't want to actually make a request (btw. i don't know about an .error
method just about .fail
) ? Then i would do the following:
Mock jQuery globally
Create a global mock for jquery inside a __mocks__
directory at the top level of your working directory:
//__mocks__/jquery.js:const jQ = jest.requireActual("jquery");
const ajax = jest.fn(() => {
return jQ.Deferred();
});
exportconst $ = {
...jQ, // We don't want to mock jQuery completely (we might want to alter $.Deferred status)
ajax,
};
exportdefault $;
By putting jquery.js
inside the __mocks__
directory jQuery gets automatically mocked by jest when requested in modules you want to test (well, in this case it gets partially mocked...).
With this setup you can just run your code without making an actual request but normally run .done
and .error
methods and the registered callbacks.
Mock .done and .fail methods
If you don't want to execute the registered callbacks in .done
or .fail
you need to mock them by hand and instead of returning jQ.Deferred()
return a plain javascript object with jest mocks.
Inside a specific test case where you definitly don't want that .done
/.error
calls your registered callback:
// By returning "this" we are able to chain in the way $.ajax("/api", params).done().fail()const jqXHR = {
done: jest.fn().mockImplementation(function () {
returnthis;
}),
fail: jest.fn().mockImplementation(function () {
returnthis;
}),
// some more $.Deferred() methods you want to mock
};
// Overwrite the global $.ajax mock implementation from __mocks__/jquery.js with our custom one
$.ajax.mockImplementation(() => jqXHR)
Simulate success or error
When you want to simulate success or error inside a specific test case again overwrite the global mock implementation:
For success:
// successconst dfd = $.Deferred();
$.ajax.mockImplementation(() => {
return dfd.resolve("success"); // this is what your done callback will receive as argument
});
For error:
// successconst dfd = $.Deferred();
$.ajax.mockImplementation(() => {
return dfd.reject("error"); // this is what your fail callback will receive as argument
});
Note that it does not make sense to assert that .done
or .fail
was called/not called since both are always called because they register the callbacks you put inside them. Only when $.Deferred
resolves or rejects a specific registered callback gets executed, which you then can test.
For better testability w.r.t unit testing you should factor out the anonymous functions from .done
/.error
. Since JavaScript is weird and not like python (which i like more) you cannot easily mock specific functions inside a module under test. So you would need to put them inside a dedicated module and mock this module completely. Then you could just assert that they were called either in success or error case.
It took me a while to figure out how to correctly handle mocking with jquery so i want to share my experience here. Hope this helps...
Post a Comment for "How To Mock Jquery .done() So It Executes Correctly With Jest?"