Network throttling with chrome and selenium
Asked Answered
L

10

50

Google Chrome 38 introduced the new "Device Mode & Mobile Emulation" functionality in devtools. In addition to choosing a device for emulation, it is also possible to emulate different network conditions:

Optimizing your site's performance under varying network conditions is a key aspect of developing for a mobile audience.

Device mode's network conditioning allows you to test your site on a variety of network connections, including Edge, 3G, and even offline. Select a connection from the preset dropdown to apply network throttling and latency manipulation.

For example, we can set it to be like in good old days - GPRS 50 Kbps:

enter image description here

Now we have a good use case for it - we have an internal application for network speed testing. And this new emulation functionality is very helpful for manual testing. But, we'd like to automate it.

Question is:

Is it possible to start chrome via selenium with specified network conditions? Is it something that can be controlled through chrome preferences or command-line arguments?


There are certainly multiple options to simulate slow internet connection, but the question is specifically about chrome+selenium.

Landloper answered 10/1, 2015 at 21:38 Comment(0)
B
53

The API to control network emulation were added to ChromeDriver. And should be available for quite a while now. According to comment in the linked issue you should use version at least 2.26 because of some bugfix.

According to Selenium changelog bindings are available for these languages:

  • JavaScript as of version 3.4.0 (commit)
  • Python as of version 3.5.0 (commit)
  • Ruby as of version 3.11.0 (commit)
  • C# as of version 4 (commit)

If you need these binding in other languages you should probably open issue/contribute implementation similar to one of the above.

Example usage from Python is below:

driver.set_network_conditions(
    offline=False,
    latency=5,  # additional latency (ms)
    download_throughput=500 * 1024,  # maximal throughput
    upload_throughput=500 * 1024)  # maximal throughput
Bucephalus answered 10/10, 2017 at 17:40 Comment(9)
Is download_throughput & upload_throughput in bytes per second? So the examples roughly 5MB/s?Mumford
@Mumford In Chrome Dev Tools it says kb/s. My assumption is that it is the same when using API. But I haven't tested myself. Please edit the answer if/when you figure it out.Bucephalus
It's weird. If I use dev tools to toggle it on and put in like 5 * 1024 and test at speedtest.xfinity.com (Easy to find start button) I get 5 mbps. But if I do the same in a Selenium script, 5 * 1024 it basically doesn't register. To get around 5 mbps I need to do something around 5 * 30000 to get something that tops out around 5 mbps (on a 300 mbps+ if I don't throttle in the script so not internet). Maybe a bug though as that doesn't correspond well to any conversion I can think of.Mumford
Here's a link to the JS code: github.com/SeleniumHQ/selenium/blob/…Gradeigh
According to the comments in the ChromeDriver code here, it appears then when you are overriding the network conditions you are providing the throughput speeds in bps, even though the presets are listed in kbps.Ferrin
Note that it does not yet affect websocket connections, see crbug.com/423246Mcadams
Thanks @YaroslavAdmin it really helped!!Lorgnon
From what I am seeing it appears the input to download_throughput is measured in Bytes per second. Not bits. I may be crazy, but that's how the numbers seem to be working out. So if you want 500 kbps: download_throughput=500 / 8 * 1024, Let me know if anyone else is seeing the same. Kind of hard to measure definitively.Lusatian
That's super useful, thanks a lot @YaroslavAdmin! Testing scripts -- and dealing with the edge cases that throttling reveals -- definitely helps make those scripts more robust. Cheers!Enface
S
16

No, it is not possible to control Network Connectivity Emulation through Chrome preferences or command-line arguments. Network Connectivity Emulation is part of the build-in Chrome debugger. One way way in solving this is to control the debugger. This can be done via an extension or by directly controlling the debugger, see explanation. However, this will not work with WebDriver. The reason for this is that there can only be one "debug" session and WebDriver is already using it, see explanation. Since there is no public interface, there is also no way to control it via WebDriver.

For Device Mode & Mobile Emulation which is also part of the build-in debugger, there is a public interface (details), and thus can be controlled. This can be done through WebDriver Capabilities. Two options 1) Specify a device name 2) Enter your own parameters (limited).

Smorgasbord answered 24/1, 2015 at 2:20 Comment(1)
You may want to remove this answer, as this is now possible via Selenium.Burdett
M
8

You can use this method to run your test case in specified network conditions

protected void networkThrotting() throws IOException {
  Map map = new HashMap();
  map.put("offline", false);
  map.put("latency", 5);
  map.put("download_throughput", 500);
  map.put("upload_throughput", 1024);


  CommandExecutor executor = ((ChromeDriver)driver).getCommandExecutor();
  Response response = executor.execute(
        new Command(((ChromeDriver)driver).getSessionId(),    "setNetworkConditions", ImmutableMap.of("network_conditions", ImmutableMap.copyOf(map)))
  );
}
Mohave answered 10/6, 2019 at 12:7 Comment(1)
Was anyone able to use this? When I try to use this I am getting org.openqa.selenium.UnsupportedCommandException: setNetworkConditions exception. I have tried changing it to setNetworkConnection, but that does not have any impact in the network speed!Swingle
R
5

While this is a very welcome and useful bit of functionality, for serious testing I think the conventional methods of network simulation are still the way to go.

I am aware of 2 solutions in addition to those already linked - the Charles web proxy (very useful tool - commercial) and implementing your own recipe using Linux Traffic Control (e.g. see chapter 6 of LAMPe2e).

By interfering with the network connections rather than the browser, you then get a proper measure of the impact independently of the browser in use.

Why do you just want to use the Chrome functionality?

Revisory answered 24/1, 2015 at 23:31 Comment(0)
P
5

