screenshot-helper
v1.3.7
Published
A helper for taking automated web screenshots using Playwright.
Downloads
66
Maintainers
Readme
screenshot-helper
Automate high-quality screenshots of web pages for testing, visual review, and documentation.
screenshot-helper is a flexible Node.js utility designed to programmatically capture screenshots of web apps with minimal boilerplate. It supports scenario lists, custom setup and cleanup logic, device presets, and easy integration into your QA or CI flows.
Features
- Automates screenshots from a scenario configuration
- Works with Playwright to simulate real browser environments (desktop/mobile, etc.)
- Supports UI interaction setup (
before) and post-setup cleanup (cleanup) - Granular capture: full-page, clipped to element, function-based, etc.
- Use filters to selectively run a subset of scenarios
- Strong integration for visual testing and asset generation
- Errors in scenarios (including Playwright errors) are always caught: process never crashes, errors are highlighted and remaining scenarios continue.
- Full ES module (ESM) support everywhere; tested with Vitest.
Installation
npm install screenshot-helperFor development/contributors:
npm install --save-dev vitestRunning the Tests
This project uses Vitest for all unit and integration tests and supports top-level import/export JavaScript syntax out of the box. No Babel or legacy Jest config is needed with Node.js (>=18).
npm testOr run a single test file:
npx vitest run test/your.test.jsBasic Usage
Define your scenarios and call the runner. Each scenario can have:
name: Unique name for the output fileroute: URL path (relative to your baseURL)full: Capture the entire page (true) or just the viewport (false)selector: (optional) CSS selector for element-only screenshotsbefore: (optional) Async function for custom setup (e.g., open a modal, wait for element)cleanup: (optional) Async function for removing overlays/ads/etc before the screenshot
import launchScreenshotsRunner from 'screenshot-helper';
const baseURL = 'http://localhost:8888';
const devices = {
desktop: { viewport: { width: 1280, height: 1080 }, deviceScaleFactor: 2 },
mobile: { viewport: { width: 375, height: 812 }, deviceScaleFactor: 2 }
};
const loadTimeoutMs = 8000; // optional: max wait for networkidle before acting
const loadTimeoutAction = 'continue'; // or 'skip' to abandon the scenario
const debug = true; // optional: verbose logging for stuck runs
const scenarioData = [
{
name: 'simple-homepage',
route: '/',
full: true
},
{
name: 'cookie-banner',
route: '/',
selector: '#cookie-consent-banner',
before: async (page, locator, device) => {
await page.waitForFunction(() => !!window.cookieconsent);
await page.evaluate(() => window.cookieconsent.show());
// device is now available as a third argument (e.g. 'desktop' or 'mobile')
if (device === 'mobile') {
// special handling for mobile...
}
if (!await locator.isVisible()) return false; // skip screenshot if banner is not visible
}
},
{
name: 'third-party-capture',
route: '/external-widget-demo',
before: async page => {
await page.click('#widget-opener');
},
cleanup: async page => {
await page.evaluate(() => {
let el = document.querySelector('.third-party-banner');
if (el) el.remove();
});
},
full: true
}
];
// Optionally pass a filter to only run a subset of scenarios
const filter = process.argv[2];
// To provide HTTP Basic Auth credentials to all requests
const httpCredentials = {
username: 'yourUsername',
password: 'yourPassword',
};
launchScreenshotsRunner({ scenarioData, baseURL, devices, filter, httpCredentials, loadTimeoutMs, loadTimeoutAction, debug });Scenario Configuration
- name: string (required)
Used for the output filename and reporting. - route: string (required)
Path relative tobaseURL - full: boolean
Capture the entire page (true) or just viewport/selector area (false) - selector: string
CSS selector for element screenshot (optional; use type: 'element' for clarity) - before:
(page, locator?) => Promise
An async function run prior to the screenshot, for setup (e.g., open menus, wait for content) - cleanup:
(page) => Promise
An async function run just before the screenshot (after setup), ideal to remove overlays/ads, etc.
Scenario Types
screenshot-helper supports 3 scenario type modes for maximum control:
Default (Page)
- Omit
type, or use any unrecognized value. - Screenshots the full page or just the viewport (if
full: true) after running optionalbeforeandcleanuphooks. selectoris ignored.- If
full: true, the page is scrolled to capture the entire length.
- Omit
Element (
type: 'element')- Only screenshots the area of a specific DOM element, as matched by
selector. - If
full: true, the screenshot will output multiple PNG files ("tiles/fragments") per element, scrolling through both axes using Playwright. This pans through overflow within the selected element viaelement.scrollTo, so containers wider or taller than the viewport are robustly covered. Files are named with letter suffixes (e.g....001a-,...001b-, etc). - Receives
before(page, locator, device)andcleanup(page, locator, device)for custom setup/teardown.
- Only screenshots the area of a specific DOM element, as matched by
Function (
type: 'function')- For advanced/edge scenarios requiring full Playwright scripting.
- Hooks are given both the
pageobject and a locator for chaining or ignoring as you wish:before(page, locator, device). - Does not perform any screenshot by default—your hook code should perform interactions as needed. You can use these for setup, or for logic-only tasks that do not result directly in a screenshot.
Advanced Patterns
Use type: 'element' for element screenshots, or type: 'function' scenarios for full scriptable logic.
You can chain Playwright's page and locator methods inside your hooks, interact with dynamic JS elements, or conditionally skip screenshots.
CLI Filtering
You can filter which scenarios are run by passing a substring as a CLI argument:
node screenshots.js homepageWill only run scenarios whose name includes "homepage".
Load timeouts
loadTimeoutMscaps how long the runner waits for a page to reachnetworkidlebefore proceeding.loadTimeoutActioncontrols behavior on timeout:'skip'stops the scenario immediately,'continue'runs hooks/screenshot even if the page never reachednetworkidle.- The same
loadTimeoutMsis reused for asset waits (ensureAssetsLoaded), so hanging images/fonts won’t stall forever.
Debug logging
- Pass
debug: truetolaunchScreenshotsRunnerto print step-by-step progress (navigation, load waits, hooks, and screenshot points) for each scenario/device. Useful when runs hang or stall.
Testing
Run tests with:
npm testUnit and integration tests are in [test/].
Contributing
PRs and suggestions welcome! Please open an issue first to discuss feature ideas or bugs.
License
ISC (see LICENSE file)
See also:
- test/launchScreenshotsRunner.test.js for more usage patterns
