What is @percy/dom?
@percy/dom is an npm package designed to facilitate visual testing by capturing and serializing the DOM (Document Object Model) of web pages. This allows for visual comparisons to be made between different states of a web page, ensuring that changes do not introduce visual regressions.
What are @percy/dom's main functionalities?
Serialize DOM
This feature allows you to serialize the current state of the DOM into a string. This serialized DOM can then be used for visual comparisons.
const percyDOM = require('@percy/dom');
const domSnapshot = percyDOM.serialize();
console.log(domSnapshot);
Capture Specific Elements
This feature allows you to capture and serialize only specific elements within the DOM by specifying a CSS selector. This is useful for focusing on particular parts of a web page.
const percyDOM = require('@percy/dom');
const domSnapshot = percyDOM.serialize({ scope: '#main-content' });
console.log(domSnapshot);
Exclude Elements
This feature allows you to exclude certain elements from the DOM snapshot by specifying CSS selectors. This is useful for ignoring dynamic or irrelevant parts of a web page.
const percyDOM = require('@percy/dom');
const domSnapshot = percyDOM.serialize({ ignore: ['.ad-banner', '.tracking-pixel'] });
console.log(domSnapshot);
Other packages similar to @percy/dom
puppeteer
Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It can be used for taking screenshots, generating PDFs, and capturing the DOM. Unlike @percy/dom, Puppeteer is a more general-purpose tool for browser automation and not specifically focused on visual testing.
cypress
Cypress is a JavaScript end-to-end testing framework that allows you to write tests for your web applications. It includes features for capturing screenshots and recording videos of tests. While it is not specifically designed for visual testing like @percy/dom, it can be extended with plugins to achieve similar functionality.
selenium-webdriver
Selenium WebDriver is a tool for automating web application testing. It provides APIs to interact with web browsers and can be used to capture screenshots and the DOM. However, it is more complex and less focused on visual testing compared to @percy/dom.
@percy/dom
Serializes a document's DOM into a DOM string suitable for re-rendering.
Usage
ES6 imports
import serializeDOM from '@percy/dom';
const domSnapshot = serializeDOM(options)
Browser injection
await page.addScriptTag({ path: require.resolve('@percy/dom') })
const domSnapshot = await page.evaluate(() => PercyDOM.serialize(options))
Options
enableJavaScript
— When true, does not serialize some DOM elementsdomTransformation
— Function to transform the DOM after serializationdisableShadowDOM
— disable shadow DOM capturing, usually to be used when enableJavascript: true
reshuffleInvalidTags
— moves DOM tags which are outside </body>
to its inside to make the DOM compliant.
Serialized Content
The following serialization happens to a cloned instance of the document in order.
Input elements
Input elements (input
, textarea
, select
) are serialized by setting respective DOM attributes
to their matching JavaScript property counterparts. For example checked
, selected
, and value
.
Frame elements
Frame elements are serialized when they are CORS accessible and if they haven't been built by
JavaScript when JavaScript is enabled. They are serialized by recursively serializing the iframe's
own document element.
CSSOM rules
When JavaScript is not enabled, CSSOM rules are serialized by iterating over and appending each rule
to a new stylesheet inserted into the document's head.
Canvas elements
Canvas elements' drawing buffers are serialized as data URIs and the canvas elements are replaced
with image elements. The image elements reference the serialized data URI and have the same HTML
attributes as their respective canvas elements. The image elements also have a max-width of 100% to
accomidate responsive layouts in situations where canvases may be expected to resize with JS.
Video elements
Videos without a poster
attribute will have the current frame of the video
serialized into an image and set as the poster
attribute automatically. This is
to ensure videos have a stable image to display when screenshots are captured.
Shadow DOM
Shadow dom #shadow-root (open)
is serialized into declarative shadow DOM (<template shadowroot="open">
) form
Shadow host element is annotated with special identifier attribute named data-percy-shadow-host
. This identifier
attribute may be used when passing domTransformation
.
Other elements
All other elements are not serialized. The resulting cloned document is passed to any provided
domTransformation
option before the serialize function returns a DOM string.
Examples
- perform DOM transformations on serialized DOM
this example contains scenario of nested shadow DOMs
import serializeDOM from '@percy/dom';
const domSnapshot = serializeDOM({
domTransformation: (documentElement) => {
function insertHelloHeader(root) {
h1 = document.createElement('h1');
h1.innerText = 'Inserted using dom transformations';
root.append(h1);
root.querySelectorAll('[data-percy-shadow-host]')
.forEach(
shadowHost => {
if (shadowHost?.shadowRoot)
insertHelloHeader(shadowHost.shadowRoot)
});
}
insertHelloHeader(documentElement);
}
});