Indeed C# Selenium latest (3.11) has NetworkConditions added. Now you can use it like this:

     var driver = new ChromeDriver(pathToDriver);
     driver.NetworkConditions = new ChromeNetworkConditions()
     {  DownloadThroughput = 5000, UploadThroughput = 5000, Latency = TimeSpan.FromMilliseconds(5) };

The problem is it's not yet usable because of the bug

https://github.com/SeleniumHQ/selenium/issues/5693

So .Net guys will have to wait until 3.12 Selenium Release.

Perigordian answered 26/3, 2018 at 19:52 Comment(0)
X
4

Let's consider two different approaches,

one where we can throttle the entire network and one where we can specify which network requests to throttle specifically.

Approach 1: throttle the entire network

const { Builder } = require("selenium-webdriver")

async function throttleNetwork() {
  let driver = await new Builder().forBrowser("chrome").build();

  await driver.setNetworkConditions({
    offline: false,
    latency: 5000, // Additional latency (ms).
    download_throughput: 50 * 1024, // Maximal aggregated download throughput.
    upload_throughput: 50 * 1024, // Maximal aggregated upload throughput.
  });

  driver.get("http://www.google.com/");
}

thanks to Yaroslav for pointing out the commit.

This has a downside where we can't specify a specific network request to throttle and the rest to go unthrottled.

Let's fix this downside in our next approach.

Approach 2: throttle a specific network request

Here we'd be using an npm package from requestly called Requestly for Selenium.

We need to create a rule first in their client application and get the link by creating a shared list.

For example, let's throttle network request to google.com

require("chromedriver");
const { Builder } = require("selenium-webdriver");
const chrome = require("selenium-webdriver/chrome");
const {
  getRequestlyExtension,
  importRequestlySharedList,
} = require("@requestly/selenium");

const sharedListUrl = "YOUR_SHARED_LIST_LINK_HERE" // For example, use "https://app.requestly.io/rules/#sharedList/1631611216670-delay"

async function throttleGoogle() {
  const options = new chrome.Options().addExtensions(
    getRequestlyExtension("chrome") // This installs requestly chrome extension in your testing instance
  );

  const driver = new Builder()
    .forBrowser("chrome")
    .setChromeOptions(options)
    .build();

  await importRequestlySharedList(driver, sharedListUrl); // Here we import the shared list we created some time back
  driver.get("http://www.google.com/");
}

This was a high-level overview of how we can overcome the downsides of the selenium-only approach. I've written a blog on the same where I go into depth on how to create a rule, shared list, and so on. You can read it here.

Xymenes answered 30/9, 2021 at 7:22 Comment(0)
F
3

The below issue has now been fixed in this commit

For anyone like me in the C# world wondering why the upload/download throughput does not work as expected, it seems the tooltips for these properties are mislabelled. The tooltip states the data rate is measured in kb/s but in my own experience it is actually bytes per second so if you want to use a more familiar measurement like Mbps you will have to multiply by 125,000:

int latencyInMilliseconds = 20;
long downloadLimitMbps = 20;
long uploadLimitMbps = 5;
_driver.NetworkConditions = new ChromeNetworkConditions()
{
    Latency = new TimeSpan(0, 0, 0, 0, latencyInMilliseconds),
    DownloadThroughput = downloadLimitMbps * 125000, // Mbps to bytes per second
    UploadThroughput = uploadLimitMbps * 125000, // Mbps to bytes per second
    IsOffline = false,
};

Using these settings and looking at network traffic while my tests are running I can see they result in exactly 20Mbps down and 5Mbps up.

Faints answered 10/5, 2021 at 16:9 Comment(0)
L
2

It looks like it's coming soon to Selenium (C#). The commit was on 01/28/2018:

https://github.com/SeleniumHQ/selenium/blob/ef156067a583fe84b66ec338d969aeff6504595d/dotnet/src/webdriver/Chrome/ChromeNetworkConditions.cs

Lipocaic answered 30/1, 2018 at 18:7 Comment(0)
Q
2

I know this is an old question, but I recently had to solve for this problem and this page came up at the top of my Google search. Here are the main bits from how I did it in C#. Hope this helps someone in the future.

var networkConditions = new ChromeNetworkConditions();
networkConditions.Latency = new TimeSpan(150);
networkConditions.IsOffline = false;
networkConditions.DownloadThroughput = 120 * 1024;
networkConditions.UploadThroughput = 150 * 1024;
Driver.NetworkConditions = networkConditions;
Quirinal answered 17/6, 2020 at 14:57 Comment(0)
T
2

Inspired by the answer from TridentTrue, here is an updated version for Selenium 4.0.0 in C#. If anyone knows how to use it for alpha7 and upwards without beeing version specific feel free to update this. :)

public void LimitNetwork(int latencyInMilliseconds, long downloadLimitMbps, long uploadLimitMbps)
{
    IDevTools devTools = driver as IDevTools;
    session = devTools.CreateDevToolsSession();
    session.Network.Enable(new EnableCommandSettings());

    EmulateNetworkConditionsCommandSettings command = new EmulateNetworkConditionsCommandSettings();

    command.Latency = latencyInMilliseconds;
    command.DownloadThroughput = downloadLimitMbps * 125000; // Mbps to bytes per second
    command.UploadThroughput = uploadLimitMbps * 125000; // Mbps to bytes per second
    command.Offline = false;

    session.Network.EmulateNetworkConditions(command);
}

Update: After I had implemented this for my own, I found a really good article to get an overview in Selenium 4.0, also in Emulating network conditions.

Update 2: My issue was that I forgot to add the Network.Enable command, so don't forget to call it before you do the other stuff. I have updated the code. :)

Tuber answered 9/2, 2022 at 13:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.