Change GeoLocation in Firefox with Selenium WebDriver

Problem

We want to manipulate our GeoLocation in the Firefox browser using Selenium WebDriver.

Solution

We have to follow a few steps in order to achieve the desired behavior. We have to create a customized Firefox profile, we have to create a JSON file with the desired location and finally we have to adjust our code to use the customized profile and JSON location file.

  • Create a predefined Firefox profile.
  1. Start the Firefox Profile manager with: firefox.exe -P and create a new profile.
  2. Open about:permissions in the browser
  3. Locate the entry of the website and change Share Location from Always Ask to Allow
  • Create a JSON file with a GeoLocation.

{
    "status": "OK",
    "accuracy": 10.0,
    "location": {"lat": 52.1771129, "lng": 5.4099848}
}
1
2
3
4
5
{
    "status": "OK",
    "accuracy": 10.0,
    "location": {"lat": 52.1771129, "lng": 5.4099848}
}
  • Use the just created profile and set the geo.wifi.uri preference before launching the browser. So, the the code will end up like this:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.firefox.internal.ProfilesIni;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class LocationContextExample {
    private static WebDriver driver;

    @BeforeClass
    public void setUp() {
        FirefoxProfile profile = new ProfilesIni().getProfile("dev");
        profile.setPreference("geo.wifi.uri", "file://C:/location.json");
        driver = new FirefoxDriver(profile);
        driver.get("http://www.w3schools.com/html5/html5_geolocation.asp");
    }

    @AfterClass
    public void tearDown() {
        driver.close();
        driver.quit();
    }

    @Test
    public void getLocation() throws InterruptedException {
        driver.findElement(By.cssSelector("p#demo button")).click();
        Thread.sleep(5000);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.firefox.internal.ProfilesIni;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class LocationContextExample {
    private static WebDriver driver;

    @BeforeClass
    public void setUp() {
        FirefoxProfile profile = new ProfilesIni().getProfile("dev");
        profile.setPreference("geo.wifi.uri", "file://C:/location.json");
        driver = new FirefoxDriver(profile);
        driver.get("http://www.w3schools.com/html5/html5_geolocation.asp");
    }

    @AfterClass
    public void tearDown() {
        driver.close();
        driver.quit();
    }

    @Test
    public void getLocation() throws InterruptedException {
        driver.findElement(By.cssSelector("p#demo button")).click();
        Thread.sleep(5000);
    }
}

(English) Capturing javascript errors with Selenium WebDriver

Problem

We want to capture javascript errors with our FirefoxDriver implementation.

Solution

We need to add a pre-built jar to our project. We can download it here. The following code will show us how we can use the library to capture javascript errors:


package tipsAndTricks;
import java.io.IOException;
import java.util.List;

import net.jsourcerer.webdriver.jserrorcollector.JavaScriptError;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class CaptureJavascriptErrors {
    private static WebDriver driver;
    
    @BeforeClass
    public void setUp() throws IOException {
        FirefoxProfile ffProfile = new FirefoxProfile();
        JavaScriptError.addExtension(ffProfile);
        driver = new FirefoxDriver(ffProfile);
        driver.get("http://www.telegraaf.nl/");
    }
    
    @AfterClass
    public void tearDown() {
        List<JavaScriptError> jsErrors = JavaScriptError.readErrors(driver);
        System.out.println("###start displaying errors");
        for(int i = 0; i < jsErrors.size(); i++) {
            System.out.println(jsErrors.get(i).getErrorMessage());
            System.out.println(jsErrors.get(i).getLineNumber());
            System.out.println(jsErrors.get(i).getSourceName());
        }
        System.out.println("###start displaying errors");
        driver.close();
        driver.quit();
    }
    
    @Test
    public void returnJavascriptErrors() throws InterruptedException {
        Thread.sleep(5000);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package tipsAndTricks;
import java.io.IOException;
import java.util.List;

import net.jsourcerer.webdriver.jserrorcollector.JavaScriptError;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class CaptureJavascriptErrors {
    private static WebDriver driver;
    
    @BeforeClass
    public void setUp() throws IOException {
        FirefoxProfile ffProfile = new FirefoxProfile();
        JavaScriptError.addExtension(ffProfile);
        driver = new FirefoxDriver(ffProfile);
        driver.get("http://www.telegraaf.nl/");
    }
    
    @AfterClass
    public void tearDown() {
        List<JavaScriptError> jsErrors = JavaScriptError.readErrors(driver);
        System.out.println("###start displaying errors");
        for(int i = 0; i < jsErrors.size(); i++) {
            System.out.println(jsErrors.get(i).getErrorMessage());
            System.out.println(jsErrors.get(i).getLineNumber());
            System.out.println(jsErrors.get(i).getSourceName());
        }
        System.out.println("###start displaying errors");
        driver.close();
        driver.quit();
    }
    
    @Test
    public void returnJavascriptErrors() throws InterruptedException {
        Thread.sleep(5000);
    }
}

How to use it

We can enrich our @Before en @After methods, like above.

Markeer elementen met Selenium WebDriver

Probleem

We willen graag elementen met Selenium WebDriver markeren, zoals we dat kunnen doen met de vorige versie van Selenium. Dit zal ons helpen om te zien welke elementen er worden gebruikt. Deze methode zal de test een beetje vertragen, maar soms is het handig voor debug doeleinden.

Oplossing


public void highlightElement(WebDriver driver, WebElement element) {
    for (int i = 0; i < 2; i++) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "color: yellow; border: 2px solid yellow;");
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "");
    }
}
1
2
3
4
5
6
7
8
9
public void highlightElement(WebDriver driver, WebElement element) {
    for (int i = 0; i < 2; i++) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "color: yellow; border: 2px solid yellow;");
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "");
    }
}

