What I want to do: We are writing some tests for an existing Javascript code base that uses jQuery heavily. For the tests, we don't want to have actual HTML elements (HTML fixtures). We'd prefer it if we had a jQuery mock object that does not do anything HTML-related.
My starting point: The most promising approach I found here:
http://eclipsesource.com/blogs/2014/03/27/mocks-in-jasmine-tests/
This creates a helper method that creates a mock by going through the functions of an object and creating a spy for each function:
window.mock = function (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push( key );
return keys.length > 0 ? jasmine.createSpyObj( name || "mock", keys ) : {};
};
Then, if I understand him correctly, he uses that like this (adapted example from his blog post):
var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');
However, this does not work, since el
is an object
and not a function
.
My approach to resolve this problem: I refactored his mock
function to account for the case that constr
is a function
:
mock (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push(key);
var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};
// make sure that if constr is a function (like in the case of jQuery), the mock is too
if (typeof constr === 'function') {
var result2 = result;
result = jasmine.createSpy(name || 'mock-fn');
for (var key in result2)
result[key] = result2[key];
}
return result;
}
However, the second line in the test throws a Cannot read property css of undefined
error:
var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');
Other ideas: I also tried to merge the spy object into jQuery, but that did not help either.
Any ideas? I hope we're not the only ones who do it without HTML fixtures.
Found it. When my version of the
mock
function is set up to return the jQuery object when the jQuery function is invoked, the test works: