Modify serialised DOM using domTransformation

👍

Covered in this doc

  • How to configure Percy's SDKs to modify the serialized DOM.

Overview

There could be different reasons to modify the DOM to make it look as you expect in Percy, say there is an Ad banner or some UI state is not properly captured, e.t.c

Before understanding domTransformation make sure you understand how Percy SDKs work here. Okay now that you've read how Percy works, Let's proceed further. The Serialized DOM is sent to our backend for re-rendering on different browsers and devices, we can modify it by passing a domTransformation function.

domTransformationtakes documentElement as an argument and doesn't expects anything to be returned, check the examples below to understand further.

Config

📘

This feature requires v1.24.0+ of Percy CLI to work

This config is only available for per-snapshot configuration and not available in global config!

If you're using percy snapshot command then you'll need to follow the below configuration

Percy Snapshot

snapshots:
- name: Example
  url: https://example.com
  widths: [1280]
  domTransformation: | 
    (documentElement) => {
      function changeHeader(root) {
        documentElement.querySelector('h1').innerText = 'Changed using domTransformation'
      }
      changeHeader(documentElement);
    }

Other SDKs

If you're using any SDKs then you can check the following SDK examples.

Cypress

it('example test', function() {
  // ...
  
  domTransformation = "(documentElement) => documentElement.querySelector('h1').innerText = 'Changed using domTransformation'"
  cy
	  .viewport(1280, 1024)
	  .percySnapshot('Home page', { width: 1280, domTransformation });
  // ...
});

Playwright or Puppeteer

it('example test', async () => {
  // ...
  
  domTransformation = "(documentElement) => documentElement.querySelector('h1').innerText = 'Changed using domTransformation'"

  await page.setViewport({ width: 1280, height: 1024 });
  await percySnapshot(page, 'Home Page', { width: 1280, domTransformation });
  // ...
});

Selenium (JavaScript)

it('example test', async () => {
  // ...
  domTransformation = "(documentElement) => documentElement.querySelector('h1').innerText = 'Changed using domTransformation'"
  await driver.manage().window().setSize(1280, 1024);
  await percySnapshot(driver, 'Home Page', { width: 1280, domTransformation });
  // ...
});

Advanced Use case

Accessing DOM elements inside shadow DOM

// pass the function in string format as options to percySnapshot function
// you could use multiline string syntax that might be available in your language

domTransformation = (documentElement) => {
  function updateLinks(root) {
    root.querySelectorAll('.myLink').forEach(link => {
      console.log(link);
      // do stuff here
    });

    
    // we mark shadow host with following marker during serialisation
    root.querySelectorAll('[data-percy-shadow-host]')
      .forEach(
      shadowHost => {
        console.log(shadowHost);
        if (shadowHost?.shadowRoot)
          updateLinks(shadowHost.shadowRoot);
      });

  }
  updateLinks(documentElement);
}

// in JS
domTransformation = domTransformation.toString()