Popular Searches
Popular Course Categories
Popular Courses

Failure Screenshots

Screenshots & Reporting

<div class="selenium-notes">

<h1>Failure Screenshots in Selenium TestNG</h1>

<p><strong>Failure Screenshots</strong> 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.</p>

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

<p>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.</p>

<p><strong>Course Resource:</strong> <a href="https://www.justacademy.co/course-detail/selenium-training" target="_blank" rel="noopener noreferrer">Selenium Training</a> | <a href="https://www.justacademy.co/register-for-course-demo" target="_blank" rel="noopener noreferrer">Register for Course Demo</a></p>

<hr>

<h2>1. What are Failure Screenshots?</h2>

<p>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.</p>

<p>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.</p>

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

<hr>

<h2>2. Why are Failure Screenshots Important?</h2>

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

<ul>

<li>Helps identify the visual state of a failed test.</li>

<li>Makes debugging easier.</li>

<li>Provides evidence for defect investigation.</li>

<li>Helps identify unexpected error messages.</li>

<li>Helps identify missing or incorrectly displayed elements.</li>

<li>Useful when tests run on remote machines.</li>

<li>Useful in CI/CD pipelines.</li>

<li>Improves test reports.</li>

<li>Reduces debugging time.</li>

<li>Helps identify intermittent failures.</li>

<li>Provides historical evidence of failures.</li>

<li>Can be attached to automation reports.</li>

</ul>

<hr>

<h2>3. Failure Screenshot Flow</h2>

<p>The basic failure screenshot workflow is:</p>

<pre><code>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</code></pre>

<hr>

<h2>4. Selenium TakesScreenshot Interface</h2>

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

<pre><code>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);</code></pre>

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

<hr>

<h2>5. Basic Screenshot Capture</h2>

<p>The simplest approach is to capture a screenshot manually inside a test or utility method.</p>

<pre><code>File source = ((TakesScreenshot) driver)

        .getScreenshotAs(OutputType.FILE);</code></pre>

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

<hr>

<h2>6. Saving a Screenshot to a Directory</h2>

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

<pre><code>File source = ((TakesScreenshot) driver)

        .getScreenshotAs(OutputType.FILE);

 

File destination = new File(

        "screenshots/failure.png"

);

 

FileUtils.copyFile(source, destination);</code></pre>

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

<hr>

<h2>7. Using Apache Commons IO</h2>

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

<pre><code>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")

);</code></pre>

<hr>

<h2>8. Screenshot with Timestamp</h2>

<p>A timestamp can be included in the filename to prevent screenshots from being overwritten.</p>

<pre><code>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);</code></pre>

<p>A timestamp is especially useful when the same test is executed repeatedly.</p>

<hr>

<h2>9. Screenshot with Test Method Name</h2>

<p>Including the test method name makes it easier to identify which test generated the screenshot.</p>

<pre><code>String methodName = result.getName();

 

String timestamp = new SimpleDateFormat(

        "yyyyMMdd_HHmmss"

).format(new Date());

 

String fileName = methodName

        + "_" + timestamp

        + ".png";</code></pre>

<p>A typical filename might look like:</p>

<pre><code>loginTest_20261001_132100.png</code></pre>

<hr>

<h2>10. What is ITestListener?</h2>

<p><strong>ITestListener</strong> is a TestNG listener interface that provides callback methods for different test execution events.</p>

<p>One of its most useful methods for screenshot automation is <strong>onTestFailure()</strong>.</p>

<pre><code>public class FailureScreenshotListener

        implements ITestListener {

 

    @Override

    public void onTestFailure(ITestResult result) {

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

    }

}</code></pre>

<p>The listener can be used to automatically execute screenshot logic whenever a test fails.</p>

<hr>

<h2>11. onTestFailure() Method</h2>

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

<pre><code>@Override

public void onTestFailure(ITestResult result) {

 

    System.out.println(

        "Failed Test: " + result.getName()

    );

}</code></pre>

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

<hr>

<h2>12. Basic Failure Screenshot Listener</h2>

<pre><code>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();

            }

        }

    }

}</code></pre>

<p>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.</p>

<hr>

<h2>13. Why Capture Before driver.quit()?</h2>

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

<pre><code>Test fails

    |

    v

onTestFailure()

    |

    v

Capture Screenshot

    |

    v

Save Screenshot

    |

    v

@AfterMethod

    |

    v

driver.quit()</code></pre>

<p>This ordering is important for reliable failure evidence.</p>

