
Selenium 4: Mocking Geolocation
Selenium 4 is in alpha mode, and I’ve been trying out some of the new features. In this upcoming release, they are providing access to Chrome DevTools and the Chrome DevTools Protocol (CDP). Since I’ve been stuck in the house for 2 months due to COVID-19, I’m going to use this new feature to travel to Austin, TX to do some shopping…virtually at least!
Here is the recipe for programmatically overriding your browser’s geolocation.
Recipe to Change Geolocation in Chrome Browser
Ingredients
- Selenium WebDriver 4+
- Chrome browser
- Coordinates of mock location
Instructions
- Create an instance of ChromeDriver
- Invoke executeCdpCommand method
Live Stream Video
Ingredients
1 Selenium WebDriver 4+
Access to the Chrome DevTools Protocol was added in Selenium 4, so you’ll need that version as a minimum. At the time of this writing, Selenium 4 is in alpha, so note that this is experimental right now. Using maven, I add the dependency to my pom.xml file.
1 2 3 4 5 |
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-chrome-driver</artifactId> <version>4.0.0-alpha-5</version> </dependency> |
2 Chrome Browser
Because we’re using Chrome DevTools, of course, we will need the Chrome browser. I don’t yet see similar support for Firefox, and I’m not sure if that is on the roadmap.
3 Coordinates of Mock Location
To override the actual location of your browser, you’ll need to supply the longitude and latitude of the mock location. To find this info, you can use Google Maps.
Notice the latitude and longitude in the URL. The first number is the latitude (30.3079823) and the second number is the longitude (-97.893803).
Instructions
1 Create an instance of ChromeDriver
I usually create my instance as WebDriver driver = new ChromeDriver(); however, in doing this, my object’s type is WebDriver and not ChromeDriver, which means my object does not have access to the methods that are specific to ChromeDriver. So, in order to use the CDP methods, I have to declare my driver as ChromeDriver.
1 |
ChromeDriver driver = new ChromeDriver(); |
2 Invoke executeCdpCommand method
Selenium 4 introduces executeCdpCommand as a new method in the ChromeDriver class. This method takes the command name, and a Map of parameters. To find the exact command to use, I consulted the DevTools Protocol website and searched for geolocation.
I see two setGeolocationOverride commands here. I clicked on the one for Page and it was deprecated, so I knew to use the Emulation one. I copied this entire String as the command.
Now, I need the parameters for the executeCdpCommand method. I clicked on the Emulation.setGeolocationOverride method on the Chrome DevTools Protocol website to get more info.
Given this, I can see that I need to add three entries to my Map: the latitude, the longitude, and the accuracy.
1 2 3 4 5 |
Map coordinates = Map.of( "latitude", 30.3079823, "longitude", -97.893803, "accuracy", 1 ); |
Confession: I have no idea what the range is for accuracy, but when I use 0 it does not work and when I use 1 or anything greater, it does. 🤷🏽♀️
Now that I have the command and the parameters, I can finally call the executeCdpCommand method.
1 |
driver.executeCdpCommand("Emulation.setGeolocationOverride", coordinates); |
After this, be sure to refresh your page, or navigate to the page you’d like to go to.
1 2 3 4 5 |
//Refresh if already on the page driver.navigate().refresh(); //OR navigate to new URL driver.navigate().to("https://oldnavy.gap.com/stores"); |
Where is this Useful?
This new feature empowers us to test application features that are dependent on the user’s geolocation. For example, if I go to Old Navy’s store locator, it will detect my geolocation and show me stores near me.
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 |
package geolocation; import base.BaseTests; import org.junit.jupiter.api.Test; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertTrue; public class LocationTests extends BaseTests { @Test public void goShoppingInAustin(){ Map coordinates = Map.of( "latitude", 30.3079823, "longitude", -97.893803, "accuracy", 1 ); driver.executeCdpCommand("Emulation.setGeolocationOverride", coordinates); driver.navigate().to("https://oldnavy.gap.com/stores"); var addresses = driver.findElementsByClassName("address"); assertTrue(addresses.size() > 0, "No addresses found"); assertTrue(addresses. stream() .allMatch(a -> a.getText().contains(", TX ")), "Some addresses listed are not in Texas"); } } |
Colum Wilde
This is cool. Can we mock the timezone the same way chrome dev tools allows us to mock it using Sensors?
Nitesh Rajgopal
Hi Angie. Thank you for this really helpful recipe. I love your work. I’ve used your example and adapted it accordingly to work in C#. Geolocation is working as expected, but I cannot find any documentation or examples for setting timezones using the C# libraries. I cannot find any method for SetTimezoneOverride. Please advise me.
Nitesh Rajgopal
Literally 5 minutes after posting the question here, I realized the issue. I was using an older beta version of the npm package. I upgraded to the latest alpha version and I am now able to set the timezone as well. My code is similar to the samples here:https://www.selenium.dev/documentation/en/support_packages/chrome_devtools/