Total Pageviews

Showing posts with label WebDriver. Show all posts
Showing posts with label WebDriver. Show all posts

Monday, 12 January 2015

ChromeDriver: Mobile Emulation

ChromeDriver is a standalone server which implements WebDriver's wire protocol.

[C#]

    var mobileEmulation = new Dictionary
    {
        { "deviceName", "Apple iPhone 5" }
    };
    var options = new ChromeOptions();
    options.AddAdditionalCapability("mobileEmulation", mobileEmulation);
    driver = new ChromeDriver(options);
  
Tips:
  • The “mobileEmulation” dictionary must use a valid device name from the DevTools Emulation panel.  
    
 
Reference:
 
ChromeDriver
Provides a mechanism to write tests against Chrome 

ChromeOptions
Class to manage options specific to ChromeDriver

AddAdditionalCapability
Provides a means to add additional capabilities not yet added as type safe options for the Chrome driver. 

Friday, 27 June 2014

Selenium WebDriver: org.openqa.selenium.firefox.NotConnectedException

The Problem

org.openqa.selenium.firefox.NotConnectedException: Unable to connect to host 127.0.0.1 on port 7055 after 45000 ms

Solution 1

Download the latest version of Selenium

Tips:

Remember to add it to your build path

Solution 2

Alternatively, downgrade Firefox

Tips:
Mozilla's archive containing old versions of Firefox are for testing purposes, it is not recommended that you use anything but the latest version. Old versions of Firefox may pose a significant security risk.

Tuesday, 22 April 2014

Writing and verifying reliable locators

The problem
Selecting your locators are a core part of writing automated WebDriver tests. However, I have seen this part of automation get overlooked so many times.

If you do not craft you locators carefully you can end up wasting a lot of time debugging brittle test cases.

I have seen development teams lose faith in the tests because they consistently give incorrect results, which can sometimes be a direct result of using poorly written locators.

Iterating on the design off web apps or fixing bugs can cause the dynamics of a page to change. Dependent on the change you may want your test to fail. However, sometimes your test should be resilient to the change (for example, styling changes), and having solid locators plays a big part in this.
Writing solid locators reduce the cost of maintenance, for the reason that reliable locators make the tests less brittle. In turn, you do not need to amend them as often.

Crafting reliable locators
When selecting locators the first thing to look for is an ID, after inspecting the element if it has an ID go for that first. If the element does not have an ID, then look to see if it's parent has an ID that can be used as a starting point to provide support followed by the descendant.

The next option should be CSS class names, but only the class names that are determined by functionality. Choose these locators over CSS class names that are used for styling, because the look and feel of the page can change but the functionality may remain the same.
Another option would be to use "data-" attributes, although the "data-" attributes can only be used in HTML 5 compliant browsers.
When constructing locators try to avoid chaining direct descendants. The reason behind this is that a change to one element in the chain will cause the locator to fail. There will be occasions when you need to use a descendant, don't be afraid to use it. Use it with careful consideration and try not to use more than one or two if possible.

Another thing to avoid is using indexes, web apps change frequently and elements may get moved around (for example, a menu item in a list). In this particular scenario you wouldn't want the test to beak if your test is verifying the functionality of a menu item. Indexes should only be used in scenarios like when you want to select the first item from a list regardless of what the list item is.

Example
Fruits
  • Orange
  • Apple
If asked to select the Apple from the list above. Copying the XPath straight from Firebug will give you a locator similar to '/html/body/some/more/direct/descendants/div/ul/li[2]'. Now imagine if the list was wrapped inside an additional div... Will the Apple still be located? No!

I have also seen people create locators like this '//li[2]' or '//li[position()=2]'. Now imagine if another fruit was add to the top of the list... Will the Apple still be located? No!

To overcome a problem like this you can carefully construct your XPath as follows: '//*[@id='Shopping']//li[contains(text(), 'Apple')]'. Here you can see the Xpath uses the id of its parent as an anchor then drills into the list. When selecting the Apple, the contains function is used to ensure that the element that contains the text Apple is retrieved. This Xpath locator will work wherever the Apple is in the list.

The solution
The next time you are about to write a test, give FirePath a try. https://addons.mozilla.org/en-US/firefox/addon/firepath/
FirePath is a Firebug extension that adds a development tool to edit, inspect and generate XPath 1.0 expressions, CSS 3 selectors and JQuery selectors (Sizzle selector engine).
For FirePath to work properly you will need to install the Firebug addon.https://addons.mozilla.org/en-US/firefox/addon/firebug/
Before you;
  • right click on an element in FireBug and select Copy XPath or Copy CSS Path
  • traverse a page for a complex locator
  • repeatedly try out various locators in your tests in hope that you get what your looking for
Spend a minute or so of your time and carefully construct the locator and then try it out in FirePath.

Wednesday, 26 March 2014

Selenium WebDriver: Say cheese

Taking screenshots of a test failures using Selenium WebDriver can come in handy, especially when investigating failed test cases from previous test executions. For example, a test that may have ran overnight.
 
Screenshots coupled with the stack trace and logging allows you to diagnose why a test failed without the need to rerun the test.

In the solution below I will detail how to take a screenshot using Selenium WebDriver, with the following caveats;
  • I am not sure what test may fail, so I cannot explicitly set what tests should take a screenshot.
  • I do not want to capture a screenshot of successful test runs.
 
To get around this problem I will be taking advantage of NUnit's TestContext which contains a wealth of useful information. For example, the full name and status of a test.

Tips:


Ensure you edit the location for the screenshot file as you see fit.

[C#]
using System;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Diagnostics;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace TestAutomationEngineer
{
    [TestFixture]
    public class Screenshots
    {
        private IWebDriver driver;
        private string baseURL;
        private string filename;
        private string saveLocation;
        
        [SetUp]
        public void SetupTest()
        {
            driver = new FirefoxDriver();
            baseURL = "http://testautomationengineer.blogspot.co.uk/";
        }
        
        [TearDown]
        public void TeardownTest()
        {
         if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)
         {
          Snap(driver);
          Console.WriteLine("Check out why the test failed, look here: " + filename);
         }
         
         if(driver != null)
         {
          driver.Quit();
         }
        }
        
        [Test]
        public void TakeScreenshotTestThatPasses()
        {
         driver.Navigate().GoToUrl(baseURL);
         Assert.IsTrue(true);
        }
        
        [Test]
        public void TakeScreenshotTestThatFails()
        {
         driver.Navigate().GoToUrl(baseURL);
         Assert.IsTrue(false);
        }
        
        public void Snap(IWebDriver driver)
        {
         try{
          createTempDirectory();
          createFilename();
    ((ITakesScreenshot) driver).GetScreenshot().SaveAsFile(filename, ImageFormat.Png);
         }
         catch(Exception){}
        }
        
        public void createTempDirectory(){
         try{
          saveLocation = "c:\\temp\\";
    bool dirExists = System.IO.Directory.Exists(saveLocation);
    if(!dirExists)
        System.IO.Directory.CreateDirectory(saveLocation);
         }
         catch(Exception){}
        }
        
        public void createFilename(){
      try{
    var timeStamp = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
    filename = TestContext.CurrentContext.Test.FullName;
    string ext = ".png";
    filename = filename + timeStamp;
    filename = saveLocation + filename + ext;
         }
         catch(Exception){}
        }
        
    }
}

Reference:

ITakesScreenshot
Defines the interface used to take screen shot images of the screen.

GetScreenshot
Gets a Screenshot object representing the image of the page on the screen.

TestContext (NUnit)
The TestContext class allows tests to access certain information about the execution context.


Saturday, 28 December 2013

Selenium WebDriver: Handling mouseover and hover events

There are many ways to simulate mouse movement in Selenium WebDriver. A few of the of the ways I have used to date can be seen below.
  1. Use the Actions class
  2. Hijack the mouse
  3. Execute Javascript
Example

Hello world



[C#] Solution 1 : Action class

[Test]
public void handlingMouseoverEvent()
{
driver.Navigate().GoToUrl("http://testautomationengineer.blogspot.com/2013/12/selenium-webdriver-handling-mouseover.html");
Actions builder = new Actions(driver);
IWebElement smiley = driver.FindElement(By.Id("hoverOverMe"));
builder.MoveToElement(smiley).Build().Perform();
}


[C#] Solution 2 : Hijack the mouse

[Test]
public void handlingMouseoverEvent()
{
driver.Navigate().GoToUrl("http://testautomationengineer.blogspot.com/2013/12/selenium-webdriver-handling-mouseover.html");
ILocatable hoverItem = (ILocatable) driver.FindElement(By.Id("hoverOverMe"));
IMouse mouse = ((IHasInputDevices) driver).Mouse;
mouse.MouseMove(hoverItem.Coordinates);
}


[C#] Solution 3 : Execute Javascript

[Test]
public void handlingMouseoverEvent()
{
driver.Navigate().GoToUrl("http://testautomationengineer.blogspot.com/2013/12/selenium-webdriver-handling-mouseover.html");
var js = (IJavaScriptExecutor)driver;
            js.ExecuteScript("$('[id=hoverOverMe]').trigger('mouseover')");
}


Reference:

Actions
Provides a mechanism for building advanced interactions with the browser.

ExecuteScript
Executes JavaScript in the context of the currently selected frame or window.

IJavaScriptExecutor
Defines the interface through which the user can execute JavaScript.

ILocatable
Defines the interface through which the user can discover where an element is on the screen.

IMouse
Provides methods representing basic mouse actions.

MouseMove(ICoordinates)
Moves the mouse to the specified set of coordinates.

MoveToElement(IWebElement)
Moves the mouse to the specified element.

Monday, 25 November 2013

Selenium WebDriver: Perform a drag and drop

If your browser supports advanced user interactions like drag and drop, you can use the Actions class to imitate this behaviour.

Drag and Drop

This is an interactive demo. Drag and drop the small square into the large square. 



Below you will find an example detailing how to drag one element to another:

[C#] Solution 1

  [Test]
  public void draganddrop()
  {
   driver.Navigate().GoToUrl("http://testautomationengineer.blogspot.com/2013/11/selenium-webdriver-perform-drag-and-drop.html");
   
   IWebElement source = driver.FindElement(By.Id("draggable"));
   IWebElement target = driver.FindElement(By.Id("droppable"));
   
   Actions builder = new Actions(driver);
    builder.DragAndDrop(source, target);
    builder.Build().Perform();

    Assert.That(dragAndDropIsComplete());
  }
  
  private bool dragAndDropIsComplete()
  {
   return driver.FindElement(By.ClassName("drag-and-drop-complete")).Displayed;
  }

[C#] Solution 2


  [Test]
  public void draganddrop()
  {
   driver.Navigate().GoToUrl("http://testautomationengineer.blogspot.com/2013/11/selenium-webdriver-perform-drag-and-drop.html");
   
   IWebElement source = driver.FindElement(By.Id("draggable"));
   IWebElement target = driver.FindElement(By.Id("droppable"));
   
   Actions builder = new Actions(driver);
          builder.ClickAndHold(source);
          builder.MoveToElement(target);
          builder.Release(target);
          builder.Build().Perform();
    
   Assert.That(dragAndDropIsComplete());
  }
  
  private bool dragAndDropIsComplete()
  {
   return driver.FindElement(By.ClassName("drag-and-drop-complete")).Displayed;
  }

Tips:

  • Ensure native events are enabled
  • Maximise your browser windows before you perform a drag and drop


Reference: 

DragAndDrop

Performs a drag-and-drop operation from one element to another.

ClickAndHold

Clicks and holds the mouse button down on the specified element.

MoveToElement

Moves the mouse to the specified element.

Tuesday, 12 November 2013

Selenium WebDriver: Handling multiple windows

When testing web applications you may come across a few situations when you will need to handle multiple windows.

A common example of this could be clicking on a hyper-link which subsequently opens a new web-page in another window.

In some cases this may be a problem because Selenium WebDriver does not automatically switch to the new window.

Link
Visit my blog testautomationengineer.blogspot.co.uk

Below you will find an example detailing how to handle multiple windows:

[C#]

        [Test]
        public void OpenLinkInANewWindowThenSwitchToNewWindow()
        {
         driver.Navigate().GoToUrl("http://testautomationengineer.blogspot.com/2013/11/webdriver-handling-multiple-windows.html");
         
         // get the current windows handle
         string oldWindow = driver.CurrentWindowHandle;
         string newWindow = null;
         
         // open a link in a new window
         IWebElement element = driver.FindElement(By.Id("visitMyBlog"));
         element.SendKeys(Keys.Shift + Keys.Return);
         
         // wait for the new window
         WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
         wait.Until((d) => driver.WindowHandles.Count==2);
            
   // get the new window handle         
         var windowHandles = driver.WindowHandles;
         ReadOnlyCollection<string> windows = new ReadOnlyCollection<string>(windowHandles);
         foreach (string window in windows)
         {
          if(window != oldWindow)
          {
           newWindow = window;
          }
         }
         
         // switch to the new window
         driver.SwitchTo().Window(newWindow);
        }
Tips:

  • It is just as useful to keep track of your original window, as it is to keep track of your new window.
  • Each window in Selenium WebDriver has a unique handle identifier; this allows you to differentiate windows.
  • There may be a delay opening the new window, to avoid problems in this area wait for the count of window handles to increase.

Reference:

Gets the current window handle, which is an opaque handle to this window that uniquely identifies it within this driver instance.

Gets the window handles of open browser windows.