<hr>

<h2>14. Screenshot and @AfterMethod</h2>

<p>TestNG frameworks commonly use <strong>@AfterMethod</strong> for browser cleanup.</p>

<pre><code>@AfterMethod(alwaysRun = true)

public void tearDown() {

 

    if (driver != null) {

        driver.quit();

    }

}</code></pre>

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

<hr>

<h2>15. Manual Screenshot vs Automatic Screenshot</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Manual Screenshot</th><th>Automatic Failure Screenshot</th></tr>

<tr><td>Developer explicitly calls screenshot method</td><td>Listener captures screenshot automatically</td></tr>

<tr><td>Useful at selected checkpoints</td><td>Useful for failed tests</td></tr>

<tr><td>Requires code inside test flow</td><td>Centralized implementation</td></tr>

<tr><td>Can capture successful states</td><td>Usually captures failure states</td></tr>

<tr><td>More repetitive</td><td>More reusable</td></tr>

</table>

<hr>

<h2>16. Registering Listener with @Listeners</h2>

<p>TestNG allows listeners to be registered using the <strong>@Listeners</strong> annotation.</p>

<pre><code>import org.testng.annotations.Listeners;

 

@Listeners(FailureScreenshotListener.class)

public class LoginTest {

 

    @Test

    public void loginTest() {

        // Test steps

    }

}</code></pre>

<p>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.</p>

<hr>

<h2>17. Registering Listener in testng.xml</h2>

<p>A listener can also be registered in the TestNG XML suite configuration.</p>

<pre><code>&lt;suite name="Automation Suite"&gt;

 

    &lt;listeners&gt;

        &lt;listener

            class-name="listeners.FailureScreenshotListener"/&gt;

    &lt;/listeners&gt;

 

    &lt;test name="UI Tests"&gt;

        &lt;classes&gt;

            &lt;class name="tests.LoginTest"/&gt;

        &lt;/classes&gt;

    &lt;/test&gt;

 

&lt;/suite&gt;</code></pre>

<p>XML registration is useful when the same listener should apply across many test classes.</p>

<hr>

<h2>18. Screenshot Utility Class</h2>

<p>Instead of writing screenshot code repeatedly, create a reusable utility class.</p>

<pre><code>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();

        }

    }

}</code></pre>

<hr>

<h2>19. Using Screenshot Utility in a Test</h2>

<pre><code>@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;

    }

}</code></pre>

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

<hr>

<h2>20. Capturing Screenshot with ITestResult</h2>

<p>The <strong>ITestResult</strong> object can provide the failed test's method name.</p>

<pre><code>@Override

public void onTestFailure(ITestResult result) {

 

    String testName =

        result.getMethod()

              .getMethodName();

 

    System.out.println(

        "Failed Test: " + testName

    );

}</code></pre>

<p>This value can be incorporated into the screenshot filename.</p>

<hr>

<h2>21. Unique Screenshot Naming</h2>

<p>Screenshot filenames should be unique, especially when tests run in parallel.</p>

<pre><code>String className =

        result.getTestClass()

              .getName();

 

String methodName =

        result.getMethod()

              .getMethodName();

 

String fileName =

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

        + "_"

        + methodName

        + "_"

        + System.currentTimeMillis()

        + ".png";</code></pre>

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

<hr>

<h2>22. Failure Screenshot with Thread ID</h2>

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

<pre><code>long threadId =

        Thread.currentThread().getId();

 

String fileName =

        result.getName()

        + "_thread_"

        + threadId

        + "_"

        + System.currentTimeMillis()

        + ".png";</code></pre>

<hr>

<h2>23. Screenshot Directory Structure</h2>

<p>A clean directory structure makes screenshots easier to locate.</p>

<pre><code>test-artifacts

|

|-- screenshots

|   |-- LoginTest

|   |   |-- loginTest_001.png

|   |   |-- loginTest_002.png

|   |

|   |-- SearchTest

|       |-- searchTest_001.png

|       |-- searchTest_002.png

|

|-- reports

|   |-- testng-results.xml

|   |-- index.html</code></pre>

<hr>

<h2>24. Screenshot and Test Reports</h2>

<p>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.</p>

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

<pre><code>Test Result

    |

    +-- PASS

    |

    +-- FAIL

          |

          +-- Error Message

          +-- Stack Trace

          +-- Screenshot

          +-- Test Data</code></pre>

<hr>

<h2>25. Adding Screenshot Link to HTML Report</h2>

