-
Notifications
You must be signed in to change notification settings - Fork 83
Fast JavaScript Integration Tests
This article defines a JavaScript integration test as a test that integrates with the generated DOM and JSON of an application. It is quick because the tests can be run on the file-system (or a simple web-server). AJAX calls are mocked and are not tested end-to-end, however the mock data is generated and allows valid assertions to be made.
This is a topic I haven't seen covered elsewhere, so have decided to write a quick piece on how this technique is useful as part of a web-application development process. I'm interested in any feed-back to improve this article.
The strategy is to use:
- existing application code to generate static web-pages that will run JavaScript tests
- JavaScript, typically jQuery and jQuery Simulate, to generate synthetic events to simulate user interaction
- web-browser automation to run the test, check results and store coverage results
- JSCover to collect coverage
I've used this approach with Java tools and template technologies to achieve greater than 90% code coverage in a matter of seconds - and that 90% can be quickly tested across multiple browsers.
The technique is slower than pure JavaScript tests run on NodeJS, however it does test more and is much quicker than testing JavaScript on a running application server.
Benefits:
- UI development can largely be done without ever starting the application server
- UI tests can be executed much more quickly than on a running application server
- Tests not only JavaScript, but it's interaction with the DOM and generated JSON
- Easily added to your build as part of continuous integration
- Can easily test in multiple browsers
Drawbacks:
-
Execution speed slower than pure JavaScript tests in NodeJS
-
Doesn't test server-side interpretation of data generated by JavaScript (although this could be done)
-
This requires a template language (generally a good idea for your application) such as:
The process outlined:
- Generate the HTML
- Use domain objects to populate your model, then render your view HTML
- Alter the view HTML to load static files if necessary (you may need to change your paths)
- Save the view HTML fo the file-system
- At this point, you can open the HTML file in a browser to verify that it is rendered correctly
- Write your JavaScript tests
- Write a simple JavaScript test
- Alter the view HTML to load the test framework and your test
- To simulate AJAX calls, you can:
- Use your JSON tool (e.g. Jackson) to convert server-side model objects into a
meta-tag
- Write AJAX intercept calls to retrieve the contents from your generated
meta-tag
- Use your JSON tool (e.g. Jackson) to convert server-side model objects into a
- Write your JavaScript test runner
- Use your language of choice to:
- Start JSCover to measure code coverage and serve the static content
- Run the browser automation tool of choice to loop over each generated file to run the tests
- Save the coverage results
- Use your language of choice to:
If you are automating with WebDriver, testing in different browsers is a simple matter of configuration.
Testing in IE usually requires testing in multiple versions of IE. While this can be done using a VM (and this is recommended) many IE version specific bugs can be found using emulation. As part of the test process, the following can be added to the generated HTML to test in, for example, IE8 emulation mode.
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8"/>
<meta name="getDataJson1" content="{"data":{"id":1}}"/>
var ajaxRequests = [];
$(document).ready(function () {
$.ajax = function (params) {
ajaxRequests.push(params);
var jsonString, match;
//console.log(params.url);
match = params.url.match(/\/data\/([^\/]*)\/getData.json$/);
if (match) {
jsonString = $("meta[name=getDataJson" + match[1] + "]").attr("content");
//console.log(jsonString);
//try {
params.success(JSON.parse(jsonString));
//}
//catch(e) {}
return;
}
};
});