screenshot-helper
v2.0.1
Published
A helper for taking automated web screenshots using Playwright.
Downloads
67
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)group: (optional) explicit grouping key for deterministic grouped numberingfull: 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 outputDir = 'screenshots'; // optional
const onEvent = (event) => {
// optional structured event hook for app integration
console.log(event);
};
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',
};
const summary = await launchScreenshotsRunner({
scenarioData,
baseURL,
devices,
filter,
outputDir,
onEvent,
httpCredentials,
loadTimeoutMs,
loadTimeoutAction,
debug
});
console.log(summary);By default, runner status/debug logs are written to stderr so you can keep stdout clean for JSON output.
For example, this captures only JSON summary to a file while still showing progress logs in the terminal:
node screenshots.js > summary.jsonScenario Configuration
- name: string (required)
Used for the output filename and reporting. - route: string (required)
Path relative tobaseURL - group: string | number
Optional explicit group key for filename grouping. If omitted, grouping is inferred from the route URL without query/hash. If route is missing, the scenario falls back to a
miscgroup. - 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. - outputDir: string
Optional output directory for generated screenshots. Defaults to
screenshots. - outputPathBuilder:
({ outputDir, device, shotNum, shotLabel, groupId, groupKey, shotInGroup, scenarioName, scenario, type }) => stringOptional filename/path builder. Defaults to grouped deterministic naming:outputDir/device-GG.SSS-name.png(for exampledesktop-01.002-home.png). - onEvent:
(event) => voidOptional structured event hook. Receives lifecycle events such asscenario-started,scenario-skipped,scenario-succeeded, andscenario-failed. - logger: object
Optional logger override with
log(...args)anderror(...args)methods.
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.
Return value
launchScreenshotsRunner(...)now returns a summary object with aggregate counts and per-device scenario outcomes.
Structured events
Example onEvent payload:
{
type: 'scenario-succeeded',
device: 'desktop',
scenarioName: 'homepage',
scenarioType: 'page',
status: 'succeeded',
reason: null,
filename: 'screenshots/desktop-01.001-homepage.png'
}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