Hoe te gebruiken…


@Test
public void highlightTest() {
    WebElement searchField = driver.findElement(By
            .cssSelector("input#search_query_top"));
    highlightElement(searchField);
    searchField.sendKeys("ipod nano");

    WebElement searchButton = driver.findElement(By.cssSelector("input[name='submit_search']"));
    highlightElement(searchButton);
    searchButton.click();

    String searchHeader = driver.findElement(By.cssSelector("H1")).getText().toLowerCase();
    Assert.assertTrue(searchHeader.contains("ipod nano"));
}

public void highlightElement(WebElement element) {
    for (int i = 0; i < 2; i++) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "color: yellow; border: 2px solid yellow;");
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "");
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void highlightTest() {
    WebElement searchField = driver.findElement(By
            .cssSelector("input#search_query_top"));
    highlightElement(searchField);
    searchField.sendKeys("ipod nano");

    WebElement searchButton = driver.findElement(By.cssSelector("input[name='submit_search']"));
    highlightElement(searchButton);
    searchButton.click();

    String searchHeader = driver.findElement(By.cssSelector("H1")).getText().toLowerCase();
    Assert.assertTrue(searchHeader.contains("ipod nano"));
}

public void highlightElement(WebElement element) {
    for (int i = 0; i < 2; i++) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "color: yellow; border: 2px solid yellow;");
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);",
                element, "");
    }
}

Injecting the Sizzle CSS selector library

Probleem

We kunnen wat problemen ervaren met het lokaliseren van elementbij de implementatie van WebDriver. Deze problemen komen naar voren, omdat WebDriver strikt de CSS standaard volgt. Bijvoorbeeld :contains(‘text’) werkt niet meer. De oplossing is het injecteren van de Sizzle engine in de browser waar de tests in worden uitgevoerd. Door het maken van een aparte SizzleSelector class kunnen we *SizzleSelector *eenvoudig gebruiken.

Oplossing

Dit is de code van de SizzleSelector class. Het injecteerd, met gebruik van Javascript, de Sizzle engine in de browser.


import java.util.List;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
 
@SuppressWarnings("unchecked")
public class SizzleSelector {
    private JavascriptExecutor driver;
 
    public SizzleSelector(WebDriver webDriver) {
        driver = (JavascriptExecutor) webDriver;
    }
 
    public WebElement findElementBySizzleCss(String using) {
        injectSizzleIfNeeded();
        String javascriptExpression = createSizzleSelectorExpression(using);
        List<WebElement> elements = (List<WebElement>) driver
                .executeScript(javascriptExpression);
        if (elements.size() > 0)
            return (WebElement) elements.get(0);
        return null;
    }
 
