{"id":15642101,"url":"https://github.com/dferber90/jsdom-screenshot","last_synced_at":"2025-05-05T22:18:11.395Z","repository":{"id":39257795,"uuid":"149903940","full_name":"dferber90/jsdom-screenshot","owner":"dferber90","description":"📸 Take screenshots of jsdom with puppeteer","archived":false,"fork":false,"pushed_at":"2022-12-09T03:41:30.000Z","size":220,"stargazers_count":66,"open_issues_count":7,"forks_count":17,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-05T22:18:07.031Z","etag":null,"topics":["jsdom","puppeteer","screenshot","snapshot","visual-regression-testing"],"latest_commit_sha":null,"homepage":"https://github.com/dferber90/visual-regression-testing-example","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dferber90.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-22T18:12:46.000Z","updated_at":"2025-01-12T16:01:38.000Z","dependencies_parsed_at":"2023-01-25T16:32:01.585Z","dependency_job_id":null,"html_url":"https://github.com/dferber90/jsdom-screenshot","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dferber90%2Fjsdom-screenshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dferber90%2Fjsdom-screenshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dferber90%2Fjsdom-screenshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dferber90%2Fjsdom-screenshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dferber90","download_url":"https://codeload.github.com/dferber90/jsdom-screenshot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252584337,"owners_count":21771945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jsdom","puppeteer","screenshot","snapshot","visual-regression-testing"],"created_at":"2024-10-03T11:54:29.016Z","updated_at":"2025-05-05T22:18:11.377Z","avatar_url":"https://github.com/dferber90.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jsdom-screenshot\n\nGenerate screenshots of JSDOM.\n\n\u003e ⚠️ **This package is useful for visual regression testing, but highly experimental.**\n\u003e\n\u003e **If you just want visual regression testing that works, I'd recommend using a CI service for it. Otherwise you'll run differences due to different operating systems, font-rendering, animations and even GPUs.**\n\nThis package will only give you the image, you'll have to diff it with something else (like [`jest-image-snapshot`](https://www.npmjs.com/package/jest-image-snapshot)). If you are using Jest, you might be interested in [jest-transform-css](https://github.com/dferber90/jest-transform-css), which allows you to load styles into your Jest test setup.\n\n\u003e This package can be paired with [jest-transform-css](https://github.com/dferber90/jest-transform-css) and [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot) to enable Visual Regression Testing in Jest. See [jest-transform-css](https://github.com/dferber90/jest-transform-css) for more information.\n\n## Table of Contents\n\n- [Install](#install)\n- [Usage](#usage)\n- [Usage in Jest, React \u0026 react-testing-library](#usage-in-jest-react--react-testing-library)\n- [API](#api)\n  - [`generateImage(options)`](#-generateimage-options--)\n    - [Options](#options)\n      - [`options.launch`](#-optionslaunch-)\n      - [`options.screenshot`](#-optionsscreenshot-)\n      - [`options.serve`](#-optionsserve-)\n      - [`options.debug`](#-optionsdebug-)\n      - [`options.viewport`](#-optionsviewport-)\n      - [`options.targetSelector`](#-optionstargetselector-)\n      - [`options.waitUntilNetworkIdle`](#-optionswaituntilnetworkidle-)\n      - [`options.intercept`](#-optionsintercept-)\n    - [Changing viewport](#changing-viewport)\n  - [`setDefaultOptions(options)`](#-setdefaultoptions-options--)\n  - [`restoreDefaultOptions()`](#-restoredefaultoptions---)\n  - [`debug(element)`](#-debug-element--)\n- [How it works](#how-it-works)\n  - [High level](#high-level)\n  - [Technically](#technically)\n- [Performance](#performance)\n- [Debugging](#debugging)\n  - [Debugging JSDOM](#debugging-jsdom)\n  - [Debugging `puppeteer`](#debugging--puppeteer-)\n- [Attribution](#attribution)\n\n## Install\n\n```\nnpm install jsdom-screenshot --save-dev\n```\n\n## Usage\n\nYou must be in a [jsdom](https://github.com/jsdom/jsdom) environment.\n\n```jsx\nimport { generateImage } from \"jsdom-screenshot\";\n\n// add some content to jsdom (this could also be React or any other library!)\nconst div = document.createElement(\"div\");\ndiv.innerHTML = \"Hello World\";\ndocument.body.appendChild(div);\n\n// take screenshot\ngenerateImage();\n```\n\n## Usage in Jest, React \u0026 react-testing-library\n\nIt is recommended to use this package with [`jest-image-snapshot`](https://www.npmjs.com/package/jest-image-snapshot) and [`react-testing-library`](https://github.com/kentcdodds/react-testing-library). Use it as together like this:\n\n```jsx\nimport React from \"react\";\nimport { generateImage, setDefaultOptions } from \"jsdom-screenshot\";\nimport { render } from \"react-testing-library\";\nimport { SomeComponent } from \"\u003cyour-code\u003e\";\n\nit(\"should have no visual regressions\", async () =\u003e {\n  render(\u003cSomeComponent /\u003e);\n  expect(await generateImage()).toMatchImageSnapshot();\n});\n```\n\nYou probably want to use a `setupTestFrameworkScriptFile` like this:\n\n```jsx\n// react-testing-library setup\nimport \"jest-dom/extend-expect\";\nimport \"react-testing-library/cleanup-after-each\";\n// set up visual regression testing\nimport { toMatchImageSnapshot } from \"jest-image-snapshot\";\nimport { setDefaultOptions } from \"jsdom-screenshot\";\n\n// TravisCI and Linux OS require --no-sandbox to be able to run the tests\n// https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-on-travis-ci\nsetDefaultOptions({\n  launch: { args: process.env.CI === \"true\" ? [\"--no-sandbox\"] : [] }\n});\n\n// give tests more time as taking screenshots takes a while\njest.setTimeout(10000);\n\nexpect.extend({ toMatchImageSnapshot });\n```\n\n## API\n\n### `generateImage(options)`\n\n`generateImage` is the main function you're going to use to take a screenshot of the JSDOM. It supports these options.\n\n\u003e Tip: You can use `react-testing-library`'s `fireEvent` to get the component into any state before taking the screenshot.\n\n#### Options\n\n```jsx\noptions = {\n  // Options used to launch Puppeteer (puppeteer.launch(options))\n  launch: {},\n  // Options used to take a screenshot (puppeteer.screenshot(options))\n  screenshot: {},\n  // An array of folders containing static files to be served\n  serve: [\"public\", \"assets\"],\n  // Prints the jsdom markup to the console before taking the screenshot\n  debug: true,\n  // Wait for resources to be loaded before taking the screenshot\n  waitUntilNetworkIdle: false,\n  // Shortcut to set launch.defaultViewport\n  viewport: {},\n  // Enables request interception\n  intercept: () =\u003e {}\n};\n```\n\n##### `options.launch`\n\n`launch` options are passed to `puppeteer.launch([options])`, see [`docs`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunch).\n\n##### `options.screenshot`\n\n`screenshot` options are passed to `page.screenshot([options])`, see [`docs`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagescreenshotoptions).\n\n##### `options.serve`\n\n`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 `\u003cimg src=\"/party-parrot.gif\" /\u003e`.\n\nIn 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`.\n\n##### `options.debug`\n\nPrints the jsdom markup to the console before taking the screenshot.\n\nSee the [Debugging JSDOM](#debugging-jsdom) section below for more information.\n\n##### `options.viewport`\n\nThis is a shortcut to set `options.launch.defaultViewport`. `options.launch.defaultViewport` will take precedence in case both are passed.\n\n##### `options.targetSelector`\n\nA CSS selector can be provided to take a screenshot only of an element found by given selector. This will set `puppeteer`s `options.screenshot.clip` to match the given element's offset properties (`offsetLeft`, `offsetTop`, `offsetWidth` and `offsetHeight`).\n\nExample:\n\n```jsx\nimport React from \"react\";\nimport { generateImage, setDefaultOptions } from \"jsdom-screenshot\";\nimport { render } from \"react-testing-library\";\nimport { SomeComponent } from \"\u003cyour-code\u003e\";\n\nit(\"should have no visual regressions\", async () =\u003e {\n  // display: \"table\" prevents div from using full width,\n  // so the screenshot would not cover the full width here\n  render(\n    \u003cdiv data-testid=\"root\" style={{ display: \"table\" }}\u003e\n      \u003cSomeComponent /\u003e\n    \u003c/div\u003e\n  );\n\n  const image = await generateImage({\n    targetSelector: \"[data-testid=root]\"\n  });\n  expect(image).toMatchImageSnapshot();\n});\n```\n\n##### `options.waitUntilNetworkIdle`\n\nWhen set to `true`, `jsdom-screenshot` will wait until the network becomes idle (all resources are loaded) before taking a screenshot.\nYou can use this to ensure that all resources are loaded before the screenshot is taken.\n\nIt 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`](#-optionsintercept-).\n\n##### `options.intercept`\n\nWhen provided, `puppeteer`'s request interception will be enabled. The provided function will be called with the intercepted request.\n\nActivating request interception enables [`request.abort`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#requestaborterrorcode), [`request.continue`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#requestcontinueoverrides) and [`request.respond`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#requestrespondresponse) methods. This provides the capability to modify network requests that are made by a page.\n\nThis can be used to speed up tests by stubbing requests.\n\n```jsx\ngenerateImage({\n  intercept: request =\u003e {\n    if (request.url().endsWith(\".png\") || request.url().endsWith(\".jpg\")) {\n      // Blocks some images.\n      request.abort();\n    } else if (request.url().endsWith(\"/some-big-library.css\")) {\n      // Fake a response\n      request.respond({\n        status: 200,\n        contentType: \"text/css\",\n        body: \"html, body { background: red }\"\n      });\n    } else {\n      // Call request.continue() for requests which should not be intercepted\n      request.continue();\n    }\n  }\n});\n```\n\nSee [`page.setintercept`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagesetinterceptvalue) of `puppeteer`.\n\n#### Changing viewport\n\nPuppeteer will use an 800x600 viewport by default. You can change the viewport by passing `launch.defaultViewport`:\n\n```jsx\ngenerateImage({\n  launch: {\n    defaultViewport: { width: 1024, height: 768 }\n  }\n});\n```\n\nAs this is a lot of typing, there is a shortcut for it:\n\n```jsx\ngenerateImage({ viewport: { width: 1024, height: 768 } });\n```\n\n`launch.defaultViewport` / `viewport` also supports `deviceScaleFactor`, `isMobile`, `hasTouch` and `isLandscape`.\n\nSee [`launch.defaultViewport`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunch).\n\n### `setDefaultOptions(options)`\n\nHaving 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`.\n\nThis 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.\n\nFor example with Jest, you could do the following in your `setupTestFrameworkScriptFile` file:\n\n```jsx\nimport { setDefaultOptions } from \"jsdom-screenshot\";\n\n/*\n  TravisCI requires --no-sandbox to be able to run the tests.\n  We the launch options globally here so that they don't need to be\n  repeated for every `generateImage` call.\n*/\nsetDefaultOptions({\n  launch: { args: process.env.CI === \"true\" ? [\"--no-sandbox\"] : [] }\n});\n```\n\n### `restoreDefaultOptions()`\n\nThe `restoreDefaultOptions` function restores the default options provided by `jsdom-screenshot`. See `setDefaultOptions` for a usage example.\n\n### `debug(element)`\n\nLogs the JSDOM contents to the console. See [Debugging](#debugging) for more information.\n\n## How it works\n\n### High level\n\n[`jsdom`](https://github.com/jsdom/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](https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser). 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`](https://github.com/googlechrome/puppeteer/) to take a screenshot take screenshots of that page using headless Google Chrome.\n\n### Technically\n\nThe `generateImage` function reads the whole markup of `jsdom` using `document.documentElement.outerHTML`.\n\nIt then starts a local webserver on a random open port to serve the obtained markup as as `index.html`.\n\nOnce the server is read, it launches a [`puppeteer`](https://github.com/googlechrome/puppeteer/) instance and opens that `index.html` page.\nIt waits until all resources are loaded (the network becomes idle) before taking a screenshot.\n\nIt then returns that screenshot.\n\n## Performance\n\nLaunching `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`](#-optionsintercept-)).\n\nYou should not go overboard with Visual Regression Tests, but a few errors caught with\ngood Visual Regression Tests will make up for the lost time in tests. Find a good balance that works for you.\n\n## Debugging\n\n### Debugging JSDOM\n\nYou can print the markup of `jsdom` which gets passed to `puppeteer` to take the screenshot by passing `debug: true`:\n\n```jsx\ngenerateImage({ debug: true });\n```\n\nYou can also import the `debug` function and call it manually at any point. It will log the markup of `jsdom` to the console:\n\n```jsx\nimport { generateImage, debug } from \"jsdom-screenshot\";\n\nit(\"should have no visual regressions\", async () =\u003e {\n  const div = document.createElement(\"div\");\n  div.innerText = \"Hello World\";\n  document.body.appendChild(div);\n\n  debug(); // \u003c---- prints the jsdom markup to the console\n\n  expect(await generateImage()).toMatchImageSnapshot();\n});\n```\n\n### Debugging `puppeteer`\n\nYou can set the following `launch` in case you need to debug what the page looks like before taking a screenshot:\n\n```jsx\ngenerateImage({\n  launch: {\n    // Whether to auto-open a DevTools panel for each tab.\n    // If this option is true, the headless option will be set false.\n    devtools: true,\n    // Whether to run browser in headless mode.\n    // Defaults to true unless the devtools option is true.\n    headless: false,\n    // Slows down Puppeteer operations by the specified amount of milliseconds.\n    // Useful so that you can see what is going on.\n    slowMo: 500\n  }\n});\n```\n\n## Attribution\n\nThis package was built by massively rewriting [`component-image`](https://github.com/corygibbons/component-image/). Huge thanks to [@corygibbons](https://github.com/corygibbons) for laying the foundation of this package.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdferber90%2Fjsdom-screenshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdferber90%2Fjsdom-screenshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdferber90%2Fjsdom-screenshot/lists"}