Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To attach a browser screenshot to a failed JUnit 5 test, capture the browser’s image bytes while its session is still available, then pass those bytes to a reporting integration that supports image attachments. JUnit’s TestWatcher can detect test-method failures; Allure can store and preview a PNG when you label it as image/png. These are separate jobs: JUnit detects the result, Selenium or another browser driver captures the page, and the report integration stores the image.

Choose the failure hook and report format

The right implementation depends on which failures you need to cover and what your report viewer can display. For ordinary failed test methods, a JUnit Jupiter TestWatcher is a small reusable hook. If you need to intercept the test exception itself, an exception handler is another option. For image previews, use a reporting integration that explicitly supports image attachments, such as Allure; a generic JUnit XML file is not automatically an inline image viewer.

Approach Useful for Important limitation
JUnit TestWatcher Responding to a failed test method or template It does not report class-level failures such as a @BeforeAll exception, and certain instance registrations miss template events.
TestExecutionExceptionHandler Handling a test’s thrown exception while the test execution is being intercepted You still need a live browser session and a separate attachment integration.
JUnit TestReporter or XML output Publishing additional test data or producing test-result output Support for data output does not guarantee that a chosen viewer will preview image bytes.
Allure attachment API Storing a screenshot with a test result and previewing supported image types Allure does not operate the browser or take the screenshot for you.

Attach a screenshot with a JUnit 5 TestWatcher

The example below uses Selenium and Allure. The project-specific part is obtaining the correct WebDriver for the test that just failed. The placeholder DriverStore represents your own driver manager; replace it with the thread-local, test-context, or dependency-injection mechanism your suite already uses. Do not create a new driver in the watcher: it would capture a new page rather than the page that failed.

Keep the driver alive through screenshot capture. If your teardown quits the browser before the watcher can access it, move capture to an earlier hook or use an exception-handler design that runs while the test session remains open.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import java.io.ByteArrayInputStream;
import java.util.Optional;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestWatcher;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import io.qameta.allure.Allure;

public final class FailureScreenshotWatcher implements TestWatcher {
    @Override
    public void testFailed(ExtensionContext context, Throwable cause) {
        Optional<WebDriver> maybeDriver = DriverStore.current();
        if (maybeDriver.isEmpty()) {
            return;
        }

        WebDriver driver = maybeDriver.get();
        if (!(driver instanceof TakesScreenshot)) {
            return;
        }

        try {
            byte[] png = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
            String label = "Failure screenshot - " + context.getDisplayName();
            Allure.addAttachment(
                label,
                "image/png",
                new ByteArrayInputStream(png),
                ".png"
            );
        } catch (RuntimeException captureError) {
            // Preserve the original test failure; record captureError in your test logs.
        }
    }
}

The attachment’s media type matters: image/png tells Allure that the bytes are a PNG image, so it can offer a preview for supported media types. The display name identifies which test produced the artifact. The catch prevents a screenshot problem from obscuring the original assertion failure; in a real project, log the capture exception to the test or build output so it can be diagnosed.

Register the extension with the test class:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(FailureScreenshotWatcher.class)
class CheckoutTest {
    @Test
    void showsConfirmationAfterPurchase() {
        // Arrange, act, and assert using the suite's existing WebDriver.
    }
}

Alternatively, use a static extension field when your registration arrangement calls for it. JUnit documents a scope caveat: a non-static instance extension under the default PER_METHOD lifecycle does not receive template events. Register at class level or use a static field when template coverage matters. A TestWatcher also does not receive result callbacks for class-level failures such as a @BeforeAll exception, or for disabled classes. It should not be treated as a universal hook for every way a test run can fail.

Use an exception handler when you need the thrown test exception

JUnit’s TestExecutionExceptionHandler is an alternative interception point for an exception thrown during test execution. Its handler should capture and attach the screenshot, then rethrow the original exception so JUnit still records the test as failed. This is useful when the watcher’s timing or result scope does not fit the test framework integration you need. It does not remove the key lifecycle requirement: the handler needs access to the failed test’s still-open browser.

For Selenium with JUnit 5 and Allure, Allure’s Selenium integration guidance describes this handler approach alongside attachment options such as @Attachment, Allure.attachment, and Allure.addAttachment. Choose one hook deliberately rather than attaching twice from both a handler and a watcher. Make sure your extension is registered for the tests that need it and that screenshot capture is attempted before driver shutdown.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose an Allure attachment API

Allure supports attachment methods that return byte[], as well as runtime APIs that accept bytes or streams. For example, a helper can return a PNG byte array from an annotated method, or the watcher can call Allure.addAttachment directly as above. Use a descriptive attachment name and an image media type such as image/png; an optional .png extension helps preserve the file type for download.

Allure documents both download links and previews for supported media types. That behavior is specific to the configured reporting integration; do not assume that another JUnit XML consumer will render the same attachment inline. Confirm that the Allure JUnit 5 integration is present and configured in the project, then inspect the generated report for both the failed test entry and its attachment.

