Visual testing catches UI regressions that unit tests usually miss. It is especially useful for UI libraries and frontend apps where layout, spacing, typography, and interaction states can break without JavaScript errors.
@rettangoli/vt helps you generate visual baselines, compare against references, and review diffs with a report.
1. Recommended runtime: Docker
Use the official image for Playwright browsers and install an exact project CLI version so local and CI runs use the same VT engine:
npm install --save-dev --save-exact [email protected]
docker pull han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0
Set a shell alias so docs and scripts can use plain rtgl commands:
alias rtgl='docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0 node /workspace/node_modules/rtgl/cli.js'
The image default working directory is /workspace, so -w /workspace is not required.
Commit the lockfile. The alias uses the installed project CLI, so an older bundled CLI in the browser image cannot silently change VT versions. Match the image's Playwright version to your installed VT dependency. Without Docker, use the same local dependency through package scripts:
npx rtgl --version
2. Create VT folders
Create this structure in your project:
my-app/
rettangoli.config.yaml
vt/
specs/
pages/
home.html
reference/
reference/ can start empty. It will be filled after you accept snapshots.
3. Add minimal VT config
In rettangoli.config.yaml:
vt:
path: ./vt
sections:
- title: pages
files: pages
4. Add your first spec
Create vt/specs/pages/home.html:
---
title: Home
---
<main data-testid="home-page">Hello VT</main>
5. Run the workflow
In package.json, add VT scripts that call local rtgl:
{
"scripts": {
"generate": "rtgl vt generate",
"screenshot": "rtgl vt screenshot",
"report": "rtgl vt report",
"accept": "rtgl vt accept"
}
}
Build candidate pages:
npm run generate
Capture candidate screenshots:
npm run screenshot
Compare candidate vs reference and build report:
npm run report
When changes are expected, accept them:
npm run accept
6. Open the report
Generated report:
.rettangoli/vt/_site/report.html
JSON summary:
.rettangoli/vt/report.json
Optional: use with @rettangoli/sites
If your app is built by rtgl sites, define scripts once and keep VT commands simple.
package.json:
{
"scripts": {
"watch": "rtgl sites watch -p 4173 -o dist --quiet",
"build": "rtgl sites build -o dist",
"generate": "rtgl vt generate",
"screenshot": "rtgl vt screenshot",
"report": "rtgl vt report",
"accept": "rtgl vt accept"
}
}
Scripts call the project-local rtgl binary (node_modules/.bin/rtgl) automatically.
Use this managed preview service:
vt:
path: ./vt
isolationMode: strict
url: http://127.0.0.1:4173
service:
start: npm run watch
sections:
- title: pages
files: pages
vt.service.start starts/stops the preview command automatically during npm run screenshot.
isolationMode: strict is recommended when those screenshots hit real app routes or app state is stored in IndexedDB.
For full setup details, see Sites Integration.