<p>A simple HTML report can link to a screenshot using a relative path.</p>

<pre><code>&lt;a href="screenshots/loginTest_failure.png"

   target="_blank"&gt;

   View Failure Screenshot

&lt;/a&gt;</code></pre>

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

<hr>

<h2>26. Screenshot as Base64</h2>

<p>Selenium can also return a screenshot as Base64 data.</p>

<pre><code>String screenshot =

        ((TakesScreenshot) driver)

            .getScreenshotAs(

                OutputType.BASE64

            );</code></pre>

<p>Base64 can be useful when a reporting library accepts encoded image data directly.</p>

<hr>

<h2>27. Screenshot as Bytes</h2>

<p>Another option is to obtain the screenshot as bytes.</p>

<pre><code>byte[] screenshot =

        ((TakesScreenshot) driver)

            .getScreenshotAs(

                OutputType.BYTES

            );</code></pre>

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

<hr>

<h2>28. Screenshot Output Types</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Output Type</th><th>Purpose</th></tr>

<tr><td>OutputType.FILE</td><td>Returns screenshot as a file</td></tr>

<tr><td>OutputType.BYTES</td><td>Returns screenshot as byte data</td></tr>

<tr><td>OutputType.BASE64</td><td>Returns screenshot as Base64 encoded data</td></tr>

</table>

<hr>

<h2>29. Full Failure Screenshot Listener Example</h2>

<pre><code>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()

            );

        }

    }

}</code></pre>

<hr>

<h2>30. Base Test Class for Driver Access</h2>

<p>A base test class can expose the WebDriver instance to the listener.</p>

<pre><code>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;

        }

    }

}</code></pre>

<hr>

<h2>31. Failure Screenshot with Base Test</h2>

<pre><code>@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")

        );

    }

}</code></pre>

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

<hr>

<h2>32. Failure Screenshots for Assertions</h2>

<p>Failure screenshots are particularly useful when assertions fail.</p>

<pre><code>String actualTitle =

        driver.getTitle();

 

Assert.assertEquals(

        actualTitle,

        "Dashboard"

);</code></pre>

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

<hr>

<h2>33. Failure Screenshots for Element Not Found</h2>

<p>A screenshot can also help investigate <strong>NoSuchElementException</strong> failures.</p>

<pre><code>driver.findElement(

    By.id("loginButton")

).click();</code></pre>

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

<hr>

<h2>34. Failure Screenshots for Timeout Failures</h2>

<p>Synchronization failures can also benefit from screenshots.</p>

<pre><code>WebDriverWait wait =

        new WebDriverWait(

            driver,

            Duration.ofSeconds(10)

        );

 

wait.until(

    ExpectedConditions

        .visibilityOfElementLocated(

            By.id("dashboard")

        )

);</code></pre>

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

<hr>

<h2>35. Failure Screenshots for Wrong URL</h2>

<pre><code>Assert.assertEquals(

    driver.getCurrentUrl(),

    "https://example.com/dashboard"

);</code></pre>

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

<hr>

<h2>36. Failure Screenshots for Wrong Page Title</h2>

<pre><code>Assert.assertEquals(

    driver.getTitle(),

    "Dashboard"

);</code></pre>

<p>The screenshot provides visual evidence in addition to the assertion failure message.</p>

<hr>

<h2>37. Failure Screenshots for Login Testing</h2>

<p>Login automation is one of the most common use cases.</p>

<pre><code>@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")

    );

}</code></pre>

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

<hr>

<h2>38. Failure Screenshots with Data Providers</h2>

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

<pre><code>loginTest_admin_001.png

loginTest_manager_002.png

loginTest_invalid_003.png</code></pre>

<p>Do not include passwords, tokens, session identifiers, or other secrets in filenames.</p>

<hr>

<h2>39. Failure Screenshots in Parallel Execution</h2>

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

<pre><code>Thread 1

   |

   +-- Chrome

   +-- LoginTest

   +-- failure_001.png

 

Thread 2

   |

   +-- Firefox

   +-- SearchTest

   +-- failure_002.png

 

Thread 3

   |

   +-- Edge

   +-- CheckoutTest

   +-- failure_003.png</code></pre>

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

<hr>

<h2>40. ThreadLocal WebDriver</h2>

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

<pre><code>public class DriverManager {

 

    private static ThreadLocal&lt;WebDriver&gt;

            driver = new ThreadLocal&lt;&gt;();

 

    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();

        }

    }

}</code></pre>

