Test Coverage on
Dynamic Lazy Loading JavaScript

Created by Ricky Chien

Outline


  1. Test coverage
  2. Web application
  3. Background
  4. Issue - Zero coverage
  5. Analysis
  6. Method
  7. Achievement
  8. Conclusion

Test coverage

Why we need test coverage?

For better software quality, we need to write tests

Coverage tool can give us a statistics report after testing

coverage report

Blanket.js - JavaScript test coverage tool

Web application

Web is changing

  • Nowadays, web is going to become more complicated

  • Browser can take more jobs than server

gmail

Web application depends on network

How to reduce network traffic is a significant problem

browser network

Dynamic lazy loading

dynamic loading

Background

Source instrumentation

before instrument

Before

after instrument

After

Coverage mechanism in web

Browser instrumentation / Server instrumentation

Browser instrumentation

Browser instrumentation

code coverage mechanism 1

Server instrumentation

browser test runner

Server instrumentation

code coverage mechanism 2

If situtaion is more complicated

Sometimes we need to interact with a real server

Issue - Zero coverage

In browser instrumentation

Case 1

The report of Firefox OS email app should covered 21 modules

ffox email wrong

Case 2

Prevalent web dynamic lazy loading scheme

lazyload sample Lazyload-sample

Improve browser instrumentation

Make it possible to cover dynamic lazy loading scripts

Analysis

Analyze web script loading approachs

Script Loading - HTML Script



<script src="path-to/script.js"></script>
            

Script Loading - XHR (Ajax)



var xhr = new XMLHttpRequest();
xhr.open('GET', 'path-to/script.js'); // Assign script url
xhr.onload = function (script) {
  eval(script); // Execute script
};
xhr.send();
            

Script Loading - Document.write



document.write('');
            

Script Loading - DOM modification API


appendChild / insertBefore / replaceChild


var script = document.createElement("script");
script.src = url; // Assign script url

document.head.appendChild(script);
parentNode.insertBefore(script, node);
parentNode.replaceChild(script, oldNode);
            

Script Loading - Function Wrapping


Famous module loader library such as RequireJS using syntax :


require(["path-to/script.js"], function() {
  // This function is called after path-to/script.js has loaded.
});
            

Summary

script loading analysis

Method

Solution


  • Most of dynamic lazy loading approachs are through DOM modification API and XHR

  • Overwrite DOM modification API and XHR to detect dynamic lazy loading

  • Tests are needed to ensure our method is safe

Browser Instrumentation Review

code coverage mechanism 1

Solution

solution mechanism

Web application & Web API

api structure

DOM modification API


var originalAppendChild = Element.prototype.appendChild;

Element.prototype.appendChild = function(newElement) {
    // Do our hack here
    return originalAppendChild.apply(this, args); // invoke native method
};
            

XHR API


var originalXHROpen = XMLHttpRequest.prototype.open;

XMLHttpRequest.prototype.open = function(method, url) {
  // Do our hack here
  return originalXHROpen.apply(this, args); // invoke native method
};
            

Achievement

A simple dynamic lazy loading website


Before landing this new feature in Firefox OS

ffos email wrong

After landiong this new feature in Firefox OS

ffos email correct

Conclusion

  • We demonstrated the zero coverage issue

  • Analyzed source instrumentation mechanism and dynamic lazy loading schemes

  • Proposed a solution to overwrite native Web APIs to detect dynamic lazy loading

  • Solution was succssful and safe that even integrated into FFOS testing framework

  • New feature has proposed to Blanket

Thanks for listening