mrkeyoor.com_
Tue 01 Sept 17:41 UTC
Webevaluationupdated 26 Aug 2026

jsdom review

jsdom is a JavaScript implementation of many browser DOM and HTML APIs for Node.js. It gives tests, scrapers, and server-side tools a document and window without launching a browser, but it does not render pixels or calculate layout.

+5stars / 7d
Verdict

Our jsdom run installed 254 packages in 11 seconds, then finished with 576 passing and 2 failing tests, so the dependency path is easy while repository verification was imperfect. Use jsdom for DOM-centric unit tests and controlled scraping, especially when launching a browser would be wasteful. Choose a real browser for layout, navigation, screenshots, or untrusted page execution.

We ran it

Lab card: what happened when we ran jsdomScreenshot of jsdom (github.com/jsdom/jsdom)
Install✓ · 11s254 packages · 75 MB
Buildn/ano build script
Tests✗ · 46s576 passed · 2 failed of 578 (mocha)
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)
Repo162266 files~4,194,148 lines of source · 544.2 MB · 2 CI workflows · tests dir

Answers from our run

Does jsdom build from source?

Dependencies installed in 11 seconds (254 packages), and the project has no separate build step. We cloned commit 5ff6562 into a clean Debian container with 3 CPUs and no project-specific setup.

Do jsdom's tests pass?

Not all of them: 576 of 578 passed and 2 failed when we ran the project's own test command (mocha). Some failures need services or credentials a bare container does not have.

Does jsdom have known vulnerabilities in its dependencies?

npm audit found none in the dependency tree at the time of our run.

Who should not use jsdom?

Visual regression, geometry, or CSS layout tests: the README says layout is outside scope and many related properties return zero.

What are the alternatives to jsdom?

Happy DOM, Playwright, LinkeDOM. Our jsdom run installed 254 packages in 11 seconds, then finished with 576 passing and 2 failing tests, so the dependency path is easy while repository verification was imperfect.

Setup4/5Fast install, recent Node required, repository tests had 2 failures
Docs5/5Detailed APIs, security warnings, resource loading, and scope limits
Community5/5Pushed in August 2026 with current issue and pull-request activity
Maturity5/5Long-lived browser emulation with explicit, stable scope boundaries

Discussed on

  1. hnScraping Web Pages With jQuery, Node.js and Jsdom88 points
  2. hnFrom Karma to Mocha, with a taste of jsdom31 points
  3. hnJsdom 4.0 – JavaScript standards-compliant DOM for io.js18 points
  4. hnHappy-DOM: a jsdom alternative that can server side render web components17 points
  5. hnServer-side DOM manipulation in Node.js with JSDOM, JQuery, and Mustache10 points

Who it’s for

JavaScript teams testing DOM code where a full browser would add needless startup and orchestration.
Scraper authors who need standards-aware HTML parsing, cookies, subresources, and script execution under controlled inputs.
Library maintainers who need a configurable browser-like environment inside Node.js.
Test-framework authors who can work within jsdom's documented gaps in layout and navigation.

Who it’s NOT for

Visual regression, geometry, or CSS layout tests: the README says layout is outside scope and many related properties return zero.
Navigation-heavy browser flows: assigning location.href does not create a new window or document.
Processing hostile pages with runScripts: "dangerously": the README warns that scripts can escape to the Node.js host.
Projects pinned below the current Node requirement of ^22.22.2 || ^24.15.0 || >=26.0.0.
Teams that need every browser API today: long-running open requests still cover innerText and URL.createObjectURL().

Setup reality

Our sandbox install succeeded in 11 seconds, adding 254 packages and using 75 MB. The repository checkout was much larger at 162,266 files, about 4,194,148 source lines, and 544.2 MB. There was no build target, so we skipped that step.

The test command ran for 46 seconds and exited 1. Its log ended with 576 passing and 2 failing tests, but the supplied tail did not name either failure, so we cannot assign a cause. The npm audit found 0 known vulnerabilities.

Using jsdom as a dependency is simpler than developing the repository. Current package metadata requires a recent Node release, canvas support is optional, and loading external resources or page scripts must be enabled explicitly. Script execution should be limited to trusted content because the documented sandbox boundary is porous.

jsdom gives Node a document, not a display

A JSDOM instance turns an HTML string into a window and document that ordinary browser-facing JavaScript can inspect. The parser supplies implied HTML structure, resolves URLs against a configured origin, applies cookie rules, and exposes many WHATWG DOM and HTML interfaces. That makes jsdom a natural test dependency for components and libraries whose behavior depends on nodes, events, attributes, or selectors but not on painted pixels. Scrapers also gain a browser-shaped programming model without managing a browser process.

The boundary matters. jsdom does not calculate layout or render a page. Its README names navigation and layout as two major features outside scope, and says many geometry properties return zero. Setting location.href will not replace the window and document as a browser would. The pretendToBeVisual option changes visibility values and enables animation-frame callbacks, but it still does not lay out content. If a passing test depends on element position, viewport paint, or actual navigation, jsdom is the wrong witness.

