In this post we will be focusing on some advanced topics in Selenium.
Selenium WebDriver Wait commands:
This is one of the most used commands. Most of the times the code executes much faster than the web page navigation. If not synchronized, then the test case execution will fail. To overcome this, we use different Wait commands to slow our execution. Each of these commands have their own purpose:
- Implicit Wait: Implicit waits are used to provide a user specified waiting time between each consecutive test step/command across the entire test script. This means Implicit waits will be in place for the entire time the browser is open and is applicable to search for elements also. Once set, the implicit wait is set for the life of the WebDriver object instance. Below is the code for Implicit Wait.
-
// Initialize Chrome WebDriver WebDriver driver = new ChromeDriver(); // Setting Implicit Wait for 10 seconds driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Navigate to Google Website driver.get("http://www.google.com"); //Maximize browser window driver.manage().window().maximize(); //Relative XPath for the text box driver.findElement(By.xpath("//input[@id='lst-ib']")).sendKeys("selenium");
- Explicit Wait: Explicit waits are used to stop the execution till the time a particular condition or Expected Condition is met or the maximum time has elapsed before throwing an “ElementNotVisibleException” exception. Explicit wait applies for specified element only. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until it returns successfully. Below is the code for Explicit Wait.
/ Initialize Chrome WebDriver WebDriver driver = new ChromeDriver(); // Setting Implicit Wait for 10 seconds driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Navigate to Google Website driver.get("http://www.google.com"); //Maximize browser window driver.manage().window().maximize(); //Relative XPath for the text box driver.findElement(By.xpath("//input[@id='lst-ib']")).sendKeys("selenium"); /* Setting Explicit Wait 10 seconds for Search icon button to be Clickable */ WebDriverWait wait = new WebDriverWait(driver, 10); WebElement searchElement = wait.until(ExpectedConditions.elementToBeClickable(By.id("_fZl"))); //Once searchElement is clickable searchElement.click();
- Fluent Wait: Fluent wait is another type of Explicit wait and you can define polling and ignore the exception to continue with script execution in case element is not found. Using Fluent wait we can define the frequency with which Fluent Wait has to check the conditions defined, ignore specific types of exception waiting such as NoSuchElementExceptions while searching for an element and set maximum amount of time to wait for a condition.
/* Waiting 30 seconds for an element to be present on the page, checking */ // for its presence once every 5 seconds. public void waitForElement(By by) { new FluentWait(driver) .withTimeout(30, TimeUnit.SECONDS) .pollingEvery(5, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class) .until(new ExpectedCondition() { @Override public Boolean apply(WebDriver driver) { WebElement element = driver.findElement(by); if (element == null) return false; else { System.out.println("WebElement found"); return true; } } }); }
- Page Load Timeout: Page Load Timeout sets the amount of time to wait for a page load to complete before throwing an error. If the timeout is negative, page loads can be indefinite.
driver.manage().timeouts().pageLoadTimeout(30, SECONDS);
Keyboard and Mouse Actions:
Using Actions class we can emulate complex user gestures. Sometimes we need to perform a ‘mouse hover’ action on a web site or we need to perform chain of actions like going to menu, and then from there to sub menu etc.. Sometimes we may need to do a drag and drop on a web site. All of these actions are possible using Actions class.
- Mouse Hover: Using Actions class we can do a mouse hover on any links in web page. Below is the code:
//Create actions object and pass WebDriver Actions actions = new Actions(driver); //Get the WebElement for Mouse Hover WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link")); //Perform the mouse hover //Use build().perform() to complete the action action.moveToElement(mainMenu).build().perform();
- Click Sub Menu inside Menu: Actions class can also be used to click sub menu inside main menu where the main menu appears only when we do a mouser hover.
//Create actions object and pass WebDriver Actions actions = new Actions(driver); //Get the WebElement for Main Menu WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link")); //Move to Main Menu do mouse hover action.moveToElement(mainMenu); //Get the WebElement for Sub Menu //Sub Menu will be displayed inside Menu WebElement subMenu = driver.findElement(By.linkText("Best price search")); //Use the actions object to move to sub menu and click //Use build().perform() to complete the action actions.moveToElement(subMenu).click().build().perform();
- Drag and Drop: Using Actions class we can perform drag and drop a web element. This can be done either by providing the source and target elements or by providing source elements and x, y coordinates for the destination. Below is the sample code for performing drag and drop:
//Create actions object and pass WebDriver Actions actions = new Actions(driver); //Source Element WebElement dragElement =driver.findElement(By.id("draggable")); //Target Element WebElement dropElement =driver.findElement(By.id("droppable")); //Use the actions object to perform drag and drop using source target elements actions.dragAndDrop(dragElement, dropElement).perform(); //Use the actions object to perform drag and drop using x, y coordinates actions.dragAndDropBy(mainMenu, 300, 200).perform();
- Double Click: Using Actions class we can perform double click on an element. Below sample code is for performing double click:
//Create actions object and pass WebDriver Actions actions = new Actions(driver); //Get the WebElement for Main Menu WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link")); //Use the actions object to perform double click on Main Menu actions.doubleClick(mainMenu);
- Right Click: Using Actions class we can also perform right click on an element.
//Create actions object and pass WebDriver Actions actions = new Actions(driver); //Get the WebElement for Main Menu WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link")); //Use contextClick method do right click on Main Menu actions.contextClick(mainMenu);
- Click, Hold and Move: This can be performed by click and hold a web element and then drag it to required location. Below is the set of code to perform the action:
/Create actions object and pass WebDriver Actions actions = new Actions(driver); //Source Element WebElement dragElement =driver.findElement(By.id("draggable")); //Target Element WebElement dropElement =driver.findElement(By.id("droppable")); /* Use actions object to click and hold the source element and move to target element and release source element. Use build().perform() to complete the action. */ actions.clickAndHold(mainMenu).moveToElement(subMenu).release(mainMenu).build().perform();
The same commands can be used for resizing the window. However we have to provide x, y coordinates of the resized window. In this case we have to select ‘moveByOffset’ method instead of ‘moveToElement’.
//Resize a window to x, y coordinates actions.clickAndHold(mainMenu).moveByOffset(100, 100).release(mainMenu).build().perform();
- Sliders: There are some web elements in a web page, which can be moved sideways or up and down like the volume or equalizer bars etc. These kind of movements can also be controlled using Actions class.
//Slide horizontally to forward direction. Note y coordinate is 0. actions.clickAndHold(sliderElement).moveByOffset(100, 0).release(sliderElement).build().perform(); //Slide horizontally to backward direction. Note y coordinate is 0. actions.clickAndHold(sliderElement).moveByOffset(-100, 0).release(sliderElement).build().perform();
- Key Down/Up: keyDown performs a modifier key press, doesn’t release the modifier key. Subsequent interactions may assume it’s kept pressed. keyUp performs a key release. Below is the same code for performing keyDown and keyUp:
//Perform key press control a and then delete action.keyDown(Keys.CONTROL).sendKeys("a").keyUp(Keys.CONTROL).sendKeys(Keys.DELETE).perform();
Handeling Frames:
Frames are nothing but HTML code embedded inside another HTML code. They are defined inside <iframe></iframe> tags in HTML. Using this tag we can identify if the inspected object is inside a frame. We can get the frames details using firebug add on in Firefox browser.
Sometimes in order to access the objects inside the frames, we have to switch the Web Driver to the frame where the web elements are located. Below is the sample code for accessing the frames in different ways:
/* Three ways of navigating the web driver to frame. * 1. Using index number * 2. Using String Name or ID * 3. Using Web Element */ /* Switch to frame using index number. * This is not reliable as the index number varies with different browsers */ driver.switchTo().frame(0); //Access the web element inside the frame driver.findElement(By.id("nav-menuitem-1-link")).click(); /* Switch to frame using ID or Name. * Frame id = google_ads_iframe_/55875582/WMUS/homepage_0 */ driver.switchTo().frame("google_ads_iframe_/55875582/WMUS/homepage_0"); //Access the web element inside the frame driver.findElement(By.id("nav-menuitem-1-link")).click(); //Identify the frame element first WebElement frameOne = driver.findElement(By.id("google_ads_iframe_/55875582/WMUS/homepage_0")); //Pass the frame details to web driver driver.switchTo().frame(frameOne); //Access the web element inside the frame driver.findElement(By.id("nav-menuitem-1-link")).click();
Once we are done with all the task in a particular frame we have to switch back to the main page. This is very important otherwise the Web Driver will always continue in current frame. Below is the sample code to switch back to main page.
//Switching back to main page driver.switchTo().parentFrame();
Handeling Multiple Windows:
Sometimes when clicking on a web element, a new tab is opened in the browser. What if we want to move the focus of the Web Driver from the parent page to newly opened page? Using Selenium we can handle multiple windows.
The code works by first identifying the parent window ID and then by getting the Set (java.util package) of opened window IDs. Note that window IDs are unique thats why we are using Set. To switch to child window we will use the iterator method of Set. Below is the sample method to switch to child window and then return the driver.
public WebDriver getChildWindow(WebDriver driver) { // getWindowHandle method will return the current id of the window String parentWindow = driver.getWindowHandle(); // Get the set of ids of open windows Set setWindow = driver.getWindowHandles(); // Create iterator object Iterator getWindow = setWindow.iterator(); // Navigate to child window and return driver while (getWindow.hasNext()) { String childWindow = getWindow.next(); // If childWindow!=parentWindow if (!childWindow.equalsIgnoreCase(parentWindow)) { //Switch to child window driver.switchTo().window(childWindow); return driver; } } return null; }
To switch back to parent window:
//Switch to parent window driver.switchTo().window(parentWindow);
Handeling Date Pickers:
Some web sites does not allow users to directly enter the date in text field. In those cases, the user need to select a date from the Calendar pop up. Below is one example of one such web site where the ‘Depart’ text box is non editable.
Although different web sites have their own implementation of date pickers, below sample code can be used in most cases.
// Setting System properties System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/Chrome/chromedriver"); // Initialize WebDriver WebDriver driver = new ChromeDriver(); // Maximize browser window driver.manage().window().maximize(); // Navigate to Test Website driver.get("https://www.skyscanner.com/"); // Click on Date Field present in web page driver.findElement(By.id("js-depart-input")).click(); // In Calendar click next icon to select next month driver.findElement(By.xpath("//div[@class='calendar-info-bar datepicker_clearfix']/button[2]")).click(); // Select 05/16/2017 date from Calendar driver.findElement(By.xpath("//table[@data-month='2017-05']/tbody/tr[3]/td[@data-id='2017-05-16']")).click(); // Verify the date in Date text box String departDate = driver.findElement(By.id("js-depart-input")).getAttribute("data-date"); if (departDate.equals("2017-05-16")) { System.out.println("PASS"); }
Scroll the Web Page:
For scrolling the web page up or down we can use the below code.
// Initialize WebDriver WebDriver driver = new FirefoxDriver(); //Create JavascriptExecutor object JavascriptExecutor jse = (JavascriptExecutor)driver; //Page down by 400 px jse.executeScript("scroll(0,400)"); //Scroll for a element jse.executeScript("arguments[0].scrollIntoView(true);", webElement); //Scroll Up using negative y coordinate jse.executeScript("scroll(0,-400)");
Similarly scrolling sideways can be done by changing the x coordinates.
Take Screenshot of full page:
It is very important to take screenshots when we execute a test script. Taking a screenshot also help us to debug or analyze any failed cases. Below code can be used for taking a screenshot for the entire page. Notice that we need to import ‘org.apache.commons.io.FileUtils‘ and ‘import org.openqa.selenium.TakesScreenshot‘ packages. Also in the below code we are saving the screenshot image inside Project/IMAGE folder. The image file will be named as ‘fileName.jpg’.
//Take a screenshot File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); try { FileUtils.copyFile(scrFile, new File(System.getProperty("user.dir")+"/IMAGES" + "/fileName" + ".jpg")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
Take Screenshot of Web Element:
Sometimes we don’t require a screenshot of an entire web page, instead what if we just need the screenshot of the object or the web element. This can be done by first taking the screenshot of the entire page and then cropping the web element using its coordinates. Below code can be used for taking a screenshot of a web element.
// Capture the Web Element WebElement element = driver.findElement(By.name("elementName")); //Get Height and Width of the Web Element int eleWidth = element.getSize().getWidth(); int eleHeight = element.getSize().getHeight(); // Create a rectangle using Width, Height and element location Rectangle rect = new Rectangle(eleWidth, eleHeight); /* Used selenium Point class to get x y coordinates of Image element to * get location(x y coordinates) of the element */ Point point = element.getLocation(); int xcord = point.getX(); int ycord = point.getY(); // Capture entire page screenshot as buffer. File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); // Reading full image screenshot. BufferedImage fullImg = ImageIO.read(scrFile); //Cut Image using height, width and x y coordinates parameters. BufferedImage dest = img.getSubimage(xcord, ycord, eleWidth, eleHeight); ImageIO.write(dest, "png", scrFile); //Used FileUtils class of apache.commons.io. //Save Image screenshot in Project/Images folder FileUtils.copyFile(scrFile, new File(System.getProperty("user.dir")+"/IMAGES"+ "/fileName" + ".png"));
In case if we are scrolling the web page, we need to make following changes.
//Page down by 400 px ((JavascriptExecutor)driver).executeScript("scroll(0,400)"); //Cut Image using height, width and x y coordinates parameters. BufferedImage dest = img.getSubimage(xcord, ycord - 400, eleWidth, eleHeight); ImageIO.write(dest, "png", scrFile);
With this we came to an end on some of the advanced topics in Selenium. Some of the topics are commonly used across all Selenium scripts. Many more interesting topics to follow. Till then, Happy Learning!