Slowing Down Test Execution in Selenium

Running automated tests against a web application using Selenium you can sometimes hide issues both in the application itself and in your implementation of the automation if you always rely on the browser and the web driver running at their peak performance on the test machine.

The chrome browser has a nice feature built into it so that it can simulate different network speeds. You can, for instance, go from a spiffy wifi throughput to a 2g experience to simulate a web page loading on a mobile with a bad signal.

This feature is also available from the automation side of things when you are using the chrome webdriver.

Code

I setup a class to take a text description of the network quality, perhaps from a config file, and convert it to a set of network characteristics matching that network behaviour - network latency, download and upload speed.

Throttling.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// Simulation of slower networks in selenium. 
/// </summary>
public class Throttling
{
    /// <summary>
    /// Load a set of network throttling characteristics based on a network name.
    /// Unknown networks or blank returns a default "off" setting.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public static Throttling FromPreset(string name)
    {
        if (!String.IsNullOrEmpty(name))
        {
            string key = name.ToLower();

            if (Presets.ContainsKey(key))
                return Presets[key];
        }

        // turned off
        return new Throttling { Enabled = false };
    }

    private static int KilobitPerSecond = 1000;
    private static int MegabitPerSecond = 1000 * KilobitPerSecond;

    // Figures taken from https://helpdeskgeek.com/networking/simulate-slow-internet-connection-testing/
    private static readonly Dictionary<string, Throttling> Presets = new Dictionary<string, Throttling>
    {
        { "gprs",   new Throttling { Latency = TimeSpan.FromMilliseconds(500),  Download =  50 * KilobitPerSecond,       Upload =  20 * KilobitPerSecond } },
        { "2g",     new Throttling { Latency = TimeSpan.FromMilliseconds(300),  Download = 250 * KilobitPerSecond,       Upload =  50 * KilobitPerSecond } },
        { "good2g", new Throttling { Latency = TimeSpan.FromMilliseconds(150),  Download = 450 * KilobitPerSecond,       Upload = 150 * KilobitPerSecond } },
        { "3g",     new Throttling { Latency = TimeSpan.FromMilliseconds(100),  Download = 750 * KilobitPerSecond,       Upload = 250 * KilobitPerSecond } },
        { "good3g", new Throttling { Latency = TimeSpan.FromMilliseconds(40),   Download = (long)1.5 * MegabitPerSecond, Upload = 750 * KilobitPerSecond } },
        { "4g",     new Throttling { Latency = TimeSpan.FromMilliseconds(20),   Download =  4 * MegabitPerSecond,        Upload =  3 * MegabitPerSecond } },
        { "dsl",    new Throttling { Latency = TimeSpan.FromMilliseconds(5),    Download =  2 * MegabitPerSecond,        Upload =  1 * MegabitPerSecond } },
        { "wifi",   new Throttling { Latency = TimeSpan.FromMilliseconds(2),    Download = 30 * MegabitPerSecond,        Upload = 15 * MegabitPerSecond } },
    };

    public Throttling()
    {
        this.Enabled = true;
        this.Latency = TimeSpan.Zero;
        this.Download = -1L;
        this.Upload = -1L;
    }

    public bool Enabled { get; private set; }

    public TimeSpan Latency { get; private set; }

    public long Download { get; private set; }

    public long Upload { get; private set; }
}

As part of the instantiation of the web driver we can inspect the throttling characteristics we have just built and apply them to the chrome driver via the NetworkConditions property.

WebDriverFactory.cs


ChromeOptions options = new ChromeOptions();

if (openBrowserDebugWindow)
{
    // https://peter.sh/experiments/chromium-command-line-switches/
    options.AddArgument("--auto-open-devtools-for-tabs");
}

var driver = new ChromeDriver(pathToWebDriver, options);

if (!String.IsNullOrEmpty(networkSpeed))
{
    var throttling = Throttling.FromPreset(networkSpeed);

    if (throttling.Enabled)
    {
        driver.NetworkConditions = new ChromeNetworkConditions
        {
            Latency = throttling.Latency,
            DownloadThroughput = throttling.Download,
            UploadThroughput = throttling.Upload
        };
    }
}

The differences in performance of the browser can be quite marked when going below anything but "wifi", mostly because in a desktop environment we are mostly used to the luxury of super fast internet. Some pages can be super annoying to wait for them to finish but it is a good thing to be brought back to how some of our customers must experiencce our applications in the wild.

Be prepared also for what breaks in the automation scripts where a thread sleeping for a number of seconds is suddenly no longer adequate and a better solution, perhaps waiting on a piece of data in the page to appear, beomes necessary. These kinds of sleeps injected (seemingly at random) into the automation code seem fine at the time but are nearly always a bad idea because of how much flakiness they create in the automation while simultaneously giving the opposite impression while everything is working at top speed.

A more robust method of determining a page is in the right state before progressing is always better and pays off more in the long run when we want this kind of automation to be as reliable as possible so that it "just runs" and if we find a failure we can be assured that there is a legitimate breakage or regression in the application rather than a hit-and-miss automation problem with a slightly slow connection.