Skip to main content

Make Selenium Tests Run Faster

Learn how to speed up your slow-performing Selenium tests.

Issue

Tests running on BrowserStack Automate slows down with the error as shown in the following image:

keep-alive missing issue in Automate

Cause

The absence of the keep-alive parameter leads to slow-performing tests. When you don’t use this parameter, your client binding is using a new request every time you communicate with BrowserStack.

Why you must mitigate this issue

As an organization, optimizing your builds to run faster is crucial. BrowserStack understands the need to identify issues that might not be evident, but have a large impact on the speed and stability of your test sessions.

Use the resolutions provided to mitigate these issues so as to:

  • Improve performance
  • Reduce test flakiness
Warning: Not using the HTTP keep-alive connection degrades your test performance approximately 2-10 times.

Resolution/Workaround

Since keep-alive is an HTTP connection parameter, specifying it as a capability in the test script does not work. You need to specify this parameter at the Selenium Webdriver’s level so that the client binding uses the same connection for every request, which eventually speeds up your tests.

Use the following information to enable the keep-alive parameter in your test script:

In your test script, when initializing the driver, use the keep_alive parameter and set it to True, as shown in the following code snippet.:

driver = webdriver.Remote(
    command_executor='https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub',
    desired_capabilities=desired_cap, keep_alive=True)

Sample test script

Here is a sample test script that uses the keep_alive parameter to perform a test case:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
desired_cap = {
 'browserName': 'iPhone',
 'device': 'iPhone 12 Pro Max',
 'realMobile': 'true',
 'os_version': '14',
 'name': 'BStack-[Python] Sample Test', # test name
 'build': 'BStack Sample Build' # CI/CD job or build name
}
driver = webdriver.Remote(
    command_executor='https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub',
    desired_capabilities=desired_cap, keep_alive=True)

driver.get("https://bstackdemo.com/")
try:
    WebDriverWait(driver, 5).until(EC.title_contains("StackDemo"))
    # Setting the status of test as 'passed' or 'failed' based on the condition; if title of the web page starts with 'StackDemo'
    driver.execute_script('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed", "reason": "Title contains StackDemo!"}}')
except TimeoutException:
    driver.execute_script('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed", "reason": "​​Title does not contain StackDemo."}}')
driver.quit()

In your Node.js project or any other Node.js based framework’s project such as WebdriverIO, NightwatchJS, etc., do the following:

Step 1: Create a file named fast-selenium.js in the folder where your test script file is located.

Step 2: Add the following code to the fast-selenium.js file

var http = require('http'),
    https = require('https');

//set the time (in seconds) for connection to be alive
var keepAliveTimeout = 30*1000;

if(http.globalAgent && http.globalAgent.hasOwnProperty('keepAlive')) {
    http.globalAgent.keepAlive = true;
    https.globalAgent.keepAlive = true;
    http.globalAgent.keepAliveMsecs = keepAliveTimeout;
    https.globalAgent.keepAliveMsecs = keepAliveTimeout;
} else {
    var agent = new http.Agent({
        keepAlive: true,
        keepAliveMsecs: keepAliveTimeout
    });

    var secureAgent = new https.Agent({
        keepAlive: true,
        keepAliveMsecs: keepAliveTimeout
    });

    var httpRequest = http.request;
    var httpsRequest = https.request;

    http.request = function(options, callback){
        if(options.protocol == "https:"){
            options["agent"] = secureAgent;
            return httpsRequest(options, callback);
        }
        else {
            options["agent"] = agent;
            return httpRequest(options, callback);
        }
    };
}

Step 3: Edit your existing test script to add the following require statement that imports the fast-selenium.js file:

require('./fast-selenium.js');

Sample test script

Here is a sample test script that uses the fast-selenium.js file to perform a test case:

require('./fast-selenium.js'); // imports the fast-selenium script

const webdriver = require('selenium-webdriver');
// Input capabilities
const capabilities = {
 'device' : 'Samsung Galaxy S21 Plus',
 'realMobile' : 'true',
 'os_version' : '11.0',
 'browserName' : 'Android',
 'name': 'BStack-[NodeJS] Sample Test', // test name
 'build': 'BStack Sample Build' // CI/CD job or build name
}
async function runTestWithCaps () {
  let driver = new webdriver.Builder()
    .usingServer('https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub')
    .withCapabilities(capabilities)
    .build();
  await driver.get("https://bstackdemo.com/");

  try {
    await driver.wait(webdriver.until.titleMatches(/StackDemo/i), 5000);
    await driver.executeScript(
      'browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed","reason": "Title matches to StackDemo!"}}'
    );
  } catch (e) {
    await driver.executeScript(
      'browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed","reason": "​​Title does not match to StackDemo"}}'
    );
  }
  await driver.quit();
}
runTestWithCaps();

Step 1: In your Ruby project, create a file named fast-selenium.rb in the folder where you test script file is located.

Step 2: Add the following code to the fast-selenium.rb file:

require 'selenium/webdriver/remote/http/curb'

module Selenium
  module WebDriver
    module Remote
      class Bridge
        attr_accessor :http_curb
        def http
          unless @http_curb
            @http_curb = Http::Curb.new
            @http_curb.server_url = @http.send(:server_url)
          end
          @http_curb
        end
      end # Bridge
    end # Remote
  end # WebDriver
end # Selenium

Step 3: Edit your existing test script to add the following require statement that imports the fast-selenium.rb file:

require './fast-selenium'

Sample test script

Here is a sample test script that uses the fast-selenium.rb file to perform a test case:

require 'rubygems'
require 'selenium-webdriver'
require './fast-selenium'

# Input capabilities
caps = Selenium::WebDriver::Remote::Capabilities.new
caps['device'] = 'iPhone 12 Pro Max'
caps['realMobile'] = 'true'
caps['os_version'] = '14'
caps['javascriptEnabled'] = 'true'
caps['name'] = 'BStack-[Ruby] Sample Test' # test name
caps['build'] = 'BStack Sample Build' # CI/CD job or build name
driver = Selenium::WebDriver.for(:remote,
  :url => "https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub",
  :desired_capabilities => caps)

# Opening demo website
driver.navigate.to "https://bstackdemo.com/"
wait = Selenium::WebDriver::Wait.new(:timeout => 5) # seconds
begin
  wait.until { !driver.title.match(/StackDemo/i).nil? }
  driver.execute_script('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed", "reason": "Title matches to StackDemo!"}}')
rescue
  driver.execute_script('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed", "reason": "Title does not matches to StackDemo"}}')
end
driver.quit

The keep-alive parameter is enabled by default on most client binding versions of Java and C#. If you’re using one of these languages and still encounter the error, update your client binding to the latest version.

Reach out to Support if you encounter the error even after updating the client binding version.

Verify resolution of error

Use the information in the following tabs to verify whether this error is resolved.

  1. Go to your Automate dashboard, navigate to your session, and click the Issues Detected tab.
  2. Check if the HTTP keep-alive missing error appears on the tab. Assume the error as resolved if no error is seen.
  1. Go to your Automate dashboard, navigate to your session, and click the Other Logs tab.
  2. Click View Raw Selenium Logs. A new tab opens that displays the Selenium logs of your test session.
  3. Search for x-connid in the logs and check whether the value of x-connid is the same for every request.

If the value of every instance of the x-connid parameter is the same then the error has been resolved. Same value of x-connid denotes that your client binding is using the same connection for every request.

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked






Thank you for your valuable feedback

Is this page helping you?

Yes
No

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked






Thank you for your valuable feedback!

Talk to an Expert
Download Copy