Web-page Javascript code-coverage

Getting code-coverage of browser-Javascript files requires interaction with an external tool that does JS-code instrumentation. The most common approach requires that Javascript files be instrumented manually, then upload onto the web-server for the web-page-under-test (WUT). This latter install is a manual step and may be considered intrusive. There are other approaches and various tools for Javascript instrumentation.

About JscovTestUtil

JscovTestUtil came about due to the author’s requirement to test a MCU (micro-computer-unit) that supported WiFi and enough storage to run a small web-server (an ESP8266 device). Manual instrumenting and upload, to the MCU, approach would be time consuming and subject to coordination error, while placing wear-&-tear on the MCU development board.

JSCover was found to meet the requirements needed for automatic instrumentation and no re-upload to the device. So the design and development of JscovTestUtil was instigated.

Using JSCover's proxy-server of on-the-fly instrumentation (which works great), and interacting with Selenium and TestNG, the goal of a seamless flow-through for getting code-coverage of JS-files on a MCU device/web-server works.

Capabilities/features

  • Uses JSCover features to achieve code-coverage.

    Used in a like manner as a user, by executing the tool using Java's ProcessBuilder class.

  • Allows JSCover and/or WebDrivers to be accessed:
    • as "part" of an IDE project's structure (and any source-code-management system), or
    • through an external directory
  • Allow JscovTestUtil code to remain in place at all times, by using an ON/OFF-code-coverage state to be controlled in test script.
  • Launch viewing reports at the end of the test run. With an ON or OFF control as appropriate for user's need.
  • Create WebDriver objects (used with Selenium API actions). There are two forms:
    1. as a WebDriver for code-coverage (webDriverForJSCCoverProxy(..)) [the WebDriver is configured to use JSCover's as a proxy]
    2. as a WebDriver without code-coverage (webDriverForBrowser(..), or webDriverForTypeSameAs(..))
  • 'start', 'store-report' and 'stop' the code-coverage the test script to JSCover interaction, with the ability to be ON or OFF.
  • Placing reports into 'reports' sub-directory of the JSCover directory structure.
    • Provide the ability to store reports into time-stamped sub-directory (repYYYYMMDD_hhmmss_nnn) of 'reports'.
      • Retain N time-stamped sub-directories, where the oldest time-stamped directories are removed from the file-system [storage management].
      • Keep all time-stamped sub-directories.
  • Allow reports to be stored in an explicit sub-directory of 'reports'. This allows the sub-directory to be named as per a machine name, user name, or run version. Depending on how the user configures the use of JscovTestUtil.

JSCover Javascript handling

JscovTestUtil employs JSCover's proxy-server capability to do on-the-fly instrumentation of JS-files.

For all intent-&-purposes, users of JscovTestUtil will find it removes 'manual instrumentation' for the user and subsequent upload to web-servers. The removal of any upload reduces the risk of leaving instrumented JS-files on the web-server by accident.

The proxy-server approach (simplified) allows processing in the following manner:

  • browser/user: Browser requests web-page.
  • proxy-server: Pass through requests to web-server un-filtered.
  • web-server: Respond(s) with file(s) for GET request.
  • proxy-server: Intercept returned GET responses:
    • Pass-through all none Javascript files.
    • Instrument Javascript files as per JSCover processing and then upload to browser.
    • Store original Javascript files for JSCover's reporting system.

JscovTestUtil approach

For JscovTestUtil to work setup/configuration of Selenium V3 and JSCover is needed.

How-to setup/configure is outside this documents scope, and it is assumed users will follow-up with Selenium and/or JSCover documentation.

IDEA: consider using WebDriverManager for Selenium setup/install/configuration management.

The following diagram and its ordered steps is a brief on how JscovTestUtil interacts with hi-level "components" to do Javascript code-coverage in a test Selenium (Java) and @Test framework environment.

Note: JscovTestUnit causes JSCover to generate report-files, however, creation of files is NOT concurrent friendly for parallel processing of @Test testcase-scripts.

JscovTestUnit is a part of the Test environment as a Selenium add-in. It is a library that provides JSCover control interaction methods to simplify/integrate run-time configuration.

missing image
  1. Test setup:
    • Start the proxy-server via ProcessBuilder using the JSCover executable directory.
  2. Testing:
    • Begin executing tests, perform GET-URL action.
      • Proxy-server: passes GET requests directly to web-server.
  3. Web-server:
    • Respond to GET requests and sends files back to requestor (for files: HTML, CSS, JS,...).
    1. Proxy-server: Javascript file(s) are intercepted by JSCover proxy-server and instrumented, if not excluded from instrumentation.
    2. Proxy-server: Instrumented files are forwarded to browser.
    3. Proxy-server: Excluded from instrumentation files are passed-through to the browser.
    4. Proxy-server: Records the original Javascript and retains them in the JSCover reports directory.
  4. Testing:
    • Performs normal test actions via the WebDriver API.
  5. Testing/capture report:
    • invoke a store-report at end of each test, or during testing, or whenever.
    1. Instrumented Javascript: Invoke the jscoverage_report(...) function in the instrumented Javascript. This will cause the script to forward captured results to the proxy-server directly.
    2. Proxy-server: Receives jscoverage JSON and other datum which will be formatted and converted into JSCover report format files.
    3. Proxy-server: Report-files are stored in the JSCover reports directory. JSCover will also merge the data if existing datum files present.
  6. Testing/stop:
    • On testing stop a request to terminate and stop the proxy-server is "called". This will cause a store-report first before stopping the JSCover proxy-server process on the system.

JscovTestUtil has been designed to be integral with IDE's and/or using external locations for resources, the resources being Selenium V3 WebDriver executables and the JSCover program.

Selenium setup is involved, in that WebDriver executables are OS-platform and browser type dependent, JSCover setup has no dependencies as such.

Notes: An assumption is made that users are familiar with Selenium V3's WebDriver setup/configuration.

Also, the user is capable of configuring JSCover as per its setup/configuration arrangements.

Considerations
The user needs to arrange and code the setup/install of JSCover and Selenium WebDrivers for their test environment. JscovTestUtil allows users to access JSCover from directories. However it is prudent to point out that having these directories accessed over the network will restrict the test environment in needing network access.

It is recommended that JSCover and Selenium WebDrivers be installed on a machines local-file-system, thus supporting distributed development and no reliance on a network connection.

IDE integration
An IDE has projects, which provide ease-of-use and collaboration, and when managed via a SCM (source code management) systems like Git, Mercurial,.. have even better share-ability. In addition, all users have access to the same resources within an integral project [great].
IDE JscovTestUtil

The integral support of JscovTestUtil is focused on IDE use, where all the resources are contained within an IDE's project structure. This is done by making JSCover part of the test-environment.

null caption
JSCover IDE integration

"installing" JSCover within the IDE's "user.dir" structure at '<user.dir>/jscoverInst' directory.

Notes

  • The reports directory is introduced by JscovTestUtil as a single location in the JSCover directory to be the "goto" directory for viewing.
  • Additionally, strongly consider making 'reports' ignored in an '.ignore' file if source controlled.
  • Consider removing some directories from JSCover (such as "examples") to reduce the amount of storage used.
Selenium Web-driver install

Selenium V3 WebDrivers are independently provided files for each browser type. There is a specific manner in which they are setup/install to interface with Selenium Java.

The user should refer to Selenium V3 documentation on how this is done.

Also, consider using WebDriverManager class for automatic management for WebDriver's in your test environment. (WebDriverManager is an Apache 2.0 licensed artifact.)

/<user.dir>
+- /jscoverInst
   +- /....
   +- /....
   +- /reports
   :   :
   +--- ....
   +--- ....
   +--- ....
                            
missing image

Structure allows cross-platform of project distribution so shopping around is unnecessary.

CON: Large amount of storage on SCM system

PRO: all users have the same JSCover programs

PRO: single person program update into a repository

PRO: SCM pull provides the driver distribution, vs individual download

PRO: supports distributed SCM development when network is not available

PRO: structure can be reduced in size by removing 'items' e.g. Examples


External JSCover and/or WebDriver resources

Using the external resources capability of JscovTestUtil allows users to choose how-to and where-from resources are accessed. The following diagram outlines access arrangements. It is the users decision to use the external resources arrangement:

  • JSCover can be identified as an external directory for processing the JSCover needs of JscovTestUtil.
missing image

Test scripts

With Selenium and JSCover setup in the test environment, either as identified to a JscovTestUtil object, or with a user's setup, test-cases are written against the JscovTestUtil object.

The setOn... or setOff... should be called before action methods.

Options for JSCover

JSCover has a number of options that may be added to influence the operation of the proxy-server. The key options are those that influence which JS-files are instrumented, or not (see below and/or the JSCover manual).

no name
  • optionAddGeneric(...)
  • optionNoInstrument(...)
  • optionNoInstrumentReg(...)
  • optionOnlyInstrumentReg(...)
  • optionClearAnyAdded()
  • startProxyServer()

    start requires options set before calling
Include/exclude JS-files from instrumentation

JSCover has proxy-server options that are "include/exclude settings" for JS-files that are to be instrumented, while others are excluded.

JscovTestUtil JSCover opt what
optionNoInstrument(...) --no-instrument=URL exclude URL, all other included
optionNoInstrumentReg(...) --no-instrument-reg=URL exclude regex-URL, all other included
optionOnlyInstrumentReg(...) --only-instrument-reg=URL include regex-URL, all other excluded

'Reg/-reg' is a regular expression and should be used when dealing with multiple file patterns to include or exclude from instrumenting.

regex pattern examples

Javascript files are HTTP GET requested due to the <script src... > tag:

      <script type="text/javascript" src="./subdir/file1.js"></script>
      <script type="text/javascript" src="./subdir/fileA1.js"></script>
      <script type="text/javascript" src="./file2.js"></script>
      <script type="text/javascript" src="/file3.js"></script>

The parameter regexOfJsFile is a regex-pattern to match a URL of a JS-file (as it pertains to the above paths). Regex can be involved and deal with complex patterns. For JscovTestUtil very simple patterns are recommended, for more involved patterns consult external Java regex expertise.

Following are simple positive matches (note: '\' needs to be coded as '\\' in Java)

regex to string
regex-pattern ./subdir/file1.js ./subdir/fileA1.js ./file2.js /file3.js simple wildcard coded as

^.*dir.file.*$

X X - - *dir*file*

^.*file.*$

X X X X *file*

^.*file.*1.*$

X X - - *file*1*

^.*file3.*$

- - - X *file3*

^.*file2.*$

- - X - *file2*

^.*2.*$

- - X - *2*

^.*file3\.js$

- - - X *file3.js ^.*file3\\.js$

^.*subdir.*$

X X - - *subdir*

^.*file[32].*$

- - X X

^.*file[321].*$

X - X X

^.*file.*[321].*$

X X X X

^.*file.*[13].*$

X X - X

^.*file.*[3].*$|^.*file.*[1].*$

X X - X regex or condition

^.*file.*[A].*$|^.*file.*[3].*$

^.*file.*[A].*$|^.*file[3].*$

^.*file.*[A].*$|^.*file3.*$

- X - X regex or condition

Start/stop code-coverage

At the beginning and end of testing the following methods need to be used. The start and stop are best placed in @BeforeSuite and @AfterSuite respectively. The store-report may be done anytime (before stop).

If the setOffCodeCoverage is done before testing, most JscovTestUtil methods will be ignored and not do anything.

no name
  • new JscovTestUtil(...)
  • setOnCodeCoverage()
  • setOffCodeCoverage()
  • startProxyServer()
    ::
  • storeJscoverReport(..)
    ::
  • stopProxyServer(..)
    ::

  • restartProxyServer()
The test-case scripts start, store-report and stop methods may remain in place in the scripts all the time. Basically, the invokes are just a return if code-coverage is off.

Testing

Testing is carried out in the normal WebDriver manner on a driver object:
     WebDriver driver = new FirefoxDriver();

     // the normal manner of API actions
     driver.get("http://........);
     WebElement myTestElement = driver.findElement(........);
        ::

However, for code-coverage to work a driver needs to be acquired from a JscovTestUtil object (the object provides the JSCover proxy-server management and provides a WebDriver to use the proxy).

     JscovTestUtil jscovObj = new JscovTestUtil(3129, "base");

     jscovObj.setOnCodeCoverage();
     jscovObj.startProxyServer();

     WebDriver jscovDriver 
         = jscovObj.webDriverForJSCoverProxy(JscovBrowserKind.FIREFOX);

     // the normal manner of API actions
     jscovDriver.get("http://........);
     WebElement myTestElement = jscovDriver.findElement(........);
        ::

NOTE: getting a new driver per test-case is not ideal. Consider defining the driver-for-proxy and start and stop in @BeforeSuite or @AfterSuite setup/configuration methods.

Test scripts testing template example

The following code/class is a template to help a JscovTestUtil user. It may be copied freely and modified (in fact it will need to be modified by a user to work).

Viewing reports (automatically)

Additional methods provide the ability to have a report viewed at the end of the testing.

no name
  • setOnViewReport()
  • setOffViewReport()
  • viewReportDo(..)

View reports (manually)

Viewing the reports manually the user should follow the JSCover at https://tntim96.github.io/JSCover. (Search for 'jscover.server.SimpleWebServer'.)

Hint:
>cd <JSCover directory>
>java -cp target/dist/JSCover-all.jar jscover.server.SimpleWebServer . 8080

Launch a browser with URL 'http://localhost:8080' and follow the sub-directories to the location of the 'reports' directory.

Copyright (c) 2019 dbradley.