<p>This architecture helps the screenshot listener obtain the driver associated with the correct execution context.</p>

<hr>

<h2>41. Screenshot Naming in Parallel Tests</h2>

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

<pre><code>String fileName =

        result.getTestClass()

              .getName()

        + "_"

        + result.getMethod()

              .getMethodName()

        + "_thread_"

        + Thread.currentThread().getId()

        + "_"

        + System.currentTimeMillis()

        + ".png";</code></pre>

<hr>

<h2>42. Screenshot and Retry Analyzer</h2>

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

<pre><code>Attempt 1

   |

   +-- FAIL

   +-- screenshot_attempt_1.png

   |

   v

Retry

   |

Attempt 2

   |

   +-- FAIL

   +-- screenshot_attempt_2.png</code></pre>

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

<hr>

<h2>43. Failure Screenshots and Flaky Tests</h2>

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

<ul>

<li>Compare page loading state.</li>

<li>Check unexpected popups.</li>

<li>Check missing elements.</li>

<li>Check stale or incomplete page content.</li>

<li>Check unexpected redirects.</li>

<li>Check browser-level error messages.</li>

</ul>

<hr>

<h2>44. Screenshot and Browser Alerts</h2>

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

<pre><code>try {

 

    driver.findElement(

        By.id("submit")

    ).click();

 

} catch (Exception e) {

 

    ScreenshotUtil.capture(

        driver,

        "alert_failure.png"

    );

 

    throw e;

}</code></pre>

<hr>

<h2>45. Screenshot and Multiple Windows</h2>

<p>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.</p>

<pre><code>String mainWindow =

        driver.getWindowHandle();

 

for (String handle :

        driver.getWindowHandles()) {

 

    driver.switchTo()

          .window(handle);

}</code></pre>

<hr>

<h2>46. Screenshot and Frames</h2>

<p>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.</p>

<pre><code>driver.switchTo()

      .frame("paymentFrame");

 

driver.findElement(

    By.id("cardNumber")

).sendKeys("1234");</code></pre>

<hr>

<h2>47. Full Page vs Viewport Screenshot</h2>

<p>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.</p>

<p>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.</p>

<hr>

<h2>48. Element Screenshot</h2>

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

<pre><code>WebElement logo =

        driver.findElement(

            By.id("logo")

        );

 

File source =

        logo.getScreenshotAs(

            OutputType.FILE

        );</code></pre>

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

<hr>

<h2>49. Screenshot on Success vs Failure</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Failure Screenshot</th><th>Success Screenshot</th></tr>

<tr><td>Captured when test fails</td><td>Captured when test passes or at selected checkpoints</td></tr>

<tr><td>Primarily for debugging</td><td>Primarily for evidence or documentation</td></tr>

<tr><td>Reduces unnecessary files</td><td>Can produce many artifacts</td></tr>

<tr><td>Useful in CI/CD</td><td>Useful for business evidence</td></tr>

</table>

<hr>

<h2>50. Screenshot Storage Strategy</h2>

<p>A framework should define where screenshots are stored and how long they are retained.</p>

<pre><code>Project

|

|-- test-artifacts

|   |-- screenshots

|   |-- logs

|   |-- reports

|

|-- src

|   |-- test

|       |-- java

|       |-- resources</code></pre>

<p>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.</p>

<hr>

<h2>51. Screenshot and Jenkins</h2>

<p>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.</p>

<pre><code>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</code></pre>

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

<hr>

<h2>52. Screenshot and Maven</h2>

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

<pre><code>mvn clean test</code></pre>

<p>A common project structure is:</p>

<pre><code>target

|

|-- test-output

|   |-- screenshots

|   |-- reports

|

|-- surefire-reports</code></pre>

<hr>

<h2>53. Screenshot and CI/CD Pipeline</h2>

<pre><code>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</code></pre>

<hr>

<h2>54. Failure Screenshots and Logs</h2>

<p>Screenshots should complement logs rather than replace them.</p>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Evidence</th><th>Provides</th></tr>

<tr><td>Screenshot</td><td>Visual browser state</td></tr>

<tr><td>Log</td><td>Execution information</td></tr>

<tr><td>Stack Trace</td><td>Technical failure location</td></tr>

<tr><td>Test Report</td><td>Overall execution result</td></tr>

<tr><td>Test Data</td><td>Input used for execution</td></tr>

</table>

<hr>

<h2>55. Avoid Exposing Sensitive Information</h2>

