Visual Testing for Static Sites: No Tests Required
Got a static site? Now you can visually test every page without writing tests. The new Static Site SDK auto-discovers pages, captures screenshots, and handles comparisons. Works with Gatsby, Astro, Jekyll, Next.js, and any static site generator.
If you’re building a static site, visual testing has been… awkward. You either skip it entirely or cobble together a test suite just to capture screenshots. Neither option feels right.
We built a Static Site SDK that fixes this. Point it at your build directory and it handles the rest - page discovery, screenshots, comparisons, the whole workflow.
How It Works
The SDK discovers your pages automatically. It looks for a sitemap.xml, scans HTML files, or both. Then it spins up a local server, captures screenshots across viewports, and sends them to Vizzly.
Here’s what that looks like:
# Build your static site first
npm run build
# Capture screenshots from the build
vizzly static-site ./dist
That’s it. No test files, no configuration, no manually listing every page.
What Gets Discovered
The SDK finds pages using two methods:
Sitemap.xml parsing - If your static site generator creates a sitemap (most do), the SDK extracts all the URLs automatically.
HTML file scanning - Walks through your build directory and finds every .html file, converting file paths to proper URLs.
Both methods work together. If you’ve got a sitemap, great. If not, HTML scanning has you covered.
Multi-Viewport Screenshots
Static sites need to work everywhere - desktop, tablet, mobile. The SDK captures screenshots at multiple viewports by default.
Want custom viewports? Configure them:
// vizzly.config.js
export default {
staticSite: {
viewports: [
{ name: 'mobile', width: 375, height: 667 },
{ name: 'tablet', width: 768, height: 1024 },
{ name: 'desktop', width: 1920, height: 1080 },
],
},
};
Or pass them via CLI:
vizzly static-site ./dist --viewports "mobile:375x667,desktop:1920x1080"
Each page gets captured at every viewport. You’ll catch responsive layout issues before they ship.
Interaction Hooks for Dynamic Content
Static sites aren’t always static. You’ve got JavaScript, lazy-loaded content, animations that need time to settle.
Interaction hooks let you interact with pages before screenshots:
// vizzly.static-site.js
export default {
interactions: {
'blog/*': async (page) => {
// Wait for blog content to load
await page.waitForSelector('.blog-content');
},
'products/*': async (page) => {
// Click to reveal product details
await page.click('.view-details');
await page.waitForSelector('.product-modal');
},
},
};
Patterns support glob syntax (blog/*, docs/**). The SDK matches pages to hooks and runs them before capturing screenshots.
Pattern-Based Filtering
Got hundreds of pages but only want to test specific sections? Filter them:
# Only test blog pages
vizzly static-site ./dist --include "blog/**"
# Test everything except 404s
vizzly static-site ./dist --exclude "**/404.html"
Combine patterns for precise control:
// vizzly.config.js
export default {
staticSite: {
include: 'blog/**',
exclude: '**/draft-*.html',
},
};
Works with Your Static Site Generator
This SDK doesn’t care how you build your site. It just needs HTML files.
Gatsby:
gatsby build
vizzly static-site ./public
Astro:
npm run build
vizzly static-site ./dist
Jekyll:
bundle exec jekyll build
vizzly static-site ./_site
Next.js Static Export:
npm run build
vizzly static-site ./out
Same pattern works for Hugo, Eleventy, VuePress, Docusaurus - any generator that outputs HTML.
Local TDD Workflow
Here’s where this gets useful. When you’re building a static site, you make changes, rebuild, check the output. Rinse and repeat.
Now add visual validation to that loop:
# Start Vizzly TDD mode
vizzly tdd start
# In another terminal, rebuild and capture screenshots
npm run build && vizzly static-site ./dist
The SDK detects the TDD server automatically. Screenshots get compared locally, diffs show up instantly in your browser at http://localhost:47392.
No context switching. You code, rebuild, see exactly what changed visually. Accept or reject changes from the UI.
CI/CD Integration
The same SDK works in CI. Set a VIZZLY_TOKEN environment variable and screenshots upload to the cloud for team review:
# .github/workflows/visual-tests.yml
name: Visual Tests
on: [push, pull_request]
jobs:
visual-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm install
- run: npm run build
- run: npx vizzly static-site ./dist
env:
VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }}
The SDK detects the token and switches to cloud mode. Your team gets automatic visual review on every PR.
Configuration Priority
Configuration merges in this order:
- Default settings (sensible defaults, works out of the box)
vizzly.config.js(project-level configuration)vizzly.static-site.js(interaction hooks and page overrides)- CLI flags (highest priority, overrides everything)
This layering means you can set project defaults but override them per-page or per-run as needed.
Per-Page Overrides
Sometimes specific pages need different treatment:
// vizzly.static-site.js
export default {
pages: {
'/': {
viewports: ['mobile', 'desktop'], // Only test key viewports for homepage
},
'/pricing': {
screenshot: { fullPage: true }, // Capture entire pricing page
},
},
};
Per-page config overrides global settings. Useful for special cases without cluttering your main config.
Parallel Processing
Static sites can have hundreds or thousands of pages. The SDK processes them in parallel:
vizzly static-site ./dist --concurrency 5
Default is 3 parallel pages. Bump it higher for faster captures, or lower it if you’re hitting resource limits.
Why This Matters
Visual testing shouldn’t require test infrastructure. If you’re generating HTML, you should be able to validate it visually without writing Playwright scripts or maintaining a test suite.
This SDK makes visual testing as simple as your build process. Point it at HTML, get screenshots, see what changed. Local iteration stays fast. Team review happens automatically in CI.
It’s visual quality integrated into your static site workflow, not bolted on afterward.
Try It
Install the SDK:
npm install @vizzly-testing/static-site
Capture screenshots from your build:
vizzly static-site ./dist
The plugin auto-discovers pages, handles viewports, and integrates with both local TDD and cloud builds.