Screenshot attachment on failure in Selenium Java - Build an Automation Script
import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import org.testng.ITestResult; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.time.Duration; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class LoginTest { private WebDriver driver; private WebDriverWait wait; @BeforeMethod public void setUp() { driver = new ChromeDriver(); wait = new WebDriverWait(driver, Duration.ofSeconds(10)); driver.manage().window().maximize(); } @Test public void testInvalidLoginShowsError() { driver.get("https://example.com/login"); WebElement usernameInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username"))); usernameInput.sendKeys("wronguser"); WebElement passwordInput = driver.findElement(By.id("password")); passwordInput.sendKeys("wrongpass"); WebElement loginButton = driver.findElement(By.id("loginBtn")); loginButton.click(); WebElement errorMsg = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("error-message"))); Assert.assertTrue(errorMsg.isDisplayed(), "Error message should be displayed on invalid login"); } @AfterMethod public void tearDown(ITestResult result) { if (ITestResult.FAILURE == result.getStatus()) { takeScreenshot(result.getName()); } if (driver != null) { driver.quit(); } } private void takeScreenshot(String testName) { try { File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); Path destPath = Path.of("screenshots", testName + "_" + timestamp + ".png"); Files.createDirectories(destPath.getParent()); Files.copy(srcFile.toPath(), destPath, StandardCopyOption.REPLACE_EXISTING); System.out.println("Screenshot saved to: " + destPath.toAbsolutePath()); } catch (IOException e) { System.err.println("Failed to save screenshot: " + e.getMessage()); } } }
This test class uses Selenium WebDriver with TestNG to automate a login failure scenario.
setUp() initializes the Chrome browser and sets an explicit wait.
testInvalidLoginShowsError() opens the login page, enters wrong credentials, clicks login, and asserts the error message is visible.
tearDown() runs after each test. If the test failed, it calls takeScreenshot() to capture the browser screen and save it with a timestamped filename in the screenshots folder. Then it closes the browser.
takeScreenshot() uses Selenium's TakesScreenshot interface to get the screenshot file, creates the folder if needed, and saves the file with a name that includes the test method name and current time. This helps identify which test failed and when.
This approach ensures that any failure during the test run is documented visually, helping debugging.
Now add data-driven testing with 3 different invalid username and password combinations
Practice
Solution
Step 1: Understand the role of screenshots in testing
Screenshots help testers see what the application looked like when a test failed.Step 2: Identify the benefit of visual evidence
This visual evidence helps diagnose issues faster and more clearly than logs alone.Final Answer:
To visually capture the state of the application at failure -> Option CQuick Check:
Screenshot = Visual failure evidence [OK]
- Thinking screenshots fix errors automatically
- Believing screenshots speed up tests
- Assuming screenshots reduce report size
Solution
Step 1: Recall Selenium interfaces for screenshots
TheTakesScreenshotinterface provides the method to capture screenshots.Step 2: Differentiate from other interfaces
Other interfaces likeWebDrivercontrol browser,Alerthandles popups, andJavascriptExecutorruns JS scripts.Final Answer:
TakesScreenshot -> Option DQuick Check:
TakesScreenshot = Capture screenshots [OK]
- Using WebDriver directly for screenshots
- Confusing Alert or JavascriptExecutor with screenshot capture
- Not casting driver to TakesScreenshot
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File("screenshots/fail.png"));Solution
Step 1: Analyze the screenshot capture code
The driver is cast toTakesScreenshotand screenshot saved as a file named "fail.png" in the "screenshots" folder.Step 2: Check for errors or randomness
FileUtils.copyFile copies the screenshot correctly; file name is fixed as "fail.png" so no randomness.Final Answer:
Screenshot saved as fail.png in screenshots folder -> Option BQuick Check:
Code saves fixed-name screenshot file [OK]
- Forgetting to cast driver to TakesScreenshot
- Not importing or defining FileUtils
- Expecting random file names without code for it
File srcFile = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File("screenshots/error.png"));Solution
Step 1: Check method call on driver
ThegetScreenshotAsmethod belongs toTakesScreenshot, so driver must be cast before calling it.Step 2: Verify other parts
FileUtils.copyFile exists and OutputType.FILE is correct. Relative paths are allowed if folder exists.Final Answer:
driver must be cast to TakesScreenshot before calling getScreenshotAs -> Option AQuick Check:
Cast driver to TakesScreenshot before screenshot [OK]
- Calling getScreenshotAs directly on WebDriver
- Assuming OutputType.FILE is wrong
- Thinking relative paths cause errors
@AfterMethod
public void tearDown(ITestResult result) {
if (result.getStatus() == ITestResult.FAILURE) {
File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
File dest = new File("screenshots/" + result.getName() + ".png");
FileUtils.copyFile(src, dest);
// Attach dest to report here
}
driver.quit();
}Solution
Step 1: Check condition for failure
The code checks if test status is FAILURE before taking screenshot, so it runs only on failures.Step 2: Verify screenshot saving and naming
Screenshot saved with test method name, which is valid. Attaching to report is indicated as a comment.Step 3: Confirm no errors in logic
FileUtils.copyFile may throw IOException but typically handled or declared; this snippet focuses on logic correctness.Final Answer:
This code saves screenshot only on failure and attaches it correctly -> Option AQuick Check:
Screenshot on failure only with correct naming [OK]
- Taking screenshots regardless of test result
- Not handling exceptions from file operations
- Assuming getName() returns null
Ready to prove it?
Pass the test and this pattern moves unknown
