SnapDOMGitHub8K
Playwright integration

SnapDOM vs Playwright

Playwright drives the browser and owns the test lifecycle. SnapDOM can run inside that browser when the artifact needs SVG, capture plugins or the same export path used by the application.

TL;DR

Use Playwright’s page and locator screenshots for test evidence, full-page pixels and visual regression baselines. Inject SnapDOM when CI must exercise the application’s DOM export, return SVG or produce several formats from one prepared capture.

The useful dividing line

Playwright controls Chromium, Firefox and WebKit. It navigates, authenticates, waits on UI state and captures the page or a locator. Playwright Test also stores baselines and compares later runs with toHaveScreenshot().

SnapDOM starts after the page is ready. It clones a chosen DOM subtree with its resolved styles and resources, then serializes it through SVG foreignObject. The result can stay SVG or be exported to PNG, JPEG, WebP, Canvas or Blob. Navigation and assertions remain Playwright’s job.

TaskPlaywright APISnapDOM inside Playwright
Visual regression baselinetoHaveScreenshot()Produces the input artifact
Viewport or full-page capturepage.screenshot()Capture the document element
Component pixel capturelocator.screenshot()DOM subtree export
Raw SVG outputPixel screenshotresult.url
Several formats from one captureSeparate screenshot callsOne CaptureResult
In-capture redaction or watermarkingScreenshot masks and stylesPlugin hooks
Browser-engine matrixChromium · Firefox · WebKitRuns in the selected page

Visual regression: keep the Playwright assertion

Playwright Test already handles baseline naming, retries and pixel comparison. A locator assertion also waits for two consecutive screenshots to match before comparing the last image with the baseline.

import { test, expect } from '@playwright/test'

test('invoice layout', async ({ page }) => {
  await page.goto('/invoice/42')

  const invoice = page.getByTestId('invoice')
  await expect(invoice).toHaveAttribute('data-ready', 'true')
  await expect(invoice).toHaveScreenshot('invoice.png', {
    animations: 'disabled',
    caret: 'hide',
    maxDiffPixels: 40
  })
})

The baseline still depends on the browser, operating system and fonts. Generate and compare it in the same CI image. Playwright documents the workflow and update command in its visual comparison guide.

Export SVG from a Playwright-controlled page

This pattern is useful when a Node job must produce the same SnapDOM artifact as the client application. The browser context bypasses CSP so the example can inject the IIFE bundle. If the app already imports SnapDOM, skip addScriptTag() and the CSP override.

import { chromium } from 'playwright'
import { writeFile } from 'node:fs/promises'

const browser = await chromium.launch()
const context = await browser.newContext({ bypassCSP: true })
const page = await context.newPage()

await page.goto('https://example.com/report')
const report = page.locator('#report[data-ready="true"]')
await report.waitFor({ state: 'visible' })
await page.evaluate(async () => { await document.fonts.ready })

await page.addScriptTag({
  url: 'https://cdn.jsdelivr.net/npm/@zumer/snapdom/dist/snapdom.js'
})

const svgURL = await report.evaluate(async element => {
  const capture = await window.snapdom(element, { embedFonts: true })
  return capture.url
})

const encoded = svgURL.slice(svgURL.indexOf(',') + 1)
await writeFile('report.svg', decodeURIComponent(encoded))
await browser.close()

locator.evaluate() runs in the page, where DOM APIs and window.snapdom exist. Return a serializable string to Node; an HTMLImageElement, Canvas or Blob belongs to the browser context. See Playwright’s evaluation model and browser-context options.

Stabilize application state explicitly

Locator auto-waiting covers attachment, visibility and layout stability. It cannot know whether a chart has received its final data or whether the application considers a report complete. Expose a deterministic signal such as data-ready="true", wait for document.fonts.ready, and disable or freeze time-dependent UI before capture.

The native page, buffer and locator forms are listed in Playwright’s screenshot documentation.

Frequently asked questions

Should a visual regression test use Playwright or SnapDOM?

Use Playwright Test for baselines and pixel diffs. Run SnapDOM inside the Playwright page when the test must exercise the application’s export code, produce SVG, run capture plugins or derive several formats from one capture.

Can SnapDOM run inside every Playwright browser project?

Yes. Inject or bundle SnapDOM into the page, then call it in page.evaluate() or locator.evaluate(). The capture runs in the Chromium, Firefox or WebKit page selected by the project.

Why return a data URL from page.evaluate()?

A data URL is serializable across the browser and Node boundary. DOM objects, HTMLImageElement instances and Blob objects belong to the page context, so convert the artifact before returning it.

Add DOM export to the page

Use SnapDOM in the application or inject it into a Playwright-controlled browser.

Read the API docsInstall from npm