- Overview of Intern
- Use Intern to test non-AMD script
- Use Intern to test AMD code
- Asynchronous test for web application
- Generate HTML code coverage report
Asynchronous test for web application
Nowadays, nearly all of rich web applications use AJAX to communicate with server-side. But performing the real communication with the server-side goes beyond the scope of unit test, it's the responsibility of FVT or IVT. To follow the best practice of unit test, you'd better mock AJAX calls in your web application to avoid any dependency on the server-side. So this chapter will only introduce the asynchronous testing on the stand-alone client-side without any interaction with server-side. For testing your AJAX calls with real communication with server-side through Intern, please reference here.
Continuing to take the customized toaster as our example, we have missed a test case to test creating the toaster through declarative way. So we need to firstly add our toaster to the test runner's DOM tree and then use "dojo/parser" to parse the DOM tree at runtime. "parser.parse()" is a promise-based method which will return a promise instance that can be used to accomplish our asynchronous test:
Listing 16. Part of the source code of "js/widgetstest/Toaster.js"
Note: In the call back function registered to afterEach, we cleared the DOM tree by ourselves. Not like DOH which will clean up the DOM tree for you automatically by creating the new frame for each test module to make them independent, Intern doesn't provide such a mechanism, so you must reset the DOM tree yourself.
To make "parser.parse()" return a promise, here I added a ContentPane as the parent node of the toaster (parser will auto-require the module, "dijit/layout/ContentPane" here, which is not loaded by your code), so the newly implemented test case will return a promise instance (the AMD "require" API implemented by Dojo is a promise-based interface). Since the implementation of Intern is also based on Dojo, you can just return a promise instance (or any object with "then" function) from the test function to let Intern understand that your test is asynchronous. If the promise is resolved, the test case will pass, otherwise the test case will fail. For our example, the newly added test case will pass, but if you modify strictEqual(toaster.get("message"), "Hello") to strictEqual(toaster.get("message"), "hello"), the callback function registered to "parser.parse()" will throw an error, which will cause the error handler registered by Intern to the returned promise be invoked:
You can also call "this.async()" from within a test function to enable asynchronous testing. You will get a Deferred object from calling this method and Intern will assume your test case is asynchronous. In addition to the standard Promise API, the returned Deferred object also has a "callback()" function which takes a function as its first argument. It's used to wrap a callback function and will resolve the Deferred automatically when it is called, so long as the callback function does not throw any errors. If the callback function throws an error, the Deferred will be rejected with that error instead. It's very common to complete an asynchronous test in that way, so let's migrate the above code to use "this.aync()" and "deferred.callback()" instead:
Listing 17. Part of the source code of "js/widgetstest/Toaster.js"
For more information on writing asynchronous tests with Intern, you can reference this wiki page.
Generate HTML code coverage report
Let's walk into the last but exciting chapter of this tutorial: generating detailed code coverage report in HTML format.
Before we start, we need to do some works to prepare the environment.
For user on Unix-like system, make sure genhtml is installed on your system (type in "genhtml" in command line).
For Windows user, you must firstly install cygwin which provides a simulated Linux environment on Windows and then install genhtml (through rpm package or other sources) on the cygwin.
The rpm for genhtml can be downloaded here.
After installing genhtml, we need to add the "lcov" reporter to "internPhantom.js":
Listing 18. Part of the source code of the modified "js/internPhantom.js"
"lcov" format which is supported by Intern is a standard for GCC testing tool gcov. It can be read by genhtml and generate the code coverage report accordingly. "lcov" can be specified only if running Intern on NoeJS environment (stand-alone or with PhantomJS). Combining what was said in the previous part, working with PhantomJS is the only option to generate code coverage report for DOM-sensitive test, so our next job is to launch Intern with PhantomJS just like in Part 2:
- Open a command line interface, input "phantomjs --webdriver 4444" under the "InternSample/WebContent/js" directory.
- Type in "node intern\runner.js config=internPhantom" under the "InternSample/WebContent/js" directory in a new terminal.
To do so, a new file "lcov.info" will be created in "InternSample/WebContent/js" directory:
For Windows user, you must modify the path of the files for which will be generated the code coverage report in "lcov.info". The reason is that "lcov.info" is created by running Intern on NodeJS environment with PhantomJS on Windows system, so all of the file paths are only valid on Windows. But genhtml will be run on cygwin which is a simulated Linux environment to generate the final code coverage report, so only the valid Linux file paths will be consumed by genhtml on cygwin. Thus the modification for the file paths in "lcov.info" is unavoidable:
Listing 19. Part of the content of the modified "WebContent/js/lcov.info"
Then launch a cygwin terminal (or a shell terminal for Linux), change to "InternSample/WebContent/js" directory and use the following command:
Through the above command, the code coverage report was specified to be generated under the "WebContent/lcovreport" directory. By default, genhtml won't generate branch coverage statistics in the report, so the "--branch-coverage" option is needed. You can use "genhtml --help" or reference here to see all available options.
Now, let's enter the "WebContent/lcovreport" directory and open the "index.html" in your local browser:
From the three figures above, the report gives us the coverage statistics for line, functions and branches and all of which are in green status. Through the source view (figure 3), we can see there is one branch not hit by our test cases and all of the statements covered by our tests are in blue background.
genhtml provides you with many fine-grained options to control its behavior through its configuration file (use "--config-file <FILENAME>" command line option to specify a configuration file). For example, you can customize the thresholds for test status (e.g. red if coverage below 60%, yellow for 60% - 90% and green if above 90%). Details can be referenced here.
In Intern 1.4 (a new release in the near future), a new reporter "lcovhtml" will be supported. This reporter will generate the illustrated HTML files from the collected data directly, so there will be no need to generate HTML report from "lcov.info" through genhtml manually.