Hello world
`); console.log(dom.window.document.querySelector("p").textContent); // "Hello world" ``` (Note that jsdom will parse the HTML you pass it just like a browser does, including implied ``, ``, and `` tags.) The resulting object is an instance of the `JSDOM` class, which contains a number of useful properties and methods besides `window`. In general, it can be used to act on the jsdom from the "outside," doing things that are not possible with the normal DOM APIs. For simple cases, where you don't need any of this functionality, we recommend a coding pattern like ```js const { window } = new JSDOM(`...`); // or even const { document } = (new JSDOM(`...`)).window; ``` Full documentation on everything you can do with the `JSDOM` class is below, in the section "`JSDOM` Object API". ## Customizing jsdom The `JSDOM` constructor accepts a second parameter which can be used to customize your jsdom in the following ways. ### Simple options ```js const dom = new JSDOM(``, { url: "https://example.org/", referrer: "https://example.com/", contentType: "text/html", includeNodeLocations: true, storageQuota: 10000000 }); ``` - `url` sets the value returned by `window.location`, `document.URL`, and `document.documentURI`, and affects things like resolution of relative URLs within the document and the same-origin restrictions and referrer used while fetching subresources. It defaults to `"about:blank"`. - `referrer` just affects the value read from `document.referrer`. It defaults to no referrer (which reflects as the empty string). - `contentType` affects the value read from `document.contentType`, as well as how the document is parsed: as HTML or as XML. Values that are not a [HTML MIME type](https://mimesniff.spec.whatwg.org/#html-mime-type) or an [XML MIME type](https://mimesniff.spec.whatwg.org/#xml-mime-type) will throw. It defaults to `"text/html"`. If a `charset` parameter is present, it can affect [binary data processing](#encoding-sniffing). - `includeNodeLocations` preserves the location info produced by the HTML parser, allowing you to retrieve it with the `nodeLocation()` method (described below). It also ensures that line numbers reported in exception stack traces for code running inside ` `); // The script will not be executed, by default: console.log(dom.window.document.getElementById("content").children.length); // 0 ``` To enable executing scripts inside the page, you can use the `runScripts: "dangerously"` option: ```js const dom = new JSDOM(` `, { runScripts: "dangerously" }); // The script will be executed and modify the DOM: console.log(dom.window.document.getElementById("content").children.length); // 1 ``` Again we emphasize to only use this when feeding jsdom code you know is safe. If you use it on arbitrary user-supplied code, or code from the Internet, you are effectively running untrusted Node.js code, and your machine could be compromised. If you want to execute _external_ scripts, included via ` `, { runScripts: "outside-only" }); // run a script outside of JSDOM: dom.window.eval('document.getElementById("content").append(document.createElement("p"));'); console.log(dom.window.document.getElementById("content").children.length); // 1 console.log(dom.window.document.getElementsByTagName("hr").length); // 0 console.log(dom.window.document.getElementsByTagName("p").length); // 1 ``` This is turned off by default for performance reasons, but is safe to enable. Note that in the default configuration, without setting `runScripts`, the values of `window.Array`, `window.eval`, etc. will be the same as those provided by the outer Node.js environment. That is, `window.eval === eval` will hold, so `window.eval` will not run scripts in a useful way. We strongly advise against trying to "execute scripts" by mashing together the jsdom and Node global environments (e.g. by doing `global.window = dom.window`), and then executing scripts or test code inside the Node global environment. Instead, you should treat jsdom like you would a browser, and run all scripts and tests that need access to a DOM inside the jsdom environment, using `window.eval` or `runScripts: "dangerously"`. This might require, for example, creating a browserify bundle to execute as a ` ``` If you do not control the page, you could try workarounds such as polling for the presence of a specific element. For more details, see the discussion in [#640](https://github.com/jsdom/jsdom/issues/640), especially [@matthewkastor](https://github.com/matthewkastor)'s [insightful comment](https://github.com/jsdom/jsdom/issues/640#issuecomment-22216965). ### Unimplemented parts of the web platform Although we enjoy adding new features to jsdom and keeping it up to date with the latest web specs, it has many missing APIs. Please feel free to file an issue for anything missing, but we're a small and busy team, so a pull request might work even better. Some features of jsdom are provided by our dependencies. Notable documentation in that regard includes the list of [supported CSS selectors](https://github.com/dperini/nwsapi/wiki/CSS-supported-selectors) for our CSS selector engine, [`nwsapi`](https://github.com/dperini/nwsapi). Beyond just features that we haven't gotten to yet, there are two major features that are currently outside the scope of jsdom. These are: - **Navigation**: the ability to change the global object, and all other objects, when clicking a link or assigning `location.href` or similar. - **Layout**: the ability to calculate where elements will be visually laid out as a result of CSS, which impacts methods like `getBoundingClientRects()` or properties like `offsetTop`. Currently jsdom has dummy behaviors for some aspects of these features, such as sending a "not implemented" `"jsdomError"` to the virtual console for navigation, or returning zeros for many layout-related properties. Often you can work around these limitations in your code, e.g. by creating new `JSDOM` instances for each page you "navigate" to during a crawl, or using `Object.defineProperty()` to change what various layout-related getters and methods return. Note that other tools in the same space, such as PhantomJS, do support these features. On the wiki, we have a more complete writeup about [jsdom vs. PhantomJS](https://github.com/jsdom/jsdom/wiki/jsdom-vs.-PhantomJS). ## Supporting jsdom jsdom is a community-driven project maintained by a team of [volunteers](https://github.com/orgs/jsdom/people). You could support jsdom by: - [Getting professional support for jsdom](https://tidelift.com/subscription/pkg/npm-jsdom?utm_source=npm-jsdom&utm_medium=referral&utm_campaign=readme) as part of a Tidelift subscription. Tidelift helps making open source sustainable for us while giving teams assurances for maintenance, licensing, and security. - [Contributing](https://github.com/jsdom/jsdom/blob/main/Contributing.md) directly to the project. ## Getting help If you need help with jsdom, please feel free to use any of the following venues: - The [mailing list](https://groups.google.com/group/jsdom) (best for "how do I" questions) - The [issue tracker](https://github.com/jsdom/jsdom/issues) (best for bug reports) - The Matrix room: [#jsdom:matrix.org](https://matrix.to/#/#jsdom:matrix.org)