Attach the screenshot in a Cucumber After hook, after checking that the scenario failed, and await both Playwright’s screenshot promise and Cucumber’s attach call. Keep the Playwright page on the Cucumber World and run the built-in HTML formatter. This produces a report that displays the PNG beside the failed scenario.
Working implementation
The following CommonJS example assumes your World exposes this.page and uses the default Cucumber attachment method, this.attach.
const { After, Status } = require('@cucumber/cucumber');
After(async function (scenario) {
if (scenario.result?.status !== Status.FAILED) {
return;
}
// Capture before any teardown closes the page or browser context.
const screenshot = await this.page.screenshot({ type: 'png' });
await this.attach(screenshot, {
mediaType: 'image/png',
fileName: 'screenshot.png'
});
});
Playwright returns PNG bytes. Cucumber receives those bytes through this.attach, and the formatter renders the attachment. The image/png media type is important: without an image MIME type, an HTML formatter may treat the payload as generic text or fail to render it.
Make the page available on World
Your step definitions and hooks must use the same World instance. A minimal custom World can create the browser and page in a Before hook, then close them after the screenshot hook has run.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
const { Before, AfterAll } = require('@cucumber/cucumber');
const { chromium } = require('playwright');
Before(async function () {
this.browser = await chromium.launch();
this.context = await this.browser.newContext();
this.page = await this.context.newPage();
});
AfterAll(async function () {
// Close the browser after all scenario After hooks have completed.
// Put per-scenario teardown in an After hook only if its order is safe.
});
If you use a custom World constructor, preserve the attachment function supplied by Cucumber or explicitly expose it. The default World provides this.attach; a custom implementation that omits it can let the hook run without creating a report attachment.
Run the built-in Cucumber HTML formatter
Generate the report with cucumber-js’s built-in formatter:
npx cucumber-js --format html:cucumber-report.html
Open cucumber-report.html in a browser after the run. Attachments are embedded by default, so the report is normally a standalone file that can be copied to another machine or CI artifact store.
Externalize images when reports are large
Many high-resolution screenshots can make an embedded report large. Configure external attachments in cucumber.js:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesmodule.exports = {
format: ['progress', ['html', 'reports/cucumber-report.html']],
formatOptions: {
html: {
externalAttachments: ['image/*']
}
}
};
The image/* pattern writes image files beside the HTML report instead of embedding them. Set externalAttachments: true to externalize all attachment types. Publish the generated image directory together with the HTML file and preserve relative paths; otherwise the report will open with broken images.
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
Capture only failures, or capture evidence at a step
Failure-only screenshots
Checking scenario.result?.status === Status.FAILED keeps successful reports small and focuses screenshots on diagnostic evidence. The optional chaining guard also avoids an exception if a result object is unavailable in an unusual hook invocation.
Step-level screenshots
For a scenario with several important states, attach in a step definition immediately after the action you want to document:
const { When } = require('@cucumber/cucumber');
When('I submit the form', async function () {
await this.page.getByRole('button', { name: 'Submit' }).click();
const image = await this.page.screenshot({ type: 'png' });
await this.attach(image, {
mediaType: 'image/png',
fileName: 'after-submit.png'
});
});
The formatter places that attachment after the step, which makes it easier to associate an image with a particular transition. You can use both step-level evidence and a failure hook, but avoid creating redundant, full-page images on every step.
Hook order and browser teardown
A screenshot cannot be taken after the page, context, or browser has been closed. If your suite has multiple After hooks, ensure the capture hook runs before teardown. The exact ordering mechanism depends on your cucumber-js version and hook configuration; the practical requirement is that the page remains usable until the attachment promise resolves.
Protect the original test failure if diagnostics fail. A screenshot attempt should not hide the assertion that caused the scenario to fail:
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
After(async function (scenario) {
if (scenario.result?.status !== Status.FAILED || !this.page) {
return;
}
try {
const image = await this.page.screenshot({ type: 'png' });
await this.attach(image, {
mediaType: 'image/png',
fileName: 'failure.png'
});
} catch (error) {
// Log the diagnostic error, but do not replace the scenario's failure.
console.error('Could not attach failure screenshot:', error.message);
}
});
Awaiting both operations matters. Letting the hook finish while either promise is pending can produce an empty or missing attachment, particularly when Cucumber is writing asynchronous formatter streams.
Accepted attachment formats and naming
- Buffer: the normal result of
page.screenshot(); pass it directly tothis.attach. - Readable stream: supported when another API produces a stream.
- Base64: mark the media type as
base64:image/pngwhen passing a base64 payload. - Filename: optional, but
fileName: 'screenshot.png'gives downloads and report readers a useful name.
Use a matching extension and MIME type. A JPEG payload labelled image/png, for example, can be displayed incorrectly by a formatter or image viewer.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Parallel runs and artifact naming
Cucumber-managed buffers avoid most filename collisions because the formatter associates each attachment with its scenario. If you write files yourself, do not use one shared path such as screenshots/latest.png in parallel workers. Include a scenario identifier, worker identifier, or timestamp in the filename, and make sure the CI artifact collector includes every worker’s directory.
Externalized attachments also require deterministic artifact collection. Merge worker output directories without overwriting files, then publish the resulting directory and its report together.
Troubleshooting missing screenshots
No image appears in the HTML
- Confirm the hook file is loaded by cucumber-js and that the scenario actually reaches the hook.
- Verify
this.pageis the live Playwright page andthis.attachexists on the World. - Check that the formatter command points to the HTML file you opened.
- Use
mediaType: 'image/png'and awaitthis.attach.
The image is empty or corrupt
Await page.screenshot() before attaching it, and do not close the context until the attachment has completed. If the page is already torn down because another hook ran first, reorder teardown or move it to a later lifecycle hook.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
The report opens but images are broken
This usually indicates external attachments. Copy the generated image files beside the report, preserve the formatter’s relative directory structure, and avoid opening only the HTML file after moving it.
The terminal shows output but the HTML does not
Progress output is not the HTML report. Check that the run includes --format html:cucumber-report.html (or the equivalent cucumber.js entry), then inspect the report generated by that same run. An attachment event must be present in the scenario output.
A custom World reports that attach is undefined
The default World supplies attach. When replacing it with a custom constructor, expose the function or use Cucumber’s supported World setup so hooks and steps retain the attachment API.
Built-in formatter or cucumber-html-reporter?
The built-in cucumber-js HTML formatter is the simplest choice when your tests already run through cucumber-js: it consumes attachment events directly, embeds images by default, and can externalize them with externalAttachments. The third-party cucumber-html-reporter package documents a different JSON-to-HTML workflow with options such as storeScreenshots, screenshotsDirectory, and noInlineScreenshots.
Choose the third-party workflow only when your project intentionally generates JSON and then converts it. Before switching, verify compatibility with your cucumber-js version, how each reporter handles parallel artifact names, whether the report is standalone, and how your CI retains external files. Do not mix configuration options from one reporter with the other.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. One request captures a URL as PNG, JPEG, WebP, or PDF, so it can complement Cucumber when you need an independent page artifact rather than a screenshot of the in-memory Playwright session. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
See the ScreenshotNeo API documentation for all parameters. A direct cURL call is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Equivalent Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Equivalent Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo includes full-page and selector capture, lazy-image loading, device presets, custom viewports and retina scale, PDF page controls, custom CSS and JavaScript, click and wait actions, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.
Recommended Free Tools
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Create a free ScreenshotNeo account to start without a card.
Practical checklist
- Store the Playwright page on the Cucumber World.
- Load the hook file in cucumber-js.
- Check
Status.FAILEDfor failure-only evidence. - Capture before teardown closes the page.
- Await both screenshot and attachment promises.
- Use
image/pngand an optional filename. - Keep external image files beside the HTML report.
- Use unique paths or Cucumber-managed buffers in parallel runs.
Frequently Asked Questions
Can I attach a screenshot for a passing scenario?
Yes. Call the same awaited page.screenshot() and this.attach() sequence without the failure-status condition, preferably at the specific step that needs visual evidence.
Does the HTML formatter require a separate image folder?
No. Its default is embedded attachments. A folder is required only when you enable external attachments.
Can the hook attach JPEG or WebP instead of PNG?
Yes, if Playwright produces that format and the attachment uses the matching MIME type, such as image/jpeg or image/webp.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