<p>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.</p>

<ul>

<li>Do not intentionally capture passwords.</li>

<li>Do not include credentials in screenshot filenames.</li>

<li>Avoid logging authentication tokens.</li>

<li>Control access to screenshot artifacts.</li>

<li>Apply retention policies to test artifacts.</li>

<li>Mask sensitive information where practical.</li>

</ul>

<hr>

<h2>56. Common Mistakes in Failure Screenshots</h2>

<ul>

<li>Calling <strong>driver.quit()</strong> before screenshot capture.</li>

<li>Using a shared WebDriver in parallel tests.</li>

<li>Using the same filename for every failure.</li>

<li>Not creating the screenshot directory.</li>

<li>Ignoring screenshot exceptions completely.</li>

<li>Overwriting screenshots from retry attempts.</li>

<li>Storing screenshots outside the published CI artifact directory.</li>

<li>Putting passwords or tokens in filenames.</li>

<li>Assuming every screenshot is automatically embedded in every report.</li>

<li>Capturing screenshots without identifying the corresponding test.</li>

<li>Using a static driver for concurrent test execution.</li>

</ul>

<hr>

<h2>57. Best Practices for Failure Screenshots</h2>

<ul>

<li>Use <strong>ITestListener</strong> for centralized failure handling.</li>

<li>Capture the screenshot before the WebDriver session is closed.</li>

<li>Use unique filenames.</li>

<li>Include test class and method information.</li>

<li>Include thread information for parallel execution.</li>

<li>Keep screenshots in a dedicated artifact directory.</li>

<li>Publish screenshots with CI build artifacts when required.</li>

<li>Keep screenshot failures secondary to the original test failure.</li>

<li>Use thread-safe WebDriver management.</li>

<li>Avoid sensitive information in filenames and logs.</li>

<li>Use external reporting tools when richer attachments are required.</li>

<li>Keep screenshot utilities reusable.</li>

<li>Clean old artifacts according to project retention requirements.</li>

</ul>

<hr>

<h2>58. Screenshot Capture Should Not Hide Original Failure</h2>

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

<pre><code>try {

 

    captureScreenshot(driver);

 

} catch (Exception screenshotError) {

 

    System.err.println(

        "Screenshot failed: "

        + screenshotError.getMessage()

    );

}

 

// Preserve the original test failure</code></pre>

<p>This approach helps keep the original failure as the primary diagnostic information.</p>

<hr>

<h2>59. Handling Screenshot Capture Exceptions</h2>

<pre><code>try {

 

    File source =

        ((TakesScreenshot) driver)

            .getScreenshotAs(

                OutputType.FILE

            );

 

    FileUtils.copyFile(

        source,

        destination

    );

 

} catch (Exception e) {

 

    System.err.println(

        "Unable to capture screenshot: "

        + e.getMessage()

    );

}</code></pre>

<p>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.</p>

<hr>

<h2>60. Practical Screenshot Utility</h2>

<pre><code>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;

        }

    }

}</code></pre>

<hr>

<h2>61. Complete Listener Architecture</h2>

<pre><code>                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</code></pre>

<hr>

<h2>62. Practical Project Structure</h2>

<pre><code>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</code></pre>

<hr>

<h2>63. Complete Practical Failure Screenshot Example</h2>

<pre><code>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;

        }

    }

}</code></pre>

<hr>

<h2>64. Complete FailureScreenshotListener Example</h2>

<pre><code>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()

            );

        }

    }

}</code></pre>

<hr>

<h2>65. Failure Screenshot with Data Provider</h2>

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

<pre><code>@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)

    );

}</code></pre>

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

<hr>

<h2>66. Failure Screenshots with Page Object Model</h2>

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

<pre><code>Test Class

    |

    v

Page Object

    |

    v

Selenium WebDriver

    |

    v

Application

    |

    v

Failure

    |

    v

TestNG Listener

    |

    v

Screenshot Utility</code></pre>

<p>This separation keeps screenshot management independent from page-specific Selenium interactions.</p>

<hr>

<h2>67. Failure Screenshots and Reporting Tools</h2>

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

<p>A common architecture is:</p>

<pre><code>TestNG

  |

  +-- Test Result

  |

  +-- Failure Details

  |

  +-- Screenshot

  |

  +-- Logs

  |

  v

Automation Report</code></pre>

<p>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.</p>

<hr>

<h2>68. Failure Screenshots in Regression Testing</h2>

<p>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.</p>

