Debugging Tips
Essential techniques for debugging Selenium tests, identifying failures, and fixing flaky tests.
Selenium 3 & 4 Stable
Debugging Selenium tests can be challenging. This guide covers practical techniques to identify and fix common issues.
Common Issues and Solutions
1. Element Not Found
Debugging Element Not Found
Selenium 3 & 4 Stable
// Problem: NoSuchElementException
// Step 1: Check if element exists in current context// Are you in the right frame?driver.switchTo().defaultContent();
// Step 2: Wait for element to be presentWebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));try { WebElement element = wait.until( ExpectedConditions.presenceOfElementLocated(By.id("myElement")) );} catch (TimeoutException e) { // Element truly doesn't exist - check your locator System.out.println("Current URL: " + driver.getCurrentUrl()); System.out.println("Page source contains element: " + driver.getPageSource().contains("myElement"));}
// Step 3: Verify locator in browser console// Open DevTools and run:// document.querySelector('#myElement')// $x("//your/xpath")# Problem: NoSuchElementException
# Step 1: Check if element exists in current context# Are you in the right frame?driver.switch_to.default_content()
# Step 2: Wait for element to be presentwait = WebDriverWait(driver, 10)try: element = wait.until( EC.presence_of_element_located((By.ID, "myElement")) )except TimeoutException: # Element truly doesn't exist - check your locator print(f"Current URL: {driver.current_url}") print(f"Page source contains element: {'myElement' in driver.page_source}")
# Step 3: Verify locator in browser console# Open DevTools and run:# document.querySelector('#myElement')# $x("//your/xpath")// Problem: NoSuchElementError
// Step 1: Check if element exists in current contextawait driver.switchTo().defaultContent();
// Step 2: Wait for element to be presenttry { const element = await driver.wait( until.elementLocated(By.id('myElement')), 10000 );} catch (e) { // Element truly doesn't exist - check your locator console.log('Current URL:', await driver.getCurrentUrl()); const source = await driver.getPageSource(); console.log('Page source contains element:', source.includes('myElement'));}// Problem: NoSuchElementException
// Step 1: Check if element exists in current contextdriver.SwitchTo().DefaultContent();
// Step 2: Wait for element to be presentWebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));try{ IWebElement element = wait.Until( ExpectedConditions.ElementExists(By.Id("myElement")) );}catch (WebDriverTimeoutException){ // Element truly doesn't exist - check your locator Console.WriteLine($"Current URL: {driver.Url}"); Console.WriteLine($"Page contains element: {driver.PageSource.Contains("myElement")}");}2. Element Not Clickable
Debugging Click Issues
Selenium 3 & 4 Stable
// Problem: ElementClickInterceptedException or Element not clickable
WebElement element = driver.findElement(By.id("submit"));
// Check 1: Is element visible?System.out.println("Displayed: " + element.isDisplayed());System.out.println("Enabled: " + element.isEnabled());
// Check 2: What's blocking it?// In browser console: document.elementFromPoint(x, y)
// Solution 1: Wait for element to be clickableWebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));element.click();
// Solution 2: Scroll element into viewJavascriptExecutor js = (JavascriptExecutor) driver;js.executeScript("arguments[0].scrollIntoView({block: 'center'})", element);element.click();
// Solution 3: Wait for overlay to disappearwait.until(ExpectedConditions.invisibilityOfElementLocated(By.className("loading-overlay")));element.click();
// Solution 4: JavaScript click (last resort)js.executeScript("arguments[0].click()", element);# Problem: ElementClickInterceptedException or Element not clickable
element = driver.find_element(By.ID, "submit")
# Check 1: Is element visible?print(f"Displayed: {element.is_displayed()}")print(f"Enabled: {element.is_enabled()}")
# Solution 1: Wait for element to be clickablewait = WebDriverWait(driver, 10)element = wait.until(EC.element_to_be_clickable((By.ID, "submit")))element.click()
# Solution 2: Scroll element into viewdriver.execute_script("arguments[0].scrollIntoView({block: 'center'})", element)element.click()
# Solution 3: Wait for overlay to disappearwait.until(EC.invisibility_of_element_located((By.CLASS_NAME, "loading-overlay")))element.click()
# Solution 4: JavaScript click (last resort)driver.execute_script("arguments[0].click()", element)// Problem: ElementClickInterceptedError
const element = await driver.findElement(By.id('submit'));
// Check 1: Is element visible?console.log('Displayed:', await element.isDisplayed());console.log('Enabled:', await element.isEnabled());
// Solution 1: Wait for element to be clickableawait driver.wait(until.elementIsVisible(element), 10000);await driver.wait(until.elementIsEnabled(element), 10000);await element.click();
// Solution 2: Scroll element into viewawait driver.executeScript("arguments[0].scrollIntoView({block: 'center'})", element);await element.click();
// Solution 3: JavaScript click (last resort)await driver.executeScript('arguments[0].click()', element);// Problem: ElementClickInterceptedException
IWebElement element = driver.FindElement(By.Id("submit"));
// Check 1: Is element visible?Console.WriteLine($"Displayed: {element.Displayed}");Console.WriteLine($"Enabled: {element.Enabled}");
// Solution 1: Wait for element to be clickableWebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));element = wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("submit")));element.Click();
// Solution 2: Scroll element into viewIJavaScriptExecutor js = (IJavaScriptExecutor)driver;js.ExecuteScript("arguments[0].scrollIntoView({block: 'center'})", element);element.Click();
// Solution 3: JavaScript click (last resort)js.ExecuteScript("arguments[0].click()", element);3. Stale Element Reference
Handling Stale Elements
Selenium 3 & 4 Stable
// Problem: StaleElementReferenceException// Element was found but DOM changed before interaction
// Solution 1: Re-find the elementWebElement element = driver.findElement(By.id("dynamic"));// ... page updates ...try { element.click();} catch (StaleElementReferenceException e) { element = driver.findElement(By.id("dynamic")); // Re-find element.click();}
// Solution 2: Wait for staleness then find againWebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));WebElement oldElement = driver.findElement(By.id("dynamic"));// Trigger page updatedriver.findElement(By.id("refresh")).click();// Wait for old element to become stalewait.until(ExpectedConditions.stalenessOf(oldElement));// Find new elementWebElement newElement = wait.until( ExpectedConditions.presenceOfElementLocated(By.id("dynamic")));
// Solution 3: Retry patternpublic WebElement retryingFind(By locator) { int attempts = 0; while (attempts < 3) { try { return driver.findElement(locator); } catch (StaleElementReferenceException e) { attempts++; } } throw new RuntimeException("Element still stale after 3 attempts");}# Problem: StaleElementReferenceException# Element was found but DOM changed before interaction
from selenium.common.exceptions import StaleElementReferenceException
# Solution 1: Re-find the elementelement = driver.find_element(By.ID, "dynamic")# ... page updates ...try: element.click()except StaleElementReferenceException: element = driver.find_element(By.ID, "dynamic") # Re-find element.click()
# Solution 2: Wait for staleness then find againwait = WebDriverWait(driver, 10)old_element = driver.find_element(By.ID, "dynamic")# Trigger page updatedriver.find_element(By.ID, "refresh").click()# Wait for old element to become stalewait.until(EC.staleness_of(old_element))# Find new elementnew_element = wait.until(EC.presence_of_element_located((By.ID, "dynamic")))
# Solution 3: Retry patterndef retrying_find(driver, locator, attempts=3): for _ in range(attempts): try: return driver.find_element(*locator) except StaleElementReferenceException: pass raise Exception("Element still stale after retries")// Problem: StaleElementReferenceError
// Solution 1: Re-find the elementlet element = await driver.findElement(By.id('dynamic'));try { await element.click();} catch (e) { if (e.name === 'StaleElementReferenceError') { element = await driver.findElement(By.id('dynamic')); await element.click(); }}
// Solution 2: Wait for staleness then find againconst oldElement = await driver.findElement(By.id('dynamic'));await driver.findElement(By.id('refresh')).click();await driver.wait(until.stalenessOf(oldElement), 10000);const newElement = await driver.findElement(By.id('dynamic'));
// Solution 3: Retry patternasync function retryingFind(driver, locator, attempts = 3) { for (let i = 0; i < attempts; i++) { try { return await driver.findElement(locator); } catch (e) { if (e.name !== 'StaleElementReferenceError') throw e; } } throw new Error('Element still stale after retries');}// Problem: StaleElementReferenceException
// Solution 1: Re-find the elementIWebElement element = driver.FindElement(By.Id("dynamic"));try{ element.Click();}catch (StaleElementReferenceException){ element = driver.FindElement(By.Id("dynamic")); element.Click();}
// Solution 2: Wait for staleness then find againWebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));IWebElement oldElement = driver.FindElement(By.Id("dynamic"));driver.FindElement(By.Id("refresh")).Click();wait.Until(ExpectedConditions.StalenessOf(oldElement));IWebElement newElement = wait.Until( ExpectedConditions.ElementExists(By.Id("dynamic")));
// Solution 3: Retry patternpublic IWebElement RetryingFind(By locator, int attempts = 3){ for (int i = 0; i < attempts; i++) { try { return driver.FindElement(locator); } catch (StaleElementReferenceException) { } } throw new Exception("Element still stale after retries");}Debugging Tools
Browser DevTools
// In browser console:
// Find element by CSS selectordocument.querySelector('#myId')document.querySelectorAll('.myClass')
// Find element by XPath$x("//button[@id='submit']")$x("//div[contains(text(), 'Hello')]")
// Check if element is visibleconst el = document.querySelector('#myId');const style = getComputedStyle(el);console.log('display:', style.display);console.log('visibility:', style.visibility);console.log('opacity:', style.opacity);
// Find what's at specific coordinatesdocument.elementFromPoint(100, 200)
// Monitor events on an elementmonitorEvents(document.querySelector('#myId'), 'click')Taking Screenshots
Screenshot on Failure
Selenium 3 & 4 Stable
import org.openqa.selenium.OutputType;import org.openqa.selenium.TakesScreenshot;import java.io.File;import java.nio.file.Files;
public void takeScreenshot(String filename) { File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); try { Files.copy(screenshot.toPath(), new File("screenshots/" + filename + ".png").toPath()); } catch (IOException e) { e.printStackTrace(); }}
// In test teardown@AfterMethodpublic void afterMethod(ITestResult result) { if (result.getStatus() == ITestResult.FAILURE) { takeScreenshot(result.getName()); }}import osfrom datetime import datetime
def take_screenshot(driver, name): timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"screenshots/{name}_{timestamp}.png" os.makedirs("screenshots", exist_ok=True) driver.save_screenshot(filename) return filename
# Using pytest fixture@pytest.fixture(autouse=True)def screenshot_on_failure(request, driver): yield if request.node.rep_call.failed: take_screenshot(driver, request.node.name)async function takeScreenshot(driver, name) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const filename = `screenshots/${name}_${timestamp}.png`;
const fs = require('fs'); if (!fs.existsSync('screenshots')) { fs.mkdirSync('screenshots'); }
const image = await driver.takeScreenshot(); fs.writeFileSync(filename, image, 'base64'); return filename;}public void TakeScreenshot(string name){ string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); string filename = $"screenshots/{name}_{timestamp}.png";
Directory.CreateDirectory("screenshots");
Screenshot screenshot = ((ITakesScreenshot)driver).GetScreenshot(); screenshot.SaveAsFile(filename);}
// In test teardown[TearDown]public void TearDown(){ if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Failed) { TakeScreenshot(TestContext.CurrentContext.Test.Name); }}Debugging Checklist
| Check | Question |
|---|---|
| URL | Am I on the right page? |
| Frame | Am I in the right frame/iframe? |
| Timing | Did I wait long enough? |
| Locator | Does my locator match in DevTools? |
| Visibility | Is the element visible/enabled? |
| Overlay | Is something blocking the element? |
| State | Did the page change since I found the element? |
Best Practices
- Add logging to track test execution flow
- Take screenshots on failure automatically
- Use explicit waits instead of sleep
- Verify locators in browser DevTools first
- Check for frames when elements aren’t found
- Review page state before and after actions
Next Steps
- Screenshots and Videos - Capture visual evidence
- Common Errors - Error reference guide
- Explicit Waits - Prevent timing issues
- JavaScript Executor - Advanced debugging techniques