Script execution is useful only with trusted input

Embedded scripts are disabled by default. Turning on runScripts: "dangerously" lets page code change the document, while resources: "usable" can fetch external scripts, stylesheets, and frames. Those switches make controlled application fixtures much more realistic. They also change the security model. The project warns that its sandbox is not foolproof and determined page code may reach the Node.js environment. Feeding it arbitrary pages under that option can expose the machine running the test or scraper.

Safer jobs can leave embedded scripts off and manipulate the page from the outside. The outside-only mode installs fresh JavaScript globals on the window and permits evaluation in that context. Resource loading is also opt-in and configurable through a dispatcher, interceptors, and user-agent settings. Images need the optional canvas package. These controls are useful because a DOM test and a web crawler should not silently inherit the same network behavior.

What happened when we ran it

Our fresh Node 22 sandbox installed jsdom's repository dependencies in 11 seconds. npm added 254 packages and occupied 75 MB, while the checkout itself contained 162,266 files, roughly 4,194,148 source lines, and used 544.2 MB. The project had no build script or target for our harness to call, so that stage was skipped. npm audit reported 0 known vulnerabilities across the installed tree.

Tests were less tidy. The command ran for 46 seconds and exited with code 1. The log tail reported 576 passing and 2 failing tests, followed by several additional passing-group summaries, but it did not include the failing test names or error messages. That is enough to say the checkout did not pass cleanly in our container. It is not enough to blame Node 22, the container, a missing service, or the project itself.

The repository is unusually large for a package that consumers install with one npm command, which makes contributor setup a different decision from dependency setup. The test scripts initialize web-platform tests through a Git submodule before running several suites. Consumers do not need to reproduce that machinery to create a document, but contributors should budget for a substantial checkout and a test surface much wider than the small public API suggests.

Browser compatibility stops at documented gaps

The README is candid about missing behavior. Asynchronous scripts on uncontrolled pages have no universal "finished" signal, so callers may need application hooks or polling. Navigation emits a not-implemented error instead of opening a new document. Layout getters may return zeros. Open issue 1245 still requests HTMLElement.innerText, while issue 1721 requests URL.createObjectURL() and revokeObjectURL(). Both have remained open for years and were updated in 2026, which is evidence of an active gap rather than a forgotten tracker.

Those gaps affect tool choice more than they affect jsdom's quality. A unit test can often replace layout values or create a fresh JSDOM for each page. A visual regression suite cannot sensibly fake the very rendering behavior it is supposed to verify. Playwright is heavier, but its real browser engines can navigate, paint, take screenshots, and report actual geometry. Happy DOM and LinkeDOM are closer alternatives when the question is which in-process DOM best matches a narrower workload.

Current maintenance is active despite a large queue

The repository was pushed on August 26, 2026, and release v30.0.1 arrived on July 29. That release fixed a getComputedStyle() regression involving calc() and sped up range operations on large documents. The GitHub counter showed 404 open issues and pull requests combined, so it describes a sizable work queue rather than 404 confirmed defects. Recent activity includes changes to CSS grid tracks, media events, script execution, and Blob streams.

One open report describes slower style operations after upgrading to jsdom 27, with maintainers and users still discussing it in August 2026. Treat that report as a reason to measure style-heavy suites before a major upgrade, not as our benchmark. Our lab numbers cover installation and repository tests only. The healthier signal is that code, releases, issues, and pull requests all moved recently, while the README states the hard limits without pretending to be a full browser.

Use it when DOM behavior is the thing under test

jsdom remains the sensible default for Node projects that need parsing and DOM semantics inside a process. Its API is direct, its configuration is unusually well explained, and the security warning around page scripts is hard to miss. Pin a current Node runtime, keep hostile scripts disabled, and separate DOM assertions from browser assertions. If a requirement mentions coordinates, screenshots, page-to-page navigation, or adversarial web content, move that part of the suite to a real browser.

Alternatives

ProjectWhat it isPick it when
Happy DOMA JavaScript browser environment aimed at fast DOM testing in Node runtimes.pick this instead when test speed and its particular API coverage matter more than jsdom compatibility.
Playwright gh↗Browser automation and testing against real Chromium, Firefox, and WebKit engines.pick this instead when layout, navigation, screenshots, or real browser behavior decides correctness.
LinkeDOMA lightweight DOM implementation built for server-side parsing and manipulation.pick this instead when a smaller server-side DOM is enough and broad browser emulation is unnecessary.

What people are saying

  1. [velocity-scout] jsdom/jsdom

Sources

  1. jsdom README
  2. jsdom repository
  3. jsdom v30.0.1 release
  4. jsdom performance regression issue
  5. jsdom innerText issue
  6. jsdom object URL issue

More web reviews

axios · super-productivity · Graphite · fastify · tabler · go-zero · the whole board →