<p>For regression automation, combine screenshots with:</p>

<ul>

<li>Test name.</li>

<li>Failure message.</li>

<li>Stack trace.</li>

<li>Browser name.</li>

<li>Environment.</li>

<li>Test data identifier.</li>

<li>Timestamp.</li>

<li>Execution thread.</li>

</ul>

<hr>

<h2>69. Failure Screenshots in Cross-Browser Testing</h2>

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

<pre><code>LoginTest_Chrome_failure.png

LoginTest_Firefox_failure.png

LoginTest_Edge_failure.png</code></pre>

<p>This makes browser-specific failures easier to investigate.</p>

<hr>

<h2>70. Cross-Browser Failure Architecture</h2>

<pre><code>                 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</code></pre>

<hr>

<h2>71. Failure Screenshot and Environment</h2>

<p>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.</p>

<pre><code>screenshots

|

|-- QA

|   |-- LoginTest_failure.png

|

|-- Stage

|   |-- LoginTest_failure.png

|

|-- Production

    |-- LoginTest_failure.png</code></pre>

<hr>

<h2>72. Failure Screenshot and Browser Information</h2>

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

<pre><code>Browser: Chrome

Environment: QA

Test: LoginTest

Method: validLogin

Thread: 4

Timestamp: 20261001_132100

Screenshot: LoginTest_validLogin_4.png</code></pre>

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

<hr>

<h2>73. Failure Screenshots for E-Commerce Testing</h2>

<p>E-commerce applications contain many workflows where failure screenshots are valuable.</p>

<ul>

<li>Login.</li>

<li>Product search.</li>

<li>Product details.</li>

<li>Add to cart.</li>

<li>Cart validation.</li>

<li>Checkout.</li>

<li>Address selection.</li>

<li>Payment page.</li>

<li>Order confirmation.</li>

<li>Order history.</li>

</ul>

<pre><code>Search

  |

  v

Product

  |

  v

Cart

  |

  v

Checkout

  |

  v

Payment

  |

  v

Confirmation

  |

  +---- Failure Screenshot</code></pre>

<hr>

<h2>74. Failure Screenshots for Form Testing</h2>

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

<pre><code>Registration Form

       |

       +-- Name

       +-- Email

       +-- Mobile

       +-- Password

       +-- Confirm Password

       |

       v

Submit

       |

       v

Validation

       |

       +-- PASS

       |

       +-- FAIL

              |

              v

       Failure Screenshot</code></pre>

<hr>

<h2>75. Failure Screenshots for UI Validation</h2>

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

<pre><code>Assert element visible

        |

        v

Element missing

        |

        v

Test Failure

        |

        v

Screenshot

        |

        v

Visual Investigation</code></pre>

<hr>

<h2>76. Failure Screenshots for Navigation Testing</h2>

<pre><code>Home

 |

 v

Login

 |

 v

Dashboard

 |

 v

Profile

 |

 v

Settings

 |

 v

Unexpected Page

 |

 v

Failure Screenshot</code></pre>

<p>The screenshot can help determine which page was displayed when navigation validation failed.</p>

<hr>

<h2>77. Failure Screenshot Retention</h2>

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

<ul>

<li>Keep recent failed-test screenshots.</li>

<li>Archive screenshots for important release builds.</li>

<li>Remove obsolete artifacts.</li>

<li>Use CI artifact retention settings.</li>

<li>Keep production-sensitive artifacts access-controlled.</li>

</ul>

<hr>

<h2>78. Performance Considerations</h2>

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

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

<hr>

<h2>79. Troubleshooting Failure Screenshots</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Problem</th><th>Possible Cause</th><th>Solution</th></tr>

<tr><td>No screenshot</td><td>Listener not registered</td><td>Check @Listeners or testng.xml</td></tr>

<tr><td>No screenshot</td><td>Driver is null</td><td>Initialize driver before test</td></tr>

<tr><td>No screenshot</td><td>Driver already closed</td><td>Capture before quit()</td></tr>

<tr><td>Files overwritten</td><td>Duplicate filename</td><td>Use timestamp/UUID/thread ID</td></tr>

<tr><td>Screenshot not in CI</td><td>Artifact not published</td><td>Publish screenshot directory</td></tr>

<tr><td>Wrong browser screenshot</td><td>Shared driver</td><td>Use isolated driver instances</td></tr>

<tr><td>Blank/incomplete image</td><td>Browser state or capture limitation</td><td>Check browser state and capture timing</td></tr>

