1.0.2 • Public • Published


Generate PNG screenshots of jsdom.

  • It extracts the current HTML from document.documentElement.outerHTML
  • Spawns a server that serves the HTML snapshot
  • Takes a PNG screenshot with puppeteer

You can pass options to puppeteer within the launch props of the options, example:

import { toMatchImageSnapshot } from 'jest-image-snapshot';


const visualScreenshotOptions = {
  launch: { headless: true, defaultViewport: {width: 1300, height: 1000} },
  debug: false

test('abc', async () => {
  const screenshot = await generateImage(visualScreenshotOptions);
  expect(screenshot).toMatchImageSnapshot(); // requires package 'jest-image-snapshot'

This package is maintained by @olignyf. This is a fork of jsdom-screenshot by @dferber90.

⚠️ This package is useful for visual regression testing

If you just want visual regression testing that works reliably with different developers, I'd recommend running this package over a CI service. Otherwise you'll run differences due to different operating systems, font-rendering, animations and even GPUs.

This package will only give you the image, you'll have to diff it with something else (like jest-image-snapshot). If you are using Jest, you might be interested in jest-transform-scss, which allows you to compile and load styles into your Jest test setup.

This package can be paired with jest-transform-css and jest-transform-scss and jest-image-snapshot to enable Visual Regression Testing in Jest. See jest-transform-scss for more information.

Table of Contents


npm install jsdom-screenshot --save-dev


You must be in a jsdom environment.

import { generateImage } from "jsdom-screenshot";

// add some content to jsdom (this could also be React or any other library!)
const div = document.createElement("div");
div.innerText = "Hello World";

// take screenshot

Usage in Jest, React & react-testing-library

It is recommended to use this package with jest-image-snapshot and react-testing-library. Use it as together like this:

import React from "react";
import { generateImage, setDefaultOptions } from "jsdom-screenshot";
import { render } from "react-testing-library";
import { SomeComponent } from "<your-code>";

it("should have no visual regressions", async () => {
  render(<SomeComponent />);
  expect(await generateImage()).toMatchImageSnapshot();

You probably want to use a setupTestFrameworkScriptFile like this:

// react-testing-library setup
import "jest-dom/extend-expect";
import "react-testing-library/cleanup-after-each";
// set up visual regression testing
import { toMatchImageSnapshot } from "jest-image-snapshot";
import { setDefaultOptions } from "jsdom-screenshot";

// TravisCI and Linux OS require --no-sandbox to be able to run the tests
  launch: { args: process.env.CI === "true" ? ["--no-sandbox"] : [] }

// give tests more time as taking screenshots takes a while

expect.extend({ toMatchImageSnapshot });



generateImage is the main function you're going to use to take a screenshot of the JSDOM. It supports these options.

Tip: You can use react-testing-library's fireEvent to get the component into any state before taking the screenshot.


options = {
  // Options used to launch Puppeteer (puppeteer.launch(options))
  launch: {},
  // Options used to take a screenshot (puppeteer.screenshot(options))
  screenshot: {},
  // An array of folders containing static files to be served
  serve: ["pubilc", "assets"],
  // Prints the jsdom markup to the console before taking the screenshot
  debug: true,
  // Wait for resources to be loaded before taking the screenshot
  waitUntilNetworkIdle: false,
  // Shortcut to set launch.defaultViewport
  viewport: {},
  // Enables request interception
  intercept: () => {}

launch options are passed to puppeteer.launch([options]), see docs.


screenshot options are passed to page.screenshot([options]), see docs.


serve is an array of strings. You can provide a list of folders to serve statically. This is useful when your component uses assets through relative links like <img src="/party-parrot.gif" />.

In this case, you could provide serve: ["images"] when the images folder at the root of your project (where you launch the tests from) contains party-parrot.gif.


Prints the jsdom markup to the console before taking the screenshot.

See the Debugging JSDOM section below for more information.


This is a shortcut to set options.launch.defaultViewport. options.launch.defaultViewport will take precedence in case both are passed.


A CSS selector can be provided to take a screenshot only of an element found by given selector. This will set puppeteers options.screenshot.clip to match the given element's offset properties (offsetLeft, offsetTop, offsetWidth and offsetHeight).


import React from "react";
import { generateImage, setDefaultOptions } from "jsdom-screenshot";
import { render } from "react-testing-library";
import { SomeComponent } from "<your-code>";

it("should have no visual regressions", async () => {
  // display: "table" prevents div from using full width,
  // so the screenshot would not cover the full width here
    <div data-testid="root" style={{ display: "table" }}>
      <SomeComponent />

  const image = await generateImage({
    targetSelector: "[data-testid=root]"

When set to true, jsdom-screenshot will wait until the network becomes idle (all resources are loaded) before taking a screenshot. You can use this to ensure that all resources are loaded before the screenshot is taken.

It is disabled by default as it adds roughly one second to each screenshot. Use it wisely to avoid slowing down tests unnecessarily. You can mock requests using options.intercept.


When provided, puppeteer's request interception will be enabled. The provided function will be called with the intercepted request.

Activating request interception enables request.abort, request.continue and request.respond methods. This provides the capability to modify network requests that are made by a page.

This can be used to speed up tests by stubbing requests.

  intercept: request => {
    if (request.url().endsWith(".png") || request.url().endsWith(".jpg")) {
      // Blocks some images.
    } else if (request.url().endsWith("/some-big-library.css")) {
      // Fake a response
        status: 200,
        contentType: "text/css",
        body: "html, body { background: red }"
    } else {
      // Call request.continue() for requests which should not be intercepted

See page.setintercept of puppeteer.

Changing viewport

Puppeteer will use an 800x600 viewport by default. You can change the viewport by passing launch.defaultViewport:

  launch: {
    defaultViewport: { width: 1024, height: 768 }

As this is a lot of typing, there is a shortcut for it:

generateImage({ viewport: { width: 1024, height: 768 } });

launch.defaultViewport / viewport also supports deviceScaleFactor, isMobile, hasTouch and isLandscape.

See launch.defaultViewport.


Having to reapply the same options for every test is pretty inconvenient. The setDefaultOptions function can be used to set default options for every generateImage call. Any options passed to the generateImage call will get merged with the specified defaultOptions.

This function can be used to provide global defaults. Note that these defaults are global for all generateImage calls. You should typically only call setDefaultOptions once in your test-setup file.

For example with Jest, you could do the following in your setupTestFrameworkScriptFile file:

import { setDefaultOptions } from "jsdom-screenshot";

  TravisCI requires --no-sandbox to be able to run the tests.
  We the launch options globally here so that they don't need to be
  repeated for every `generateImage` call.
  launch: { args: process.env.CI === "true" ? ["--no-sandbox"] : [] }


The restoreDefaultOptions function restores the default options provided by jsdom-screenshot. See setDefaultOptions for a usage example.


Logs the JSDOM contents to the console. See Debugging for more information.

How it works

High level

jsdom is an emulator of a subset of browser features. jsdom does not have the capability to render visual content, and will act like a headless browser by default. jsdom does not do any layout or rendering ref. We use jsdom to obtain the state of the HTML which we want to take a screenshot of. Consumers can use jsdom to easily get components into the state they want to take a screenshot of. jsdom-screenshot then uses the markup ("the HTML") at that moment (of that state). jsdom-screenshot launches a local webserver and serves the obtained markup as index.html. It further serves assets provided through serve so that local assets are loaded. Then jsdom-screenshot uses puppeteer to take a screenshot take screenshots of that page using headless Google Chrome.


The generateImage function reads the whole markup of jsdom using document.documentElement.outerHTML.

It then starts a local webserver on a random open port to serve the obtained markup as as index.html.

Once the server is read, it launches a puppeteer instance and opens that index.html page. It waits until all resources are loaded (the network becomes idle) before taking a screenshot.

It then returns that screenshot.


Launching puppeteer to take a screenshot takes around 750ms. The rest depends on your application. You should try to mock/stub network requests to keep tests fast (see options.intercept).

You should not go overboard with Visual Regression Tests, but a few errors caught with good Visual Regression Tests will make up for the lost time in tests. Find a good balance that works for you.


Debugging JSDOM

You can print the markup of jsdom which gets passed to puppeteer to take the screenshot by passing debug: true:

generateImage({ debug: true });

You can also import the debug function and call it manually at any point. It will log the markup of jsdom to the console:

import { generateImage, debug } from "jsdom-screenshot";

it("should have no visual regressions", async () => {
  const div = document.createElement("div");
  div.innerText = "Hello World";

  debug(); // <---- prints the jsdom markup to the console

  expect(await generateImage()).toMatchImageSnapshot();

Debugging puppeteer

You can set the following launch in case you need to debug what the page looks like before taking a screenshot:

  launch: {
    // Whether to auto-open a DevTools panel for each tab.
    // If this option is true, the headless option will be set false.
    devtools: true,
    // Whether to run browser in headless mode.
    // Defaults to true unless the devtools option is true.
    headless: false,
    // Slows down Puppeteer operations by the specified amount of milliseconds.
    // Useful so that you can see what is going on.
    slowMo: 500


This is an offshoot of jsdom-screenshot with some stability improvements by @olignyf.

This package was built by massively rewriting component-image. Huge thanks to @corygibbons for laying the foundation of this package.

It was then changed and maintained by @dferber90.

Package Sidebar


npm i visual-screenshot

Weekly Downloads






Unpacked Size

31 kB

Total Files


Last publish


  • olignyf