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.
| Task | Playwright API | SnapDOM inside Playwright |
|---|---|---|
| Visual regression baseline | toHaveScreenshot() | Produces the input artifact |
| Viewport or full-page capture | page.screenshot() | Capture the document element |
| Component pixel capture | locator.screenshot() | DOM subtree export |
| Raw SVG output | Pixel screenshot | result.url |
| Several formats from one capture | Separate screenshot calls | One CaptureResult |
| In-capture redaction or watermarking | Screenshot masks and styles | Plugin hooks |
| Browser-engine matrix | Chromium · Firefox · WebKit | Runs 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.
- Use
expect(locator).toHaveScreenshot()when the output is a test baseline. - Use
locator.screenshot()for a one-off pixel artifact or trace attachment. - Run SnapDOM in
locator.evaluate()for SVG, plugins or the application’s own export behavior. - Keep separate baselines per Playwright project when testing multiple engines.
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