<tr><td>Original failure hidden</td><td>Screenshot exception replaces failure</td><td>Handle screenshot exception separately</td></tr>

</table>

<hr>

<h2>80. Common Failure Screenshot Architecture Mistakes</h2>

<ul>

<li>Using a static WebDriver for parallel execution.</li>

<li>Capturing the screenshot after browser teardown.</li>

<li>Not registering the listener.</li>

<li>Using an incorrect driver reference.</li>

<li>Saving all screenshots with the same name.</li>

<li>Not creating the destination directory.</li>

<li>Not copying temporary screenshot files to durable storage.</li>

<li>Not publishing screenshots in CI.</li>

<li>Including credentials in screenshot names.</li>

<li>Allowing screenshot errors to hide the original test failure.</li>

</ul>

<hr>

<h2>81. Best Practices Checklist</h2>

<ul>

<li>Use a reusable Screenshot Utility.</li>

<li>Use TestNG ITestListener for automatic failure capture.</li>

<li>Capture screenshots before WebDriver teardown.</li>

<li>Use unique and meaningful filenames.</li>

<li>Include class and method names.</li>

<li>Include browser and environment information where useful.</li>

<li>Use thread-safe driver management for parallel tests.</li>

<li>Store screenshots in a predictable directory.</li>

<li>Publish screenshots as CI artifacts.</li>

<li>Integrate screenshots with reports where supported.</li>

<li>Do not expose sensitive information.</li>

<li>Preserve the original assertion or WebDriver exception.</li>

<li>Clean up old artifacts according to project requirements.</li>

</ul>

<hr>

<h2>82. Interview Questions on Failure Screenshots</h2>

<h3>1. What is a failure screenshot?</h3>

<p>A failure screenshot is an image captured from the browser when an automated test fails.</p>

<h3>2. Which Selenium interface is used for screenshots?</h3>

<p>The <strong>TakesScreenshot</strong> interface is commonly used for browser screenshot capture.</p>

<h3>3. Which Selenium method captures a screenshot?</h3>

<p>The <strong>getScreenshotAs()</strong> method is used to obtain screenshot output.</p>

<h3>4. Which TestNG listener method is commonly used for failure screenshots?</h3>

<p><strong>onTestFailure(ITestResult result)</strong> is commonly used.</p>

<h3>5. Why should screenshots be captured before driver.quit()?</h3>

<p>Because the browser session needs to remain available for the screenshot operation.</p>

<h3>6. How can a listener be registered in TestNG?</h3>

<p>It can be registered using <strong>@Listeners</strong> or through <strong>testng.xml</strong>.</p>

<h3>7. Why should screenshot filenames be unique?</h3>

<p>Unique names prevent one failure from overwriting another screenshot.</p>

<h3>8. How can timestamps be added to screenshots?</h3>

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

<h3>9. Can screenshots be used with Data Providers?</h3>

<p>Yes. Screenshot filenames can identify the test invocation while avoiding sensitive test data.</p>

<h3>10. Can screenshots be used with Page Object Model?</h3>

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

<h3>11. Can screenshots be captured during parallel execution?</h3>

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

<h3>12. What is OutputType.FILE?</h3>

<p>It requests the screenshot as a file representation.</p>

<h3>13. What is OutputType.BYTES?</h3>

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

<h3>14. What is OutputType.BASE64?</h3>

<p>It returns the screenshot as Base64 encoded data.</p>

<h3>15. Does saving a PNG automatically attach it to every TestNG report?</h3>

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

<h3>16. Why should screenshot exceptions not replace the original failure?</h3>

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

<h3>17. Can screenshots be published in Jenkins?</h3>

<p>Yes. The screenshot directory can be retained and published as a build artifact.</p>

<h3>18. What information should not be included in screenshot filenames?</h3>

<p>Passwords, tokens, session identifiers, and other sensitive information should not be included.</p>

<h3>19. Why are screenshots useful in CI/CD?</h3>

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

<h3>20. What is the biggest advantage of automatic failure screenshots?</h3>

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

<hr>

<h2>83. Quick Reference Table</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Concept</th><th>Description</th></tr>

<tr><td>TakesScreenshot</td><td>Selenium interface for screenshot capture</td></tr>

<tr><td>getScreenshotAs()</td><td>Captures screenshot output</td></tr>

<tr><td>OutputType.FILE</td><td>Returns screenshot as a file</td></tr>

