mock-dom-resources

Mock DOM Resources

A simple utility for mocking the DOM APIs to simulate browser resource preloading and loading.

Resources are not actually loaded. This is a simulation. The request for a resource (i.e. adding a <script> element to the mock DOM) is matched up to a delayed firing of a load or error event as if the resource had actually loaded.

For fine grained testing purposes, you can configure all aspects of the simulation, including timings, success/error, and even browser capabilities (preloading, script ordered-async, etc).

Note: This is not a spec compliant implementation of a DOM, nor a virtual DOM, nor do we even mock the whole DOM API. The only parts that are mocked are what's minimally necessary for common resource loading simulations.

API

The API is a single function (by default called $DOM) that creates an instance of a mocked DOM (aka window) each time its called. This function is passed an options object to control its behavior.

Note: The numbers shown in the output are randomly generated internal IDs for each DOM element, and as such will vary with each use. To constrain the IDs to predictable incrementing numbers (starting at 1), pass the sequentialIds: true option.

window.performance has only the getEntriesByName(..) method, which takes a URL and returns an array (of only that URL) if that resource URL has been loaded already, false if not.

DOM Features Provided

The following subset of DOM features are mocked:

window

window.onload

window.Event

window.document (and document)

window event: load

document.location (and window.location and location)

document.baseURI

document.head

document.body

document.createElement(..)

document.readyState

document event: DOMContentLoaded

DOM Elements:

appendChild(..)

removeChild(..)

setAttribute(..)

getAttribute(..)

addEventListener(..)

removeEventListener(..)

dispatchEvent(..)

getElementsByTagName(..)

event: load

event: error

window.performance.getEntriesByName(..)

Options

The options that can be passed to $DOM(..):

replaceGlobals (true / false): In the browser, override various globals that are typically used in resource loading, like document.createElement(..) and document.head.appendChild(..). In node, define/replace global.window, global.document, global.performance, global.Event, and global.location. Call $DOM.restoreGlobals() to reset them. Defaults to false.

docReadyState ("loading" / "interactive" / "complete"): Manually sets the initial state of document.readyState. If "loading", the state will emulate transition to "interactive" and then "complete". If "interactive", the state will emulate transition to "complete". When the readyState transitions to "interactive", the DOMContentLoaded event (commonly known as "DOM ready") will be dispatched on document. When the readyState transitions to "complete", the load event (commonly known as window.onload) will be dispatched on the DOM instance (aka window). Defaults to "loading".

docReadyDelay (number): The delay in milliseconds to use between transitions of document.readyState. Defaults to 5.

scriptAsync (true / false): Make <script> elements behave with the "ordered async" capability where the async property defaults to true but if set to false, multiple requested scripts of this same sort will always execute in order of being appended to the DOM. Defaults to true.

location (string): Set the default document.location. Defaults to "https://some.thing/else".

baseURI (string): Set the default document.baseURI property. Defaults to the value of opts.location.

log (function): Specify a function to receive the log messages while performing mock DOM operations. This is useful for test cases where you want to verify that all operations were performed as expected. Set to an empty function to ignore/discard log messages. Defaults to printing to the console as with console.log(..).

error (function): Specify a function to receive any error messages while performing mock DOM operations. Set to an empty function to ignore/discard errors. Defaults to throwing the error as an exception.

resources (array): Specify the resources that should be available for the mock DOM to pretend to load. Each entry in this array is an object including the following specifiers:

url (required): the exact URL that the resource loading request should match. Note: no normalization is done on either these URLs or those requested by mock DOM elements.

cached (optional): boolean that controls if the resource is treated as if it was already fully loaded into the "cache" before any of the DOM processing occurs. Also adds an entry to be exposed by window.performance.getEntriesByName(..). Overrides preloadDelay, preload, loadDelay, and load specifiers for that resource entry.

preloadDelay (optional): integer of milliseconds to emulate as delay for preloading the element (with <link rel=preload> functionality). If provided, must be greater than 0; otherwise, defaults to 10.

preload (optional): boolean that indicates if the preload should be complete successfully (true) or as a loading error (false).

loadDelay (optional): integer of milliseconds to emulate as delay for loading the element (with a <link>, <script>, or <img> element). If provided, must be greater than 0; otherwise, defaults to 10.

load (optional): boolean that indicates if the load should complete successfully (true) or as a loading error (false).

Using with Node.js

You'll most likely use this utility to mock out a DOM for tests in Node.js. To do so, install with npm then require it in your script:

var$DOM=require("mock-dom-resources");

// ..

Builds

The distribution library file (dist/mock-dom.js) comes pre-built with the npm package distribution, so you shouldn't need to rebuild it under normal circumstances.

However, if you download this repository via Git:

The included build utility (scripts/build-core.js) builds (and minifies) dist/mock-dom.js from source. Note: Minification is currently disabled. The build utility expects Node.js version 6+.

To install the build and test dependencies, run npm install from the project root directory.

Because of how npm lifecyle events (currently: npm v4) work, npm install will have the side effect of automatically running the build and test utilities for you. So, no further action should be needed on your part. Starting with npm v5, the build utility will still be run automatically on npm install, but the test utility will not.

To run the build utility with npm:

npm run build

To run the build utility directly without npm:

node scripts/build-core.js

Tests

A comprehensive test suite is included in this repository, as well as the npm package distribution.

You can run the tests in a browser by opening up tests/index.html (requires ES6+ browser environment).

Because of how npm lifecyle events (currently: npm v4) work, npm install will have the side effect of automatically running the build and test utilities for you. So, no further action should be needed on your part. Starting with npm v5, the build utility will still be run automatically on npm install, but the test utility will not.

To run the test utility with npm:

npm test

To run the test utility directly without npm:

node scripts/node-tests.js

Test Coverage

If you have Istanbul already installed on your system (requires v1.0+), you can use it to check the test coverage:

npm run coverage

Then open up coverage/lcov-report/index.html in a browser to view the report.