    public List<WebElement> findElementsBySizzleCss(String using) {
        injectSizzleIfNeeded();
        String javascriptExpression = createSizzleSelectorExpression(using);
        return (List<WebElement>) driver.executeScript(javascriptExpression);
    }
 
    private String createSizzleSelectorExpression(String using) {
        return "return Sizzle(\"" + using + "\")";
    }
 
    private void injectSizzleIfNeeded() {
        if (!sizzleLoaded())
            injectSizzle();
    }
 
    public Boolean sizzleLoaded() {
        Boolean loaded;
        try {
            loaded = (Boolean) driver.executeScript("return Sizzle()!=null");
        } catch (WebDriverException e) {
            loaded = false;
        }
        return loaded;
    }
 
    public void injectSizzle() {
        driver.executeScript(" var headID = document.getElementsByTagName(\"head\")[0];"
                + "var newScript = document.createElement('script');"
                + "newScript.type = 'text/javascript';"
                + "newScript.src = 'https://raw.github.com/jquery/sizzle/master/sizzle.js';"
                + "headID.appendChild(newScript);");
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.util.List;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
 
@SuppressWarnings("unchecked")
public class SizzleSelector {
    private JavascriptExecutor driver;
 
    public SizzleSelector(WebDriver webDriver) {
        driver = (JavascriptExecutor) webDriver;
    }
 
    public WebElement findElementBySizzleCss(String using) {
        injectSizzleIfNeeded();
        String javascriptExpression = createSizzleSelectorExpression(using);
        List<WebElement> elements = (List<WebElement>) driver
                .executeScript(javascriptExpression);
        if (elements.size() > 0)
            return (WebElement) elements.get(0);
        return null;
    }
 
    public List<WebElement> findElementsBySizzleCss(String using) {
        injectSizzleIfNeeded();
        String javascriptExpression = createSizzleSelectorExpression(using);
        return (List<WebElement>) driver.executeScript(javascriptExpression);
    }
 
    private String createSizzleSelectorExpression(String using) {
        return "return Sizzle(\"" + using + "\")";
    }
 
    private void injectSizzleIfNeeded() {
        if (!sizzleLoaded())
            injectSizzle();
    }
 
    public Boolean sizzleLoaded() {
        Boolean loaded;
        try {
            loaded = (Boolean) driver.executeScript("return Sizzle()!=null");
        } catch (WebDriverException e) {
            loaded = false;
        }
        return loaded;
    }
 
    public void injectSizzle() {
        driver.executeScript(" var headID = document.getElementsByTagName(\"head\")[0];"
                + "var newScript = document.createElement('script');"
                + "newScript.type = 'text/javascript';"
                + "newScript.src = 'https://raw.github.com/jquery/sizzle/master/sizzle.js';"
                + "headID.appendChild(newScript);");
    }
}

Hoe te gebruiken

De class die hierboven is beschreven injecteert de Sizzle engine in de browser. Dit steld ons in staat om alle Sizzle selector features te gebruiken, zoals :contains(‘text’). Andere classes extenden deze class en dan is het mogelijk om findElementBySizzleCss() te gebruiken bij het lokaliseren van elementen.


import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class SizzleExample {
    private static WebDriver driver;
    SizzleSelector sizzle;
    
    @BeforeClass
    public void setUp() {
        driver = new FirefoxDriver();
        sizzle = new SizzleSelector(driver);
        driver.get("http://selenium.polteq.com/prestashop/");
    }
    
    @AfterClass
    public void tearDown() {
        driver.close();
        driver.quit();
    }
    
    @Test
    public void useSizzleSelector() {
        sizzle.findElementBySizzleCss("input#search_query_top").sendKeys("ipod nano");
        sizzle.findElementBySizzleCss("input[name='submit_search']").click();
        String searchHeader =  sizzle.findElementBySizzleCss("H1").getText().toLowerCase();
        
        Assert.assertTrue(searchHeader.contains("ipod nano"));
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class SizzleExample {
    private static WebDriver driver;
    SizzleSelector sizzle;
    
    @BeforeClass
    public void setUp() {
        driver = new FirefoxDriver();
        sizzle = new SizzleSelector(driver);
        driver.get("http://selenium.polteq.com/prestashop/");
    }
    
    @AfterClass
    public void tearDown() {
        driver.close();
        driver.quit();
    }
    
    @Test
    public void useSizzleSelector() {
        sizzle.findElementBySizzleCss("input#search_query_top").sendKeys("ipod nano");
        sizzle.findElementBySizzleCss("input[name='submit_search']").click();
        String searchHeader =  sizzle.findElementBySizzleCss("H1").getText().toLowerCase();
        
        Assert.assertTrue(searchHeader.contains("ipod nano"));
    }
}

Creating an UI-map for Selenium IDE

Problem

By making an UI-element repository we can make a mapping between semantically meaningful names of elements on the web pages and the elements themselves. We can define this mapping using JSON (JavaScript Object Notation). We can use this JSON file in Selenium IDE. It makes your tests less brittle as we have a single point of update. In this recipe we will see how to define the UI-map.

Prerequisites

We have to create a new text file with notepad and store it as, uimap.js

Solution

  1. We have to initialize a new UIMap object, using the following code: var map = new UIMap();

  2. Now we can add pagesets, which can define a set of pages that share a set of common page elements. A pageset can have the following attributes:

Attribute Mandatory Description
name Yes The name of the pageset, This should be unique within the UIMap.
description Yes Description of the pageset. It could give you an idea of what UI-elements the pageset will have.
pagePrefix No The path of the URL which indicates the prefix for a certain page.
paths pathRegexp Yes A string or array with regular expressions.
  paramRegexps No A mapping from URL parameter names to regular expression strings which must match their values.
pageContent    Conditional A function that tests whether a page, represented by its document object, is contained in the pageset, and returns true if this is the case. 

We can define a pageset using the following code: 


myMap.addPageset({
    name : 'SignInPage',
    description : 'Sign in page',
    pathRegexp : '.*'
}); 
1
2
3
4
5
myMap.addPageset({
    name : 'SignInPage',
    description : 'Sign in page',
    pathRegexp : '.*'
}); 
  1. Finally we can add UI-elements. They can exist of multiple attributes, the most common attributes are listed in the table below.
Attribute Mandatory Description
name Yes Name of the element
description Yes Description of the element. This is used for documentation purposes.
args No A list of arguments that will modify the getLocator() method.
locator getLocator Yes Either a fixed locator string, or a function that returns a locator string given a set of arguments.
  1. We can define a single UI-element using the following code:

myMap.addElement('SignInPage', {
    name : 'UserNameTextBox',
    description : 'UserName Text Box',
    locator : "ctl00_mainContentPlaceHolder_txt_LoginName"
});
1
2
3
4
5
myMap.addElement('SignInPage', {
    name : 'UserNameTextBox',
    description : 'UserName Text Box',
    locator : "ctl00_mainContentPlaceHolder_txt_LoginName"
});

Creating an object repository for Selenium WebDriver

Problem

It is very useful to extract the locators from the test code. This makes your test code much more maintainable and readable. Beside of that there is no need to recompile the project after changing the identifiers. There are many ways to do it, but we will see just one way in this example. It can be done by the Java properties file. Just load the file in front of running the tests and then you can use all the properties, that is basically everything what you have to do. The properties file is just flat text. That is why there is no need to recompile the whole source code once locators have been changed. We can also make use of the same locators in multiple test cases. These are big advantages of using a object repository.

Prerequisites

We can install Eclipse as preferred IDE to setup a Java test project.

Solution

  1. We have to create a properties file, given this name locators.properties. The part before the equals sign is the key, the part after the equals sign is the value. We can give the following content to the file:
login.username.textfield=css=input#username
login.password.textfield=css=input#password
  1. We have to load the properties file, before we can call the locators. We have to initiate the properties object and load the contents of the file in it. We can do this with the following code:
Properties props = new Properties();
try {
    InputStream in = getClass().getResourceAsStream("locators.properties");
    props.load(in);
} catch (IOException e) {
}
  1. We can use the object repository, once the key/values are actually loaded in the properties object. We can use the value in our tests, by calling the key parameter, like this:
props.getProperty("login.username.textfield")

What has been done

We are loading a key/value pairs into a properties object. Make sure you will do this in front of running any tests. Finally we are able to get the value by it’s key.

Source Code

The source code is available on GitHub at the following location: https://github.com/roydekleijn/HowToUsePropertiesFile