<tr><td>OutputType.BYTES</td><td>Returns screenshot bytes</td></tr>

<tr><td>OutputType.BASE64</td><td>Returns Base64 screenshot data</td></tr>

<tr><td>ITestListener</td><td>TestNG listener interface</td></tr>

<tr><td>onTestFailure()</td><td>Callback used for failed-test handling</td></tr>

<tr><td>@Listeners</td><td>Registers a TestNG listener</td></tr>

<tr><td>testng.xml</td><td>Can register listeners at suite level</td></tr>

<tr><td>Screenshot Utility</td><td>Reusable screenshot capture component</td></tr>

<tr><td>ThreadLocal WebDriver</td><td>Common approach for thread-specific drivers</td></tr>

<tr><td>CI Artifact</td><td>Persistent build output such as screenshots</td></tr>

</table>

<hr>

<h2>84. Learning Roadmap for Failure Screenshots</h2>

<ol>

<li>Understand Selenium WebDriver.</li>

<li>Learn Selenium screenshot concepts.</li>

<li>Learn the TakesScreenshot interface.</li>

<li>Understand getScreenshotAs().</li>

<li>Learn OutputType.FILE.</li>

<li>Learn OutputType.BYTES and BASE64.</li>

<li>Create a Screenshot Utility.</li>

<li>Learn TestNG listeners.</li>

<li>Implement ITestListener.</li>

<li>Implement onTestFailure().</li>

<li>Register listeners using @Listeners.</li>

<li>Register listeners using testng.xml.</li>

<li>Integrate screenshots with Page Object Model.</li>

<li>Integrate screenshots with Data Providers.</li>

<li>Handle parallel execution safely.</li>

<li>Publish screenshots in CI/CD.</li>

<li>Integrate screenshots with test reports.</li>

<li>Apply security and retention practices.</li>

</ol>

<hr>

<h2>85. Practical Exercises</h2>

<ol>

<li>Create a Selenium Screenshot Utility.</li>

<li>Capture a screenshot manually after a button click.</li>

<li>Create a TestNG ITestListener.</li>

<li>Capture a screenshot inside onTestFailure().</li>

<li>Register the listener using @Listeners.</li>

<li>Register the listener using testng.xml.</li>

<li>Add timestamps to screenshot filenames.</li>

<li>Add test method names to screenshot filenames.</li>

<li>Integrate screenshots with a LoginTest.</li>

<li>Integrate screenshots with a Data Provider.</li>

<li>Integrate screenshots with Page Object Model.</li>

<li>Execute tests in parallel and create unique screenshot names.</li>

<li>Publish screenshots as Maven/CI artifacts.</li>

<li>Create an HTML report with screenshot links.</li>

<li>Implement a complete failure evidence framework.</li>

</ol>

<hr>

<h2>86. Real-World Failure Investigation Example</h2>

<p>Suppose a checkout test fails because the expected confirmation message is not displayed.</p>

<pre><code>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</code></pre>

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

<hr>

<h2>87. Recommended Framework Architecture</h2>

<pre><code>                    Selenium Test Framework

                              |

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

          |                   |                   |

       Tests              Page Objects       Utilities

          |                   |                   |

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

          |                   |          |                 |

          |                   |       Driver           Screenshot

          |                   |       Manager           Utility

          |                   |          |                 |

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

                              |

                              v

                           TestNG

                              |

                              v

                       ITestListener

                              |

                              v

                    Failure Screenshot

                              |

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

                    |                   |

                    v                   v

                 Report             CI Artifact</code></pre>

<hr>

<h2>88. Summary</h2>

<p>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.</p>

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

<p>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.</p>

<p>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.</p>

<hr>

<h2>89. Final Takeaway</h2>

<p><strong>Failure Screenshots = Test Failure + Visual Evidence.</strong></p>

<p>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.</p>

<hr>

<h2>90. Course Resources</h2>

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

<ul>

<li><a href="https://www.justacademy.co/course-detail/selenium-training" target="_blank" rel="noopener noreferrer">Selenium Training</a></li>

<li><a href="https://www.justacademy.co/register-for-course-demo" target="_blank" rel="noopener noreferrer">Register for Selenium Course Demo</a></li>

</ul>

<p><strong>Quick Revision:</strong> Use <strong>TakesScreenshot</strong> to capture screenshots, use <strong>ITestListener.onTestFailure()</strong> for automatic failure handling, capture before <strong>driver.quit()</strong>, 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.</p>

</div>

Previous Next
whatsapp