Monitoring WebDriver Actions – Using WebDriverEventListener and EventFiringWebDriver

WebDriver performs a sequence of complex actions in the background even for tasks which seem as trivial as navigating to a webpage and entering some test data. Selenium provides useful framework which gives a peep into the busy life of WebDriver. When things become critical, debugging at the level of each event becomes crucial – these events being navigating to a URL, web element’s value changing, script getting executed through webdriver and most useful one, an event just when exception occurs. TestNG provides its own implementations for the root level event tracking like ITestListener and ISuiteListeners, but Selenium has its own way of doing this.

To throw an event, WebDriver gives a class named EventFiringWebDriver, and to catch that event, it provides an interface named WebDriverEventListener. Together, these two can be used to trigger an event, catch it and perform desired action.

There may be more than one listeners waiting for a single event and handle it their own way. It’s done by registering multiple listeners to an EventFiringWebDriver.

The whole flow of things looks like:

  1. Create an EventListener class
  2. Create a WebDriver instance
  3. Create an instance of EventFiringWebDriver by passing driver from step 2
  4. Create an instance of EventListener
  5. Register this EventListener to the EventFiringWebDriver Instance
  6. Done !! Handle the events sent by WebDriver now

An event listener can be created by either:

  1. Implementing WebDriverEventListener interface
  2. Extending AbstractWebDriverEventListener class

I am using the interface in the example here. Implementing the interface makes me define all the methods of Interface. So the code for a class implementing WebDriverEventListener is like:

package org.selenium;
import org.openqa.selenium.*;
import org.openqa.selenium.support.events.WebDriverEventListener;


public class TheEventListener implements WebDriverEventListener{

	@Override
	public void afterChangeValueOf(WebElement arg0, WebDriver arg1) {
		System.out.println("After change of value :" + arg0.toString());
		
	}

	@Override
	public void afterClickOn(WebElement arg0, WebDriver arg1) {
		System.out.println("After click on webelement: " + arg0.getText());
	}

	@Override
	public void afterFindBy(By arg0, WebElement arg1, WebDriver arg2) {
		System.out.println("After find by: " + arg0.toString());
	}

	@Override
	public void afterNavigateBack(WebDriver arg0) {
		System.out.println("After navigating back to : " + arg0.getCurrentUrl());
	}

	@Override
	public void afterNavigateForward(WebDriver arg0) {
		System.out.println("After navigating forward to : "+ arg0.getCurrentUrl());
	}

	@Override
	public void afterNavigateTo(String arg0, WebDriver arg1) {
		System.out.println("After navigating to : "+arg0);
	}

	@Override
	public void afterScript(String arg0, WebDriver arg1) {
		System.out.println("After execution of script : "+ arg0);
	}

	@Override
	public void beforeChangeValueOf(WebElement arg0, WebDriver arg1) {
		System.out.println("Before value change of : " + arg0.toString());
	}

	@Override
	public void beforeClickOn(WebElement arg0, WebDriver arg1) {
		System.out.println("Before clicking on WebElement : " + arg0.getText());
	}

	@Override
	public void beforeFindBy(By arg0, WebElement arg1, WebDriver arg2) {
		System.out.println("Before find by : " + arg0.toString());
	}

	@Override
	public void beforeNavigateBack(WebDriver arg0) {
		System.out.println("Before navigating back from : " + arg0.getCurrentUrl());
	}

	@Override
	public void beforeNavigateForward(WebDriver arg0) {
		System.out.println("Before navigating forward from : "+ arg0.getCurrentUrl());
	}

	@Override
	public void beforeNavigateTo(String arg0, WebDriver arg1) {
		System.out.println("Before navigating to : "+ arg0);
	}

	@Override
	public void beforeScript(String arg0, WebDriver arg1) {
		System.out.println("Before executing the script : " + arg0);
	}

	@Override
	public void onException(Throwable arg0, WebDriver arg1) {
		System.out.println("On exception : " + arg0.getMessage());
		arg1.quit();
	}

}


Now comes the event firing WebDriver. It’s the attention seeking big brother of WebDriver who loves to brag about what he’s going to do and have done. Listeners, tuned-in or, registered with this driver get to know everything and act as they want.

This is the code for an EventFiringWebdriver implementation:

 

package org.selenium;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.*;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.openqa.selenium.support.ui.Select;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class TheDriver {
	
	WebDriver driver;
	
	@BeforeClass
	public void setupBrowser()
	{
		driver = new FirefoxDriver();
		driver.manage().window().maximize();
	}
	
	@Test
	public void BrowserTest()
	{
		
	EventFiringWebDriver eventFiringDriver = new EventFiringWebDriver(driver); //Get EventFiringWebDriver instance
	
	TheEventListener eventListener = new TheEventListener(); //Get Listener instance
	eventFiringDriver.register(eventListener); // Register listener to driver
	
	eventFiringDriver.navigate().to("https://www.wikipedia.org/");
	eventFiringDriver.findElement(By.id("searchInput")).sendKeys("Lorem Ipsum");
	Select selLanguage = new Select(eventFiringDriver.findElement(By.id("searchLanguage")));
	selLanguage.selectByValue("en");
	eventFiringDriver.findElement(By.xpath(".//body[@id='www-wikipedia-org']/div[2]//input[@type='submit']")).click();
	
	eventFiringDriver.navigate().back();
	}
	
	@AfterClass
	public void exit() throws InterruptedException
	{
		Thread.sleep(2000);
		driver.quit();
	}
	

}

On execution, you get every event listed on the console just as we wanted to be handled. It gives an exception which is also expected.

This is how the output looks like:


Before navigating to : https://www.wikipedia.org/
After navigating to : https://www.wikipedia.org/
Before find by : By.id: searchInput
After find by: By.id: searchInput
Before value change of : [[FirefoxDriver: firefox on WINDOWS (8dc5e6de-b235-452e-8884-dfb1d6ea4d0b)] -> id: searchInput]
After change of value :[[FirefoxDriver: firefox on WINDOWS (8dc5e6de-b235-452e-8884-dfb1d6ea4d0b)] -> id: searchInput]
Before find by : By.id: searchLanguage
After find by: By.id: searchLanguage
Before find by : By.xpath: .//option[@value = “en”]
After find by: By.xpath: .//option[@value = “en”]
Before find by : By.xpath: .//body[@id=’www-wikipedia-org’]/div[2]//input[@type=’submit’]
After find by: By.xpath: .//body[@id=’www-wikipedia-org’]/div[2]//input[@type=’submit’]
Before clicking on WebElement :
On exception : Element not found in the cache – perhaps the page has changed since it was looked up

Thanks for reading !!!

Monitoring WebDriver Actions – Using WebDriverEventListener and EventFiringWebDriver