Set Up
Recently, in some client code, I found a lot of jQuery usage. While working with them to build a better test suite, I started with some simple refactoring to make these functions more testable.
The initial code looked like this ...
const testableCode1 = {
test: function() {
return testableCode.runTest();
},
runTest: function() {
var elements = $('.elements');
return elements.length;
}
};
Initial Test Coverage
There were no initial tests. Since we wanted to do some refactoring, we wound up with a simple pattern to allow for refactoring ...
describe('pre-refactor', function() {
it('test before refactor', function() {
var itemToReturn = $('<div></div>');
spyOn(window, '$').and.callFake(function(item) {
if (item === '.elements') {
return itemToReturn;
}
});
var result = testableCode1.test();
expect(result).toEqual(1);
});
});
Refactor
Now, with these tests in place, we can refactor the code with a level of confidence that the functionality will remain the same.
Here's the refactored testableCode code ...
const testableCode2 = {
test: function() {
var elements = $('.elements');
return testableCode2.runTest(elements);
},
runTest: function(items) {
return items.length;
}
};
Rework Tests
Given this refactor, the old test put into place should still pass and we can now write tests without the spyOn being used ...
describe('post-refactor', function() {
it('test before refactor', function() {
var itemToReturn = $('<div></div>');
spyOn(window, '$').and.callFake(function(item) {
if (item === '.elements') {
return itemToReturn;
}
});
var result = testableCode2.test();
expect(result).toEqual(1);
});
it('test after refactor', function() {
var itemToReturn = $('<div>');
var result = testableCode2.runTest(itemToReturn);
expect(result).toEqual(1);
});
});
Conclusion
Now that the code has been refactored, the initial test could easily be removed, making the tests much cleaner and simpler to work with.