For Selenide, use its Allure integration

If the browser tests already use Selenide, its Allure integration can be less code than managing a separate Selenium screenshot hook. The integration guide describes failure screenshots being captured automatically and shows registering the AllureSelenide listener with screenshots enabled so they appear in Allure.

import com.codeborne.selenide.logevents.SelenideLogger;
import io.qameta.allure.selenide.AllureSelenide;

// Run once during test-suite setup:
SelenideLogger.addListener(
    "AllureSelenide",
    new AllureSelenide().screenshots(true)
);

The documented default screenshot output folder is build/reports/tests. The guide shows changing it with a JVM property:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
-Dselenide.reportsFolder=test-result/reports

Check that the Selenide, Allure integration, and JUnit dependencies are compatible with your build; dependency versions in integration guides are examples, not a guarantee that they match your project. If screenshots are saved locally but absent from Allure, verify listener registration and that the report is generated from the same test run.

Rank #4
Sale

What plain JUnit reporting does—and does not—promise

JUnit’s TestReporter can publish additional test data, and the JUnit Platform supports Open Test Reporting XML output with configurable capture of standard output and error. Those capabilities are useful for reporting diagnostics, but they do not establish that every generic XML format or HTML viewer will display an image attachment inline.

If the requirement is “open the failed test and see the screenshot,” choose a report integration whose documentation promises supported image previews, configure it, and verify the generated report in the same environment where teammates or CI users will view it. Otherwise, treat the screenshot as a separate file or downloadable artifact and make its association with the test explicit.

Keep capture reliable in local runs and CI

  • Match the browser to the test. In parallel runs, retrieve the driver associated with the failing test, not a shared mutable driver that another test may be using.
  • Capture before shutdown. Teardown ordering can make a valid failure hook too late to access the browser. Arrange lifecycle hooks so the screenshot is taken while the page is still available.
  • Preserve the original failure. A screenshot error should be logged, but should not replace the assertion or browser exception that caused the test to fail.
  • Check report generation. Confirm the Allure result and attachment are included in the report output; a locally saved screenshot alone does not prove it was attached to the test result.
  • Check CI retention separately. Artifact retention and report publication depend on your CI provider and build configuration. The JUnit and Allure attachment APIs do not set those policies for you.
  • Control artifact volume. Failure-only capture avoids creating screenshots for every passing test. Consider whether sensitive page data can appear in screenshots before retaining or sharing them.

Troubleshoot missing or unusable screenshots

  • No screenshot on a failed test: Confirm the extension is registered on the test class, the test uses the expected JUnit Jupiter engine, and the driver lookup returns the active session.
  • Watcher runs but gets no driver: Your driver may be stored in a different scope or cleared during teardown. Align driver storage and extension lifecycle, or capture through an exception handler before the session closes.
  • Template failures are missing: Check whether the extension is a non-static instance field under the default PER_METHOD lifecycle. Use class-level registration or a static extension field for the relevant template coverage.
  • @BeforeAll failure has no image: A TestWatcher does not report class-level failures through its result callback. Add a setup-specific capture strategy if setup failures need screenshots, and ensure a browser exists at that point.
  • Allure shows a download but no preview: Verify that the attachment contains valid PNG bytes and is labeled image/png; check the report’s supported media types.
  • Image exists on disk but not in the report: A file in Selenide’s screenshot folder is not by itself proof it was attached. Register the Allure Selenide listener with screenshots enabled and regenerate the report from the matching test results.
  • CI report has no attachment: Inspect the report-generation and artifact-publishing configuration. JUnit, Allure, and the CI provider each have separate responsibilities.
  • Screenshot failure hides the test error: Catch and log capture exceptions in the hook, then preserve the original test failure rather than throwing the capture exception in its place.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For a screenshot of a public page that does not need the exact live state of a failed Selenium session, ScreenshotNeo offers a one-request capture. It is a website screenshot API, not a replacement for reading the failing test’s authenticated, in-progress browser state. See the ScreenshotNeo API documentation for request options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with response headers indicating the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is available on every plan. Learn more at ScreenshotNeo, then sign up for 1,000 free screenshots a month with no card.

Frequently Asked Questions

Does a TestWatcher capture screenshots for disabled tests?

No. A TestWatcher result callback is not provided for disabled classes, and the watcher also misses class-level failures such as a @BeforeAll exception.

Will a JUnit XML report show an attached PNG inline?

Not necessarily. JUnit data or XML output does not guarantee that a particular report viewer previews image attachments; use a reporting integration that explicitly supports image previews.

Can ScreenshotNeo capture the browser state from a failed Selenium test?

Not the in-progress session state by itself. It captures a URL as a separate API request, so it is appropriate when a separate page capture is sufficient rather than an exact screenshot of the failed test session.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quick Recap

SaleBestseller No. 3
SaleBestseller No. 4
Pragmatic Unit Testing in Java with JUnit
Pragmatic Unit Testing in Java with JUnit
Used Book in Good Condition
$13.55
SaleBestseller No. 5

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.