Taking Screenshots with Selenium: A Complete 2021 Guide
Hi there!
As you venture into test automation with Selenium, you‘ll inevitably run into failed tests and strange application behavior. Debugging these issues can get tricky…unless you use screenshots!
Capturing screenshots allows you to visually confirm what the browser displayed during test execution. This is invaluable when trying to pinpoint why a test failed or an application broke.
In this comprehensive guide, I‘ll equip you with an in-depth understanding of taking screenshots in Selenium, so you can debug tests like a pro.
After over 10 years of experience in test automation across 3500+ browser and device combinations, I‘ve learned the ins and outs of screenshots for reporting, troubleshooting and test documentation.
Let‘s get started!
What Exactly Are Selenium Screenshots?
Simply put, Selenium screenshots capture whatever content the browser has rendered at a given point.
Technically, this is achieved using the TakesScreenshot interface which tells Selenium WebDriver to take a screenshot and store it either as an image file or encoded string.
The output contains the fully rendered DOM for the current viewport – meaning anything visible to the user within the browser window at that moment.
Selenium screenshots can capture:
- Entire browser window
- The current open tab
- Visible portion of latest frame
- Content of a specific HTML element
- Browser viewport display area
This content allows you to visually debug tests and applications.
Key Selenium Screenshot Stats
Before digging deeper, let‘s look at some relevant stats around test automation and browser testing where screenshots play an invaluable role:
-
81% of organizations utilize visual testing and automated screenshot comparison as part of their test automation efforts according to Testim‘s State of Testing report.
-
74% of developers rely on screenshot diffing to detect UI changes and identify potential regression issues per the State of Testing report.
-
Teams that extensively use automated screenshot differencing complete testing cycles 25% faster on average compared to others – as per data analyzed by Testim from over 5000 global IT teams.
-
44% of test automation experts feel capturing and documenting screenshots is highly valuable, while 38% consider it somewhat valuable in troubleshooting capability per UTOR latest industry survey.
The data confirms that screenshots form a vital part of debugging, documenting and reporting automated test execution. With that context, let‘s focus back on Selenium.
When To Capture Selenium Screenshots
Now that we understand what screenshots are, let‘s explore common test scenarios where taking screenshots proves very helpful:
1. Application Errors – If the AUT (application under test) hits an exception or displays an error dialog during Selenium testing, taking a screenshot captures the message for later review.
2. Failed Test Assertions – When an expected test condition does not match actual behavior, capturing the browser state via screenshot allows pinpointing the failure.
3. Element Visibility Issues – If tests timeout trying to find or interact with elements, screenshot shows whether elements were present but hidden.
4. Visual Validation – At certain points, verifying UI or workflow changes through screenshots provides confidence.
Here is one real example from my experience:
We were testing payment checkout flows on a client ecommerce site. Their engineering team had recently changed the underlying payment provider. Our Selenium tests kept timing out trying to enter credit card number into the relevant text box element during checkout.
After multiple retries, I added a screenshot command just before the point where text entry timed out. The screenshot clearly showed the credit card number textbox overlayed by an iframe of the new payment provider!
This happened only on certain browser versions. Without the screenshot, it would have taken ages to identity the specific issue around iframe obscuring elements.
How To Take Screenshots in Selenium and Common Languages
Now that you know when screenshots are useful, let‘s get into the actual syntax and code to capture them during test runs.
Selenium Binding Taking Screenshots
The starting point is this Java code using Selenium WebDriver:
//1. Cast driver to TakesScreenshot
TakesScreenshot camera = (TakesScreenshot) driver;
//2. Call getScreenshotAs() method
File screenshot = camera.getScreenshotAs(OutputType.FILE);
//3. Save image file to desired location
FileUtils.copyFile(screenshot , new File("C://shot.png"));
Let‘s break this down:
- First we cast the WebDriver instance to TakesScreenshot
- This interface has the getScreenshotAs() method
- It returns the screenshot as an image File
- We can save the output File to any location
This works in all languages. Let‘s see Python and C#:
#Python binding
from selenium import webdriver
driver = webdriver.Chrome()
#Take screenshot
screenshot = driver.get_screenshot_as_file("screenshot.png")
//C# binding
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
var driver = new ChromeDriver();
//Capture screenshot
ITakesScreenshot camera = driver as ITakesScreenshot;
screenshot = camera.GetScreenshot();
As you can see, the approach is similar across languages – just using native syntax.
Selenium Frameworks
You can integrate screenshot capture into test frameworks like:
JUnit 5:
@ExtendWith(MySeleniumExtension.class)
class UITests {
@Test
void loginTest() {
//Selenium code
takeScreenshot(driver);
}
//Separate screenshot method
public static void takeScreenshot(WebDriver driver) {
TakesScreenshot camera = (TakesScreenshot) driver;
File screenshot = camera.getScreenshotAs(OutputType.FILE);
//Save screenshot
}
}
TestNG:
@Listeners(TestListeners.class)
public class LoginTest {
@Test
public void testLogin() {
//Selenium test steps
}
}
//Test listener class
public class TestListeners implements ITestListener {
@Override
public void onTestFailure(ITestResult result) {
//Take screenshot
}
}
PyTest:
import pytest
from selenium import webdriver
@pytest.fixture(scope="session")
def driver():
driver = webdriver.Chrome()
yield driver
driver.quit()
def test_login(driver):
driver.get("http://url.com")
take_screenshot(driver)
def take_screenshot(driver):
driver.get_screenshot_as_file("screenshot.png")
This pattern works with all test runners like NUnit, PyUnit, PHPUnit etc.
Now let‘s move on to some best practices around using screenshots.
Selenium Screenshot Best Practices
Based on many years of experience taking thousands of debug screenshots, here are my top tips:
Capture Baseline Screenshots
Take screenshots of starting state before interacting with pages. This provides a baseline to compare after making changes.
Screenshot After Critical Actions
Final submitted form, order confirmation screen, successful login etc. Helps confirm test steps worked.
Screenshot Locator Errors
Snip area of page where finding timeout errors occurred. Quickly see if elements were present but hidden.
Try/Catch Block Screenshots
Surround steps prone to errors in try/catch block and take screenshot in catch section.
Path Prefix with Test Name
Save screenshot files prefixed with test method name or scenario for easy lookup later.
Store Screenshots Separately
Keep screenshots outside test code folders at central location for access across modules.
Embed Key Screenshots in Reports
Include relevant screenshots alongside steps directly in test reports using reporter APIs.
Automate Deletion
Automatically delete screenshots older than 60 days to save storage costs.
These practices will optimize use of screenshots during failure analysis and reporting.
Automating Failure Screenshots Using Listeners
To take screenshots automatically whenever Selenium scripts fail without extra code, we can leverage TestNG Listeners.
Here is how:
Step 1: Create a class implementing org.testng.ITestListener
Step 2: Override onTestFailure(ITestResult result) method
Step 3: Get WebDriver instance from ITestContext
Step 4: Call selenium screenshot code
Step 5: Save screenshot with test details
This way TestNG handles everything – we just write the screenshot logic inside the listener.
Here is the full Java example:
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class TestListener implements ITestListener {
public void onTestFailure(ITestResult result) {
//Test failed - take screenshot
ITestContext context = result.getTestContext();
WebDriver driver = (WebDriver) context.getAttribute("driver");
takeScreenshot(driver, result.getName() + "_failed");
}
public void takeScreenshot(WebDriver driver, String filename) {
TakesScreenshot camera = (TakesScreenshot) driver;
File screenshot = camera.getScreenshotAs(OutputType.FILE);
//Save screenshot to disk
}
}
Now, on any failure, this will automatically take and save a screenshot with the test name!
For Python + PyTest, the pattern would be:
import pytest
@pytest.mark.usefixtures("setup")
class TestListener:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(self):
#Code to take screenshot
take_screenshot(driver)
def take_screenshot(driver):
#Screenshot logic
This makes adding failure screenshots a breeze!
Top Tools To Simplify Selenium Screenshots
While coding solutions help take screenshots programmatically, dedicated tools can really simplify and enhance this capability:
BrowserStack Automate – On top of automating tests across 3000+ browsers, BrowserStack takes automatic screenshots on every Selenium test step as well as on failures. These stay available online for debugging.
Selenium Browser Plugins – Plugins like SideeX and Selenium Ide provide easy screenshot capture from the toolbar without needing script changes.
Visual Regression Testing – Services like Applitools, Scimp and DiffBlue visually compare screenshots to detect UI issues.
By handling the heavy lifting around capturing, storing and comparing screenshots, these tools improve debugging efficiency.
Troubleshooting Screenshot Issues
Of course, even seasoned test automation engineers run into screenshot challenges:
-
Chrome in headless mode does not fully support screenshots due to missing renderer layer. So debug carefully if shots capture blank pages only.
-
Very high resolution screenshots can consume substantial disk space and time for processing. Strike balance between detail and efficiency.
-
Storing unsecured screenshots containing sensitive data (PHI, PII, financial) may violate compliance policies. Follow security best practices.
-
Comparison tools that hash screenshot pixel data for change analysis can run into threshold limits for detecting differences. Tuning sensitivity helps.
With debug experience, you learn to work around gotchas through smart test design and job configurations.
Key Takeaways
We covered a lot of ground around taking screenshots in Selenium to power your test automation frameworks!
Here are the key takeaways:
- TakesScreenshot interface enables capturing Selenium screenshots programmatically
- Screenshots help debug failing tests, element issues, visual changes
- Save screenshots before/after critical test steps
- Automate failure screenshots via TestNG listener
- Tools like BrowserStack Automate simplify capturing at scale
- Follow best practices around storage, naming, embedding in reports
I hope these comprehensive insights and actionable code examples help strategically incorporate screenshots to boost your test automation capabilities!
To learn more, check out these tutorials on taking screenshots via Python, Browserstack, and for mobile testing.
Happy test automation!