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:
- Create an EventListener class
- Create a WebDriver instance
- Create an instance of EventFiringWebDriver by passing driver from step 2
- Create an instance of EventListener
- Register this EventListener to the EventFiringWebDriver Instance
- Done !! Handle the events sent by WebDriver now
An event listener can be created by either:
- Implementing WebDriverEventListener interface
- 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 !!!