Skip to main content

About and method

DOMParity is a reference for one question: does this web platform API work in the DOM my tests run on, and how? JavaScript unit and component tests usually run in a DOM implemented in JavaScript rather than in a browser. This site compares four of them, with the same method for every engine: warpdom, happy-dom, jsdom and linkedom. It has two layers: featured APIs, each with behavior checks, and coverage, an automatic existence check of every web API.

Maintainer​

DOMParity is maintained by Sonu Kapoor, who is also the author of warpdom, one of the engines compared here. To keep that from shaping the results, every engine goes through the same probes, the probes and the raw data are public, and the results show where warpdom fails or deviates as plainly as for the others. Tables, cards and data files list warpdom first and mark it "maintainer's engine", so the connection is visible wherever its results are. If a result looks wrong for any engine, please report it (see below).

How the probes work​

Each API has a probe: a small module that says how to tell whether the API exists, and one to four checks. A check is a tiny behavioral test of what the HTML, DOM, CSSOM or other standard says a browser does, with a one-line description and a link to the relevant part of the specification.

  • Each engine creates a window in the way its own documentation describes, with no polyfills:
EngineVersionWindow created with
warpdom0.1.6createWindow({ url: 'http://localhost/' })
happy-dom21.0.3new Window({ url: 'http://localhost/' })
jsdom30.1.3new JSDOM(html, { url: 'http://localhost/', pretendToBeVisual: true })
linkedom0.18.13parseHTML(html)
  • Every engine runs in its own Node.js child process with a timeout, so one engine cannot affect another.
  • Every check gets a fresh window, so checks cannot affect each other. Each check has a time limit of 3 seconds.
  • Thrown errors become the failure text. Console output during a check is captured: an engine that logs "not implemented" (jsdom does this for some methods, through its virtual console) is recorded as such even when the call returns normally.
  • Only the engines' public, documented APIs are used. The probes are black box: no engine's source code was read to write them.
  • Engine order: every table, list, card and data file puts the maintainer's engine (warpdom) first and is otherwise alphabetical (happy-dom, jsdom, linkedom). The order is the only difference: the probes, checks and statuses are the same for every engine.

Statuses​

  • Supported Exists and every check passes.
  • Partial Exists; some checks work, at least one does not.
  • Stub Exists, but no check works (each fails, or the engine reports "not implemented").
  • Missing Not defined.

"Partial" covers both an API that misses one edge of the standard and one that fails most checks; the API page lists which checks fail and what the engine returned. "Stub" means that none of the checks works: the API is defined but does none of what was asked, whether or not the engine says so (an observer that never delivers an entry is a stub even if it reports nothing).

Each check's description names the section of the standard, and for the less obvious ones quotes the step, it relies on.

Coverage: every web API, existence only​

The Coverage section lists every interface and namespace that the Web IDL of the web platform exposes on Window (from @webref/idl, which collects the IDL of all browser specs), with every attribute, method and constant, including those added by partial interfaces and mixins in other specs. Each engine is checked for each of them, in its own process:

  • Interfaces: present, Node.js (present, but the window's value is Node.js's own global), stub (present, but calling a constructor that takes no arguments reports "not implemented"; other constructor errors are shown on the interface page) or missing.
  • Members: present or missing, looked up on the interface prototype (which covers its prototype chain), on the interface object for constants and static members, and on the window itself for Window's own members. Members inherited only from Object.prototype do not count.

Existence is not behavior. A member that is present may do nothing or the wrong thing; only the featured checks test behavior.

Web IDL also lists everything browsers expose, WebGL, WebGPU, WebRTC and Bluetooth included, which no test DOM aims to implement. So every spec is put in one group, by what it matters for in unit tests (spec-groups.json lists every spec and the reason for each group):

  • Test DOM core (shown by default): DOM, all of HTML, CSSOM and CSSOM View, UI, pointer, touch, input and clipboard events, SVG, the observers, URL, Encoding, Fetch, XHR, File API, Streams, Web Crypto, timing and a few more.
  • Rendering and graphics, Media and devices, Platform and app and Other.

Every coverage percentage says which group it is out of; the Coverage page also shows all web APIs together. Specs are grouped whole: HTML is core, so its canvas and media element members count there too.

An interface can be present while some of its members are missing: each interface page lists the missing members per engine, and a featured API page shows the same for the interfaces it is about. A featured API is "missing" when its existence test fails, which can be one missing method on an interface that is defined.

Where the window's value is the very same object as Node.js's own global (for example structuredClone), the table says "Node.js global": the API works because Node.js provides it, not because the engine implements it.

Limits​

  • Browser behavior per the standards, not every edge case. A handful of checks per API cannot cover an API's full behavior. A "supported" here means the checks pass, not that the implementation is complete.
  • The window, not the test runner. Results describe the engine's window. Test environments such as Vitest's and Jest's copy the window's properties onto the test global, and some of them also keep Node.js's globals; so a test can see an API (for example structuredClone, TextEncoder, crypto) that the engine's window lacks, or the other way round.
  • No layout. None of these engines computes layout. Checks avoid asserting sizes and positions, except where the standard's answer does not depend on layout.
  • One version per engine for now. The data format keys results by engine and version so more versions can be added.
  • The Web Platform Tests pass rates come from a separate run (cited on that page) and cover only some areas.

Reporting a wrong result​

Every API page has a "Report a wrong result" link for each engine, which opens a GitHub issue with the engine, version, API, check, expected and observed result filled in; coverage pages have one too. You can also use the wrong result form. Please add a link to the part of the specification that says what should happen.

Data and license​

The raw data is results.json (featured probe results), idl.json (coverage) and wpt.json (Web Platform Tests pass rates and their source). Code is under the MIT license; data under CC BY 4.0.