Popular Searches
Popular Course Categories
Popular Courses

Failure Screenshots

Screenshots & Reporting

Failure Screenshots in Selenium TestNG

Failure Screenshots are screenshots captured automatically when a Selenium automation test fails. They provide visual evidence of the browser state at the time of failure and help testers understand what was displayed on the screen when an assertion, element interaction, navigation, synchronization, or other test step failed.

In Selenium TestNG frameworks, failure screenshots are commonly implemented using Selenium's TakesScreenshot interface together with TestNG's ITestListener. The listener can capture the browser state inside onTestFailure() before the WebDriver session is closed.

Failure screenshots are especially useful in CI/CD environments because the tester may not have direct access to the browser that executed the test. A screenshot saved as a test artifact can provide immediate visual evidence of the failed state.

Course Resource: Selenium Training | Register for Course Demo


1. What are Failure Screenshots?

A failure screenshot is an image captured from the browser when an automated test fails. It records the visible browser state at or near the time the failure is detected.

For example, suppose a Selenium test expects a successful login but the application displays an error message. The test may fail because the expected dashboard is not displayed. A failure screenshot can show the actual page, error message, popup, or other visible state.

Instead of investigating the failure only from logs, the QA engineer can inspect the screenshot and understand what the browser displayed.


2. Why are Failure Screenshots Important?

Failure screenshots provide visual evidence that complements test logs, stack traces, assertions, and reports.

  • Helps identify the visual state of a failed test.
  • Makes debugging easier.
  • Provides evidence for defect investigation.
  • Helps identify unexpected error messages.
  • Helps identify missing or incorrectly displayed elements.
  • Useful when tests run on remote machines.
  • Useful in CI/CD pipelines.
  • Improves test reports.
  • Reduces debugging time.
  • Helps identify intermittent failures.
  • Provides historical evidence of failures.
  • Can be attached to automation reports.


3. Failure Screenshot Flow

The basic failure screenshot workflow is:

TestNG starts test

        |

        v

Selenium executes test steps

        |

        v

Assertion / WebDriver operation fails

        |

        v

TestNG marks test as failed

        |

        v

ITestListener.onTestFailure()

        |

        v

Get WebDriver instance

        |

        v

TakesScreenshot

        |

        v

Capture screenshot

        |

        v

Save PNG file

        |

        v

Attach / publish screenshot

        |

        v

Test Report


4. Selenium TakesScreenshot Interface

Selenium provides the TakesScreenshot interface for screenshot capture. A WebDriver implementation that supports screenshot capture can be cast to this interface and used with getScreenshotAs().

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

import org.openqa.selenium.WebDriver;

 

TakesScreenshot screenshot = (TakesScreenshot) driver;

 

File source = screenshot.getScreenshotAs(OutputType.FILE);

The captured result can be returned as a file, byte array, or Base64 representation depending on the selected Selenium output type.


5. Basic Screenshot Capture

The simplest approach is to capture a screenshot manually inside a test or utility method.

File source = ((TakesScreenshot) driver)

        .getScreenshotAs(OutputType.FILE);

The returned file should then be copied to a permanent destination if it needs to be retained after the test execution.


6. Saving a Screenshot to a Directory

A screenshot should normally be stored in a dedicated directory such as screenshots, test-output/screenshots, or test-artifacts/screenshots.

File source = ((TakesScreenshot) driver)

        .getScreenshotAs(OutputType.FILE);

 

File destination = new File(

        "screenshots/failure.png"

);

 

FileUtils.copyFile(source, destination);

In production frameworks, use a unique filename so that one failed test does not overwrite the screenshot produced by another test.


7. Using Apache Commons IO

Apache Commons IO is commonly used in Java Selenium projects to copy the temporary screenshot file to a permanent location.

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

 

File source = ((TakesScreenshot) driver)

        .getScreenshotAs(OutputType.FILE);

 

FileUtils.copyFile(

        source,

        new File("screenshots/failure.png")

);


8. Screenshot with Timestamp

A timestamp can be included in the filename to prevent screenshots from being overwritten.

String timestamp = new SimpleDateFormat(

        "yyyyMMdd_HHmmss"

).format(new Date());

 

File source = ((TakesScreenshot) driver)

        .getScreenshotAs(OutputType.FILE);

 

File destination = new File(

        "screenshots/failure_" + timestamp + ".png"

);

 

FileUtils.copyFile(source, destination);

A timestamp is especially useful when the same test is executed repeatedly.


9. Screenshot with Test Method Name

Including the test method name makes it easier to identify which test generated the screenshot.

String methodName = result.getName();

 

String timestamp = new SimpleDateFormat(

        "yyyyMMdd_HHmmss"

).format(new Date());

 

String fileName = methodName

        + "_" + timestamp

        + ".png";

A typical filename might look like:

loginTest_20261001_132100.png


10. What is ITestListener?

ITestListener is a TestNG listener interface that provides callback methods for different test execution events.

One of its most useful methods for screenshot automation is onTestFailure().

public class FailureScreenshotListener

        implements ITestListener {

 

    @Override

    public void onTestFailure(ITestResult result) {

        System.out.println("Test failed");

    }

}

The listener can be used to automatically execute screenshot logic whenever a test fails.


11. onTestFailure() Method

The onTestFailure() callback is invoked when TestNG reports a failed test result. It receives an ITestResult object containing information about the failed test.

@Override

public void onTestFailure(ITestResult result) {

 

    System.out.println(

        "Failed Test: " + result.getName()

    );

}

The result object can be used to obtain the test method name, test class, parameters, and other execution information.


12. Basic Failure Screenshot Listener

import java.io.File;

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

import org.openqa.selenium.WebDriver;

import org.testng.ITestListener;

import org.testng.ITestResult;

 

public class FailureScreenshotListener

        implements ITestListener {

 

    private WebDriver driver;

 

    @Override

    public void onTestFailure(ITestResult result) {

 

        System.out.println(

            "Test Failed: " + result.getName()

        );

 

        if (driver instanceof TakesScreenshot) {

 

            File source =

                ((TakesScreenshot) driver)

                    .getScreenshotAs(OutputType.FILE);

 

            try {

                FileUtils.copyFile(

                    source,

                    new File(

                        "screenshots/"

                        + result.getName()

                        + ".png"

                    )

                );

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

}

In a real framework, the listener should obtain the correct WebDriver instance associated with the failed test rather than maintaining an unsafe shared driver field.


13. Why Capture Before driver.quit()?

The screenshot should be captured while the WebDriver session is still active. If the browser has already been closed using driver.quit(), the listener may no longer be able to capture the browser state.

Test fails

    |

    v

onTestFailure()

    |

    v

Capture Screenshot

    |

    v

Save Screenshot

    |

    v

@AfterMethod

    |

    v

driver.quit()

This ordering is important for reliable failure evidence.


14. Screenshot and @AfterMethod

TestNG frameworks commonly use @AfterMethod for browser cleanup.

@AfterMethod(alwaysRun = true)

public void tearDown() {

 

    if (driver != null) {

        driver.quit();

    }

}

The failure listener should capture the screenshot while the browser is still available, and teardown should perform cleanup afterward.


15. Manual Screenshot vs Automatic Screenshot

Manual ScreenshotAutomatic Failure Screenshot
Developer explicitly calls screenshot methodListener captures screenshot automatically
Useful at selected checkpointsUseful for failed tests
Requires code inside test flowCentralized implementation
Can capture successful statesUsually captures failure states
More repetitiveMore reusable


16. Registering Listener with @Listeners

TestNG allows listeners to be registered using the @Listeners annotation.

import org.testng.annotations.Listeners;

 

@Listeners(FailureScreenshotListener.class)

public class LoginTest {

 

    @Test

    public void loginTest() {

        // Test steps

    }

}

The listener can also be placed on a shared base class when the project architecture is designed to apply the listener to the relevant test classes.


17. Registering Listener in testng.xml

A listener can also be registered in the TestNG XML suite configuration.

<suite name="Automation Suite">

 

    <listeners>

        <listener

            class-name="listeners.FailureScreenshotListener"/>

    </listeners>

 

    <test name="UI Tests">

        <classes>

            <class name="tests.LoginTest"/>

        </classes>

    </test>

 

</suite>

XML registration is useful when the same listener should apply across many test classes.


18. Screenshot Utility Class

Instead of writing screenshot code repeatedly, create a reusable utility class.

public class ScreenshotUtil {

 

    public static void capture(

            WebDriver driver,

            String fileName) {

 

        try {

            File source =

                ((TakesScreenshot) driver)

                    .getScreenshotAs(OutputType.FILE);

 

            File destination =

                new File(

                    "screenshots/" + fileName

                );

 

            FileUtils.copyFile(

                source,

                destination

            );

 

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}


19. Using Screenshot Utility in a Test

@Test

public void loginTest() {

 

    driver.get(

        "https://example.com/login"

    );

 

    try {

 

        driver.findElement(

            By.id("username")

        ).sendKeys("admin");

 

        driver.findElement(

            By.id("password")

        ).sendKeys("wrong");

 

        driver.findElement(

            By.id("loginButton")

        ).click();

 

    } catch (Exception e) {

 

        ScreenshotUtil.capture(

            driver,

            "login_failure.png"

        );

 

        throw e;

    }

}

Although this approach works, a listener is usually more convenient for framework-wide automatic failure screenshots.


20. Capturing Screenshot with ITestResult

The ITestResult object can provide the failed test's method name.

@Override

public void onTestFailure(ITestResult result) {

 

    String testName =

        result.getMethod()

              .getMethodName();

 

    System.out.println(

        "Failed Test: " + testName

    );

}

This value can be incorporated into the screenshot filename.


21. Unique Screenshot Naming

Screenshot filenames should be unique, especially when tests run in parallel.

String className =

        result.getTestClass()

              .getName();

 

String methodName =

        result.getMethod()

              .getMethodName();

 

String fileName =

        className.replace(".", "_")

        + "_"

        + methodName

        + "_"

        + System.currentTimeMillis()

        + ".png";

A robust filename can contain the class name, method name, timestamp, thread ID, and retry information when required.


22. Failure Screenshot with Thread ID

Parallel test execution can cause multiple tests to fail at approximately the same time. A thread ID can help create unique filenames.

long threadId =

        Thread.currentThread().getId();

 

String fileName =

        result.getName()

        + "_thread_"

        + threadId

        + "_"

        + System.currentTimeMillis()

        + ".png";


23. Screenshot Directory Structure

A clean directory structure makes screenshots easier to locate.

test-artifacts

|

|-- screenshots

|   |-- LoginTest

|   |   |-- loginTest_001.png

|   |   |-- loginTest_002.png

|   |

|   |-- SearchTest

|       |-- searchTest_001.png

|       |-- searchTest_002.png

|

|-- reports

|   |-- testng-results.xml

|   |-- index.html


24. Screenshot and Test Reports

A screenshot file and a test report are separate artifacts. Capturing a PNG does not automatically mean that every report format will embed that image.

A reporting framework can provide an attachment mechanism, or a custom HTML report can create a relative link to the screenshot.

Test Result

    |

    +-- PASS

    |

    +-- FAIL

          |

          +-- Error Message

          +-- Stack Trace

          +-- Screenshot

          +-- Test Data


25. Adding Screenshot Link to HTML Report

A simple HTML report can link to a screenshot using a relative path.

<a href="screenshots/loginTest_failure.png"

   target="_blank">

   View Failure Screenshot

</a>

The screenshot and report should be published together so that the relative path remains valid.


26. Screenshot as Base64

Selenium can also return a screenshot as Base64 data.

String screenshot =

        ((TakesScreenshot) driver)

            .getScreenshotAs(

                OutputType.BASE64

            );

Base64 can be useful when a reporting library accepts encoded image data directly.


27. Screenshot as Bytes

Another option is to obtain the screenshot as bytes.

byte[] screenshot =

        ((TakesScreenshot) driver)

            .getScreenshotAs(

                OutputType.BYTES

            );

Byte arrays can be useful for APIs or reporting systems that accept image data without requiring a temporary file.


28. Screenshot Output Types

Output TypePurpose
OutputType.FILEReturns screenshot as a file
OutputType.BYTESReturns screenshot as byte data
OutputType.BASE64Returns screenshot as Base64 encoded data


29. Full Failure Screenshot Listener Example

import java.io.File;

import java.text.SimpleDateFormat;

import java.util.Date;

 

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

import org.openqa.selenium.WebDriver;

import org.testng.ITestListener;

import org.testng.ITestResult;

 

public class FailureScreenshotListener

        implements ITestListener {

 

    @Override

    public void onTestFailure(

            ITestResult result) {

 

        Object testInstance =

            result.getInstance();

 

        if (!(testInstance

                instanceof BaseTest)) {

            return;

        }

 

        WebDriver driver =

            ((BaseTest) testInstance)

                .getDriver();

 

        if (!(driver instanceof TakesScreenshot)) {

            return;

        }

 

        try {

 

            String timestamp =

                new SimpleDateFormat(

                    "yyyyMMdd_HHmmss"

                ).format(new Date());

 

            String methodName =

                result.getMethod()

                      .getMethodName();

 

            File source =

                ((TakesScreenshot) driver)

                    .getScreenshotAs(

                        OutputType.FILE

                    );

 

            File destination =

                new File(

                    "test-artifacts/screenshots/"

                    + methodName

                    + "_"

                    + timestamp

                    + ".png"

                );

 

            FileUtils.copyFile(

                source,

                destination

            );

 

            System.out.println(

                "Screenshot saved: "

                + destination.getAbsolutePath()

            );

 

        } catch (Exception e) {

 

            System.err.println(

                "Screenshot capture failed: "

                + e.getMessage()

            );

        }

    }

}


30. Base Test Class for Driver Access

A base test class can expose the WebDriver instance to the listener.

public class BaseTest {

 

    protected WebDriver driver;

 

    public WebDriver getDriver() {

        return driver;

    }

 

    @BeforeMethod

    public void setUp() {

 

        driver = new ChromeDriver();

 

        driver.manage()

              .window()

              .maximize();

    }

 

    @AfterMethod(alwaysRun = true)

    public void tearDown() {

 

        if (driver != null) {

            driver.quit();

            driver = null;

        }

    }

}


31. Failure Screenshot with Base Test

@Listeners(FailureScreenshotListener.class)

public class LoginTest extends BaseTest {

 

    @Test

    public void loginTest() {

 

        driver.get(

            "https://example.com/login"

        );

 

        driver.findElement(

            By.id("username")

        ).sendKeys("admin");

 

        driver.findElement(

            By.id("password")

        ).sendKeys("wrong");

 

        driver.findElement(

            By.id("loginButton")

        ).click();

 

        Assert.assertTrue(

            driver.getTitle()

                  .contains("Dashboard")

        );

    }

}

If the assertion fails, the listener can capture the browser state before the driver is closed by teardown.


32. Failure Screenshots for Assertions

Failure screenshots are particularly useful when assertions fail.

String actualTitle =

        driver.getTitle();

 

Assert.assertEquals(

        actualTitle,

        "Dashboard"

);

If the actual title is different, the screenshot can show the page that was actually displayed at the time of failure.


33. Failure Screenshots for Element Not Found

A screenshot can also help investigate NoSuchElementException failures.

driver.findElement(

    By.id("loginButton")

).click();

If the element is missing, the screenshot may show an unexpected page, loading state, popup, error message, or changed UI.


34. Failure Screenshots for Timeout Failures

Synchronization failures can also benefit from screenshots.

WebDriverWait wait =

        new WebDriverWait(

            driver,

            Duration.ofSeconds(10)

        );

 

wait.until(

    ExpectedConditions

        .visibilityOfElementLocated(

            By.id("dashboard")

        )

);

If the expected element does not appear, a screenshot can provide additional information about the browser state.


35. Failure Screenshots for Wrong URL

Assert.assertEquals(

    driver.getCurrentUrl(),

    "https://example.com/dashboard"

);

A failure screenshot can help determine whether the application displayed an error page, login page, redirect page, or another unexpected screen.


36. Failure Screenshots for Wrong Page Title

Assert.assertEquals(

    driver.getTitle(),

    "Dashboard"

);

The screenshot provides visual evidence in addition to the assertion failure message.


37. Failure Screenshots for Login Testing

Login automation is one of the most common use cases.

@DataProvider(name = "loginData")

public Object[][] loginData() {

 

    return new Object[][] {

        {"admin", "admin123"},

        {"manager", "manager123"},

        {"invalid", "wrong123"}

    };

}

 

@Test(dataProvider = "loginData")

public void loginTest(

        String username,

        String password) {

 

    driver.findElement(

        By.id("username")

    ).sendKeys(username);

 

    driver.findElement(

        By.id("password")

    ).sendKeys(password);

 

    driver.findElement(

        By.id("loginButton")

    ).click();

 

    Assert.assertTrue(

        driver.getTitle()

              .contains("Dashboard")

    );

}

When a particular data set fails, the framework should make it possible to identify the corresponding screenshot without exposing sensitive credentials.


38. Failure Screenshots with Data Providers

Data Providers create multiple test invocations from different data sets. When screenshots are captured, filenames should distinguish different invocations.

loginTest_admin_001.png

loginTest_manager_002.png

loginTest_invalid_003.png

Do not include passwords, tokens, session identifiers, or other secrets in filenames.


39. Failure Screenshots in Parallel Execution

Parallel execution requires special attention because multiple WebDriver sessions may be active at the same time.

Thread 1

   |

   +-- Chrome

   +-- LoginTest

   +-- failure_001.png

 

Thread 2

   |

   +-- Firefox

   +-- SearchTest

   +-- failure_002.png

 

Thread 3

   |

   +-- Edge

   +-- CheckoutTest

   +-- failure_003.png

Each test invocation should have access to its own WebDriver instance, and screenshot filenames should be unique.


40. ThreadLocal WebDriver

A common framework approach for parallel Selenium execution is to maintain a WebDriver instance per thread.

public class DriverManager {

 

    private static ThreadLocal<WebDriver>

            driver = new ThreadLocal<>();

 

    public static void setDriver(

            WebDriver webDriver) {

 

        driver.set(webDriver);

    }

 

    public static WebDriver getDriver() {

 

        return driver.get();

    }

 

    public static void quitDriver() {

 

        if (driver.get() != null) {

            driver.get().quit();

            driver.remove();

        }

    }

}

This architecture helps the screenshot listener obtain the driver associated with the correct execution context.


41. Screenshot Naming in Parallel Tests

A parallel-safe screenshot filename can include class, method, thread, timestamp, and a unique identifier.

String fileName =

        result.getTestClass()

              .getName()

        + "_"

        + result.getMethod()

              .getMethodName()

        + "_thread_"

        + Thread.currentThread().getId()

        + "_"

        + System.currentTimeMillis()

        + ".png";


42. Screenshot and Retry Analyzer

Some TestNG frameworks retry failed tests. When retries are used, decide whether each failed attempt should produce a separate screenshot.

Attempt 1

   |

   +-- FAIL

   +-- screenshot_attempt_1.png

   |

   v

Retry

   |

Attempt 2

   |

   +-- FAIL

   +-- screenshot_attempt_2.png

Keeping separate screenshots can be useful when investigating flaky tests because each attempt may show a different browser state.


43. Failure Screenshots and Flaky Tests

A flaky test may pass during one execution and fail during another. Failure screenshots can help compare the visual state of different failed executions.

  • Compare page loading state.
  • Check unexpected popups.
  • Check missing elements.
  • Check stale or incomplete page content.
  • Check unexpected redirects.
  • Check browser-level error messages.


44. Screenshot and Browser Alerts

Unexpected JavaScript alerts can interfere with screenshot commands and WebDriver interactions. The framework should handle such situations carefully and preserve the original failure information.

try {

 

    driver.findElement(

        By.id("submit")

    ).click();

 

} catch (Exception e) {

 

    ScreenshotUtil.capture(

        driver,

        "alert_failure.png"

    );

 

    throw e;

}


45. Screenshot and Multiple Windows

If a test opens multiple browser windows or tabs, the screenshot represents the current WebDriver context. The framework should make sure the correct window is selected before attempting the capture.

String mainWindow =

        driver.getWindowHandle();

 

for (String handle :

        driver.getWindowHandles()) {

 

    driver.switchTo()

          .window(handle);

}


46. Screenshot and Frames

When working with iframes, the current WebDriver context matters. A screenshot may reflect the current browser state, while an element-level screenshot can target a specific element.

driver.switchTo()

      .frame("paymentFrame");

 

driver.findElement(

    By.id("cardNumber")

).sendKeys("1234");


47. Full Page vs Viewport Screenshot

A standard WebDriver screenshot should not automatically be treated as a guaranteed full-page capture. The captured area can depend on the browser, driver, implementation, and capture method.

For ordinary failure debugging, the visible browser state is often useful. If complete-page evidence is required, use a browser or framework capability that explicitly supports the desired full-page behavior.


48. Element Screenshot

Selenium can also capture a screenshot of an individual element when supported by the WebElement screenshot functionality.

WebElement logo =

        driver.findElement(

            By.id("logo")

        );

 

File source =

        logo.getScreenshotAs(

            OutputType.FILE

        );

Element screenshots are useful when the failure is specifically related to one component of the page.


49. Screenshot on Success vs Failure

Failure ScreenshotSuccess Screenshot
Captured when test failsCaptured when test passes or at selected checkpoints
Primarily for debuggingPrimarily for evidence or documentation
Reduces unnecessary filesCan produce many artifacts
Useful in CI/CDUseful for business evidence


50. Screenshot Storage Strategy

A framework should define where screenshots are stored and how long they are retained.

Project

|

|-- test-artifacts

|   |-- screenshots

|   |-- logs

|   |-- reports

|

|-- src

|   |-- test

|       |-- java

|       |-- resources

For CI systems, the screenshot directory should be configured as a build artifact when the project requires screenshots to remain accessible after the workspace is cleaned.


51. Screenshot and Jenkins

Jenkins can publish test results and retain build artifacts. Screenshot files should be stored in a predictable directory and configured as artifacts when they need to be available after the build.

Jenkins Job

     |

     v

Checkout Code

     |

     v

Maven Build

     |

     v

TestNG Tests

     |

     v

Failure

     |

     v

Screenshot

     |

     v

test-artifacts/screenshots

     |

     v

Publish Artifacts

     |

     v

Jenkins Build Results

Publishing the test result and publishing screenshot files are separate concerns; both should be configured when visual failure evidence is required.


52. Screenshot and Maven

A Maven-based Selenium TestNG project can store screenshots under the build output directory.

mvn clean test

A common project structure is:

target

|

|-- test-output

|   |-- screenshots

|   |-- reports

|

|-- surefire-reports


53. Screenshot and CI/CD Pipeline

Developer Commit

       |

       v

CI Pipeline

       |

       v

Build

       |

       v

Execute Tests

       |

       +---- PASS

       |

       +---- FAIL

               |

               v

        Capture Screenshot

               |

               v

        Save Test Artifact

               |

               v

        Generate Report

               |

               v

        Publish Results


54. Failure Screenshots and Logs

Screenshots should complement logs rather than replace them.

EvidenceProvides
ScreenshotVisual browser state
LogExecution information
Stack TraceTechnical failure location
Test ReportOverall execution result
Test DataInput used for execution


55. Avoid Exposing Sensitive Information

Screenshots can contain sensitive information such as usernames, personal information, tokens, account details, or business data. Test frameworks should consider the sensitivity of captured browser content.

  • Do not intentionally capture passwords.
  • Do not include credentials in screenshot filenames.
  • Avoid logging authentication tokens.
  • Control access to screenshot artifacts.
  • Apply retention policies to test artifacts.
  • Mask sensitive information where practical.


56. Common Mistakes in Failure Screenshots

  • Calling driver.quit() before screenshot capture.
  • Using a shared WebDriver in parallel tests.
  • Using the same filename for every failure.
  • Not creating the screenshot directory.
  • Ignoring screenshot exceptions completely.
  • Overwriting screenshots from retry attempts.
  • Storing screenshots outside the published CI artifact directory.
  • Putting passwords or tokens in filenames.
  • Assuming every screenshot is automatically embedded in every report.
  • Capturing screenshots without identifying the corresponding test.
  • Using a static driver for concurrent test execution.


57. Best Practices for Failure Screenshots

  • Use ITestListener for centralized failure handling.
  • Capture the screenshot before the WebDriver session is closed.
  • Use unique filenames.
  • Include test class and method information.
  • Include thread information for parallel execution.
  • Keep screenshots in a dedicated artifact directory.
  • Publish screenshots with CI build artifacts when required.
  • Keep screenshot failures secondary to the original test failure.
  • Use thread-safe WebDriver management.
  • Avoid sensitive information in filenames and logs.
  • Use external reporting tools when richer attachments are required.
  • Keep screenshot utilities reusable.
  • Clean old artifacts according to project retention requirements.


58. Screenshot Capture Should Not Hide Original Failure

The screenshot operation is diagnostic support. If screenshot capture itself fails, it should not replace the original assertion or WebDriver failure.

try {

 

    captureScreenshot(driver);

 

} catch (Exception screenshotError) {

 

    System.err.println(

        "Screenshot failed: "

        + screenshotError.getMessage()

    );

}

 

// Preserve the original test failure

This approach helps keep the original failure as the primary diagnostic information.


59. Handling Screenshot Capture Exceptions

try {

 

    File source =

        ((TakesScreenshot) driver)

            .getScreenshotAs(

                OutputType.FILE

            );

 

    FileUtils.copyFile(

        source,

        destination

    );

 

} catch (Exception e) {

 

    System.err.println(

        "Unable to capture screenshot: "

        + e.getMessage()

    );

}

Capture errors can occur when the browser session has already ended, the driver does not support the requested operation, the destination cannot be written, or another runtime problem occurs.


60. Practical Screenshot Utility

public class ScreenshotUtil {

 

    public static String capture(

            WebDriver driver,

            String testName) {

 

        String timestamp =

            new SimpleDateFormat(

                "yyyyMMdd_HHmmss"

            ).format(new Date());

 

        String fileName =

            testName

            + "_"

            + timestamp

            + ".png";

 

        File destination =

            new File(

                "test-artifacts/screenshots/"

                + fileName

            );

 

        try {

 

            File source =

                ((TakesScreenshot) driver)

                    .getScreenshotAs(

                        OutputType.FILE

                    );

 

            FileUtils.copyFile(

                source,

                destination

            );

 

            return destination

                .getAbsolutePath();

 

        } catch (Exception e) {

 

            System.err.println(

                "Screenshot failed: "

                + e.getMessage()

            );

 

            return null;

        }

    }

}


61. Complete Listener Architecture

                TestNG

                   |

                   v

             Test Execution

                   |

                   v

              Test Failure

                   |

                   v

         ITestListener

                   |

                   v

            onTestFailure()

                   |

                   v

         Identify Test Instance

                   |

                   v

           Get WebDriver

                   |

                   v

          TakesScreenshot

                   |

                   v

          Capture Image

                   |

                   v

         Unique File Name

                   |

                   v

       Save Test Artifact

                   |

          +--------+--------+

          |                 |

          v                 v

      HTML Report       CI Artifact

          |                 |

          +--------+--------+

                   |

                   v

             Test Evidence


62. Practical Project Structure

src

|-- test

    |-- java

        |-- tests

        |   |-- LoginTest.java

        |   |-- SearchTest.java

        |   |-- CheckoutTest.java

        |

        |-- listeners

        |   |-- FailureScreenshotListener.java

        |

        |-- utilities

        |   |-- ScreenshotUtil.java

        |   |-- DriverManager.java

        |

        |-- base

            |-- BaseTest.java

 

test-artifacts

|-- screenshots

|-- reports

|-- logs


63. Complete Practical Failure Screenshot Example

import java.io.File;

import java.text.SimpleDateFormat;

import java.util.Date;

 

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.By;

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

 

import org.testng.Assert;

import org.testng.ITestListener;

import org.testng.ITestResult;

import org.testng.annotations.AfterMethod;

import org.testng.annotations.BeforeMethod;

import org.testng.annotations.Listeners;

import org.testng.annotations.Test;

 

@Listeners(FailureScreenshotListener.class)

public class LoginTest {

 

    private WebDriver driver;

 

    @BeforeMethod

    public void setUp() {

 

        driver = new ChromeDriver();

 

        driver.manage()

              .window()

              .maximize();

 

        driver.get(

            "https://example.com/login"

        );

    }

 

    @Test

    public void loginTest() {

 

        driver.findElement(

            By.id("username")

        ).sendKeys("admin");

 

        driver.findElement(

            By.id("password")

        ).sendKeys("admin123");

 

        driver.findElement(

            By.id("loginButton")

        ).click();

 

        Assert.assertTrue(

            driver.getTitle()

                  .contains("Dashboard")

        );

    }

 

    public WebDriver getDriver() {

        return driver;

    }

 

    @AfterMethod(alwaysRun = true)

    public void tearDown() {

 

        if (driver != null) {

            driver.quit();

            driver = null;

        }

    }

}


64. Complete FailureScreenshotListener Example

import java.io.File;

 

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

import org.openqa.selenium.WebDriver;

import org.testng.ITestListener;

import org.testng.ITestResult;

 

public class FailureScreenshotListener

        implements ITestListener {

 

    @Override

    public void onTestFailure(

            ITestResult result) {

 

        try {

 

            Object instance =

                result.getInstance();

 

            if (!(instance

                    instanceof LoginTest)) {

                return;

            }

 

            LoginTest test =

                (LoginTest) instance;

 

            WebDriver driver =

                test.getDriver();

 

            if (!(driver instanceof TakesScreenshot)) {

                return;

            }

 

            File source =

                ((TakesScreenshot) driver)

                    .getScreenshotAs(

                        OutputType.FILE

                    );

 

            String testName =

                result.getMethod()

                      .getMethodName();

 

            File destination =

                new File(

                    "test-artifacts/screenshots/"

                    + testName

                    + "_"

                    + System.currentTimeMillis()

                    + ".png"

                );

 

            FileUtils.copyFile(

                source,

                destination

            );

 

            System.out.println(

                "Failure screenshot saved: "

                + destination

                    .getAbsolutePath()

            );

 

        } catch (Exception e) {

 

            System.err.println(

                "Could not capture failure screenshot: "

                + e.getMessage()

            );

        }

    }

}


65. Failure Screenshot with Data Provider

Failure screenshots become even more useful when a Data Provider executes the same test with multiple data sets.

@DataProvider(name = "products")

public Object[][] products() {

 

    return new Object[][] {

        {"Laptop"},

        {"Mobile"},

        {"Tablet"},

        {"Headphones"}

    };

}

 

@Test(dataProvider = "products")

public void searchTest(String product) {

 

    driver.findElement(

        By.id("search")

    ).sendKeys(product);

 

    driver.findElement(

        By.id("searchButton")

    ).click();

 

    Assert.assertTrue(

        driver.getTitle()

              .contains(product)

    );

}

A robust framework can include a sanitized product identifier in the screenshot filename so the failed data set is easier to identify.


66. Failure Screenshots with Page Object Model

Failure screenshots can be integrated with the Page Object Model. The page classes handle browser interaction while the listener handles failure evidence.

Test Class

    |

    v

Page Object

    |

    v

Selenium WebDriver

    |

    v

Application

    |

    v

Failure

    |

    v

TestNG Listener

    |

    v

Screenshot Utility

This separation keeps screenshot management independent from page-specific Selenium interactions.


67. Failure Screenshots and Reporting Tools

Reporting tools can provide richer ways to display screenshots alongside test results. The exact attachment mechanism depends on the reporting library and project configuration.

A common architecture is:

TestNG

  |

  +-- Test Result

  |

  +-- Failure Details

  |

  +-- Screenshot

  |

  +-- Logs

  |

  v

Automation Report

When using a third-party reporting library, follow that library's supported screenshot attachment API rather than assuming that saving a PNG automatically embeds it into the report.


68. Failure Screenshots in Regression Testing

Regression suites can contain hundreds or thousands of automated tests. Automatically capturing screenshots only when tests fail can provide useful debugging evidence without generating screenshots for every successful execution.

For regression automation, combine screenshots with:

  • Test name.
  • Failure message.
  • Stack trace.
  • Browser name.
  • Environment.
  • Test data identifier.
  • Timestamp.
  • Execution thread.


69. Failure Screenshots in Cross-Browser Testing

When the same test executes on Chrome, Firefox, and Edge, the screenshot filename should identify the browser.

LoginTest_Chrome_failure.png

LoginTest_Firefox_failure.png

LoginTest_Edge_failure.png

This makes browser-specific failures easier to investigate.


70. Cross-Browser Failure Architecture

                 TestNG

                    |

        +-----------+-----------+

        |           |           |

      Chrome      Firefox      Edge

        |           |           |

        v           v           v

     Test A       Test A       Test A

        |           |           |

        v           v           v

     Failure      Pass        Failure

        |                       |

        v                       v

   Screenshot              Screenshot

        |                       |

        +-----------+-----------+

                    |

                    v

                 Report


71. Failure Screenshot and Environment

Testing across QA, staging, and production-like environments can create similar failures with different visual states. The environment name can be included in the screenshot path.

screenshots

|

|-- QA

|   |-- LoginTest_failure.png

|

|-- Stage

|   |-- LoginTest_failure.png

|

|-- Production

    |-- LoginTest_failure.png


72. Failure Screenshot and Browser Information

For large automation suites, it can be useful to record browser information alongside screenshot metadata.

Browser: Chrome

Environment: QA

Test: LoginTest

Method: validLogin

Thread: 4

Timestamp: 20261001_132100

Screenshot: LoginTest_validLogin_4.png

This information can be stored in logs or reports without putting unnecessary sensitive information into the image filename.


73. Failure Screenshots for E-Commerce Testing

E-commerce applications contain many workflows where failure screenshots are valuable.

  • Login.
  • Product search.
  • Product details.
  • Add to cart.
  • Cart validation.
  • Checkout.
  • Address selection.
  • Payment page.
  • Order confirmation.
  • Order history.

Search

  |

  v

Product

  |

  v

Cart

  |

  v

Checkout

  |

  v

Payment

  |

  v

Confirmation

  |

  +---- Failure Screenshot


74. Failure Screenshots for Form Testing

Forms are another common use case because visual evidence can show validation messages and incorrectly displayed fields.

Registration Form

       |

       +-- Name

       +-- Email

       +-- Mobile

       +-- Password

       +-- Confirm Password

       |

       v

Submit

       |

       v

Validation

       |

       +-- PASS

       |

       +-- FAIL

              |

              v

       Failure Screenshot


75. Failure Screenshots for UI Validation

UI automation often verifies visibility, text, buttons, labels, menus, images, and page layouts. A screenshot can provide useful visual context when such checks fail.

Assert element visible

        |

        v

Element missing

        |

        v

Test Failure

        |

        v

Screenshot

        |

        v

Visual Investigation


76. Failure Screenshots for Navigation Testing

Home

 |

 v

Login

 |

 v

Dashboard

 |

 v

Profile

 |

 v

Settings

 |

 v

Unexpected Page

 |

 v

Failure Screenshot

The screenshot can help determine which page was displayed when navigation validation failed.


77. Failure Screenshot Retention

Screenshot files can accumulate rapidly in large test suites. Define a retention strategy for local and CI environments.

  • Keep recent failed-test screenshots.
  • Archive screenshots for important release builds.
  • Remove obsolete artifacts.
  • Use CI artifact retention settings.
  • Keep production-sensitive artifacts access-controlled.


78. Performance Considerations

Screenshot capture adds file-generation and storage work when a failure occurs. In normal failure-only designs, successful tests do not generate screenshot files.

For very large suites, avoid unnecessarily capturing multiple copies of the same failure and keep the listener lightweight.


79. Troubleshooting Failure Screenshots

ProblemPossible CauseSolution
No screenshotListener not registeredCheck @Listeners or testng.xml
No screenshotDriver is nullInitialize driver before test
No screenshotDriver already closedCapture before quit()
Files overwrittenDuplicate filenameUse timestamp/UUID/thread ID
Screenshot not in CIArtifact not publishedPublish screenshot directory
Wrong browser screenshotShared driverUse isolated driver instances
Blank/incomplete imageBrowser state or capture limitationCheck browser state and capture timing
Original failure hiddenScreenshot exception replaces failureHandle screenshot exception separately


80. Common Failure Screenshot Architecture Mistakes

  • Using a static WebDriver for parallel execution.
  • Capturing the screenshot after browser teardown.
  • Not registering the listener.
  • Using an incorrect driver reference.
  • Saving all screenshots with the same name.
  • Not creating the destination directory.
  • Not copying temporary screenshot files to durable storage.
  • Not publishing screenshots in CI.
  • Including credentials in screenshot names.
  • Allowing screenshot errors to hide the original test failure.


81. Best Practices Checklist

  • Use a reusable Screenshot Utility.
  • Use TestNG ITestListener for automatic failure capture.
  • Capture screenshots before WebDriver teardown.
  • Use unique and meaningful filenames.
  • Include class and method names.
  • Include browser and environment information where useful.
  • Use thread-safe driver management for parallel tests.
  • Store screenshots in a predictable directory.
  • Publish screenshots as CI artifacts.
  • Integrate screenshots with reports where supported.
  • Do not expose sensitive information.
  • Preserve the original assertion or WebDriver exception.
  • Clean up old artifacts according to project requirements.


82. Interview Questions on Failure Screenshots

1. What is a failure screenshot?

A failure screenshot is an image captured from the browser when an automated test fails.

2. Which Selenium interface is used for screenshots?

The TakesScreenshot interface is commonly used for browser screenshot capture.

3. Which Selenium method captures a screenshot?

The getScreenshotAs() method is used to obtain screenshot output.

4. Which TestNG listener method is commonly used for failure screenshots?

onTestFailure(ITestResult result) is commonly used.

5. Why should screenshots be captured before driver.quit()?

Because the browser session needs to remain available for the screenshot operation.

6. How can a listener be registered in TestNG?

It can be registered using @Listeners or through testng.xml.

7. Why should screenshot filenames be unique?

Unique names prevent one failure from overwriting another screenshot.

8. How can timestamps be added to screenshots?

A Java date/time formatter or another unique identifier can be included in the filename.

9. Can screenshots be used with Data Providers?

Yes. Screenshot filenames can identify the test invocation while avoiding sensitive test data.

10. Can screenshots be used with Page Object Model?

Yes. Screenshot handling can remain in a listener or utility while page objects manage application interactions.

11. Can screenshots be captured during parallel execution?

Yes, but each test invocation should use an appropriate isolated WebDriver and unique screenshot destination.

12. What is OutputType.FILE?

It requests the screenshot as a file representation.

13. What is OutputType.BYTES?

It returns the screenshot as byte data, which can be useful for report attachment APIs.

14. What is OutputType.BASE64?

It returns the screenshot as Base64 encoded data.

15. Does saving a PNG automatically attach it to every TestNG report?

No. Saving the image and attaching or linking it in a particular report are separate operations.

16. Why should screenshot exceptions not replace the original failure?

The original test failure contains the primary diagnostic information and should remain visible even if screenshot capture fails.

17. Can screenshots be published in Jenkins?

Yes. The screenshot directory can be retained and published as a build artifact.

18. What information should not be included in screenshot filenames?

Passwords, tokens, session identifiers, and other sensitive information should not be included.

19. Why are screenshots useful in CI/CD?

They provide visual evidence when the browser executes on a remote build agent where the tester cannot directly observe the browser.

20. What is the biggest advantage of automatic failure screenshots?

They provide reusable visual evidence automatically whenever a test fails, reducing the need for manual reproduction.


83. Quick Reference Table

ConceptDescription
TakesScreenshotSelenium interface for screenshot capture
getScreenshotAs()Captures screenshot output
OutputType.FILEReturns screenshot as a file
OutputType.BYTESReturns screenshot bytes
OutputType.BASE64Returns Base64 screenshot data
ITestListenerTestNG listener interface
onTestFailure()Callback used for failed-test handling
@ListenersRegisters a TestNG listener
testng.xmlCan register listeners at suite level
Screenshot UtilityReusable screenshot capture component
ThreadLocal WebDriverCommon approach for thread-specific drivers
CI ArtifactPersistent build output such as screenshots


84. Learning Roadmap for Failure Screenshots

  1. Understand Selenium WebDriver.
  2. Learn Selenium screenshot concepts.
  3. Learn the TakesScreenshot interface.
  4. Understand getScreenshotAs().
  5. Learn OutputType.FILE.
  6. Learn OutputType.BYTES and BASE64.
  7. Create a Screenshot Utility.
  8. Learn TestNG listeners.
  9. Implement ITestListener.
  10. Implement onTestFailure().
  11. Register listeners using @Listeners.
  12. Register listeners using testng.xml.
  13. Integrate screenshots with Page Object Model.
  14. Integrate screenshots with Data Providers.
  15. Handle parallel execution safely.
  16. Publish screenshots in CI/CD.
  17. Integrate screenshots with test reports.
  18. Apply security and retention practices.


85. Practical Exercises

  1. Create a Selenium Screenshot Utility.
  2. Capture a screenshot manually after a button click.
  3. Create a TestNG ITestListener.
  4. Capture a screenshot inside onTestFailure().
  5. Register the listener using @Listeners.
  6. Register the listener using testng.xml.
  7. Add timestamps to screenshot filenames.
  8. Add test method names to screenshot filenames.
  9. Integrate screenshots with a LoginTest.
  10. Integrate screenshots with a Data Provider.
  11. Integrate screenshots with Page Object Model.
  12. Execute tests in parallel and create unique screenshot names.
  13. Publish screenshots as Maven/CI artifacts.
  14. Create an HTML report with screenshot links.
  15. Implement a complete failure evidence framework.


86. Real-World Failure Investigation Example

Suppose a checkout test fails because the expected confirmation message is not displayed.

Checkout Test

     |

     v

Add Product

     |

     v

Open Cart

     |

     v

Checkout

     |

     v

Place Order

     |

     v

Assert Confirmation

     |

     X

Test Failed

     |

     v

ITestListener

     |

     v

Failure Screenshot

     |

     +-- Browser State

     +-- Error Message

     +-- Test Name

     +-- Timestamp

     |

     v

Report / CI Artifact

The QA engineer can inspect the screenshot together with the stack trace and logs to understand what happened during the failed execution.


87. Recommended Framework Architecture

                    Selenium Test Framework

                              |

          +-------------------+-------------------+

          |                   |                   |

       Tests              Page Objects       Utilities

          |                   |                   |

          |                   |          +--------+--------+

          |                   |          |                 |

          |                   |       Driver           Screenshot

          |                   |       Manager           Utility

          |                   |          |                 |

          +-------------------+----------+-----------------+

                              |

                              v

                           TestNG

                              |

                              v

                       ITestListener

                              |

                              v

                    Failure Screenshot

                              |

                    +---------+---------+

                    |                   |

                    v                   v

                 Report             CI Artifact


88. Summary

Failure screenshots are an important part of a professional Selenium automation framework because they provide visual evidence of the browser state when an automated test fails.

Selenium provides the TakesScreenshot interface and getScreenshotAs() method for screenshot capture. TestNG's ITestListener and onTestFailure() provide a convenient mechanism for automatically triggering screenshot capture when tests fail.

A robust implementation should capture the screenshot while the WebDriver session is still active, save the image to a durable and predictable location, use unique filenames, and publish the screenshot with the test results when required.

For advanced Selenium frameworks, failure screenshots can be combined with Page Object Model, Data Providers, parallel execution, reusable Driver Managers, Maven, CI/CD, Jenkins, logs, and reporting systems.


89. Final Takeaway

Failure Screenshots = Test Failure + Visual Evidence.

A good Selenium framework should not only tell the team that a test failed; it should also make it easier to understand what the browser looked like at the time of failure. By combining Selenium screenshot capabilities with TestNG listeners, reusable utilities, proper WebDriver management, unique filenames, and CI artifact publishing, failure investigation becomes more structured and efficient.


90. Course Resources

Learn more about Selenium automation, WebDriver, TestNG, Page Object Model, and related automation testing concepts:

Quick Revision: Use TakesScreenshot to capture screenshots, use ITestListener.onTestFailure() for automatic failure handling, capture before driver.quit(), use unique filenames, keep WebDriver thread-safe for parallel execution, preserve the original failure, and publish screenshots as test artifacts when running automation in CI/CD.

whatsapp