Test automation using Selenium, BrowserStack, and GitHub

A complete walkthrough for automating browser tests with Selenium and Python, running them on BrowserStack’s device grid, and wiring everything up with GitHub Actions CI.
Programming
Author

Souvik Sarkar

Published

October 24, 2022

Context

Challenges in QA automation

Automated testing of modern websites and mobile applications poses the following primary challenges:

  • The tests must run on numerous combinations of devices and browsers in parallel to speed up the process
  • The tests must be triggered for each new build of the application, or for each new code submission by developers
  • Logging and observability of test runs must be transparent, and the test results accessible from a single platform

BrowserStack’s offerings

BrowserStack solves these problems by offering the following:

  • A large collection of devices and browser versions on which you can run your tests
  • Support for almost all common programming languages and testing frameworks
  • Easy integration of large test suites with the BrowserStack platform
  • Comprehensive and detailed reports and logs for each test session in a single dashboard
  • Support for automated testing pipelines for all common CI/CD technologies
  • Intuitive management of users, permissions, and large scale testing infrastructure
  • Detailed documentation and support for everything you can do with BrowserStack
  • Transparent and reasonable pricing for individual users, small teams, and enterprises

Objectives

This tutorial helps you familiarize with BrowserStack’s capabilities, so that you can easily adopt BrowserStack for testing websites and mobile applications. In particular, you will learn about the following:

  • Creating and running a test automation script using Python and Selenium on your local machine. The script automatically tests signing in to Amazon’s website.
  • Adapting the script to use BrowserStack’s capabilities, and running tests remotely on BrowserStack.
  • Automating the running of tests using GitHub Actions for each modified version of the script.

Audience

The ideal audience for this tutorial are professionals with interest or experience in automated testing of websites and mobile applications.

Warning

The code samples used in this tutorial are for demonstration only; DO NOT use them in production scenarios.

Prerequisites

Before starting with test automation, ensure the following:

  • Git is installed in your local machine. You can download it from the git-scm website.
  • You are familiar with Python and Selenium for automated tests.
  • You have an active GitHub account. If not, sign up for an account.
  • You have a basic idea about Continuous Integration (CI) pipelines.

Testing on a local machine

Before running a script on BrowserStack’s grid, create and test the simpler version of the script on your local machine.

Note

All command examples and code snippets included in this tutorial have been tested on a local machine running the Fedora 35 operating system. Whenever necessary, modify the commands and code snippets according to your machine’s operating system and package manager.

Installing dependencies on the local machine

Procedure

  1. Write the following script in a file set_up.sh to create a virtual environment and install dependencies.

    cd browserstack-assignment/
    python -m venv browserstack
    source browserstack/bin/activate
    python -m pip install selenium==4.1.0
    python -m pip install python-dotenv
  2. Run the set_up.sh script file.

    $ bash set_up.sh
  3. Check the version of Google Chrome on your machine by running chrome://version/ on the browser’s search bar. Note the version, such as Google Chrome: 104.0.5112.79 (Official Build) (64-bit).

  4. Check the version of any chromedriver package installed on your system.

    $ chromedriver --version
    ChromeDriver 96.0.4664.45 (76e4c1bb2ab4671b8beba3444e61c0f17584b2fc-refs/branch-heads/4664@{#947})
  5. If the version of the chromedriver package is older than the Google Chrome version, remove the chromedriver package.

    $ which chromedriver
    ~/bin/chromedriver
    
    $ rm ~/bin/chromedriver
  6. Install the chromedriver package that matches the Google Chrome version.

    • Download the correct version for your system from the Chromium website.
    • Unzip the downloaded file and navigate to the resulting directory.
    • Copy the chromedriver binary to any location supported by your $PATH variable.

Locally running a test script

  1. Create a .env file and save your Amazon sign-in credentials in the file.

    AMAZON_EMAIL="<email_registered_with_amazon>"
    AMAZON_PASSWORD="<password_for_amazon_account>"
    Tip

    You can safely use the .env file for storing Amazon sign-in credentials while experimenting and developing the scripts. The .gitignore file has an entry for the .env file to prevent any accidental check-ins.

  2. Create a file local_script.py.

    import os, time
    from selenium.webdriver import Chrome
    from selenium.webdriver.common.by import By
    from dotenv import load_dotenv
    
    def slow_typing(element, text):
        for character in text:
            element.send_keys(character)
            time.sleep(0.3)
    
    AMZ_URL = "https://amazon.in/"
    load_dotenv()
    AMAZON_EMAIL = os.environ.get("AMAZON_EMAIL")
    AMAZON_PASSWORD = os.environ.get("AMAZON_PASSWORD")
    
    browser = Chrome()
    browser.get(AMZ_URL)
    time.sleep(2)
    sign_in_button = browser.find_element(By.ID, "nav-link-accountList")
    sign_in_button.click()
    time.sleep(2)
    
    username_textbox = browser.find_element(By.ID, "ap_email")
    slow_typing(username_textbox, AMAZON_EMAIL)
    time.sleep(2)
    
    continue_button = browser.find_element(By.ID, "continue")
    continue_button.submit()
    time.sleep(2)
    
    password_textbox = browser.find_element(By.ID, "ap_password")
    slow_typing(password_textbox, AMAZON_PASSWORD)
    time.sleep(2)
    
    sign_in_button = browser.find_element(By.ID, "auth-signin-button-announce")
    sign_in_button.submit()
    time.sleep(5)
    
    browser.close()
  3. Run the file local_script.py.

    $ python local_script.py

Integrating the script with BrowserStack

After successfully testing the script on your local machine, modify and integrate the script with BrowserStack.

Getting BrowserStack secrets

  1. Sign up for a trial account of BrowserStack.

  2. Navigate to your BrowserStack dashboard.

  3. From the ACCESS KEY dropdown menu, note the values of the User Name and Access Key fields.

  4. In the .env file, add the BrowserStack secrets below the Amazon account credentials and save it.

    BROWSERSTACK_USERNAME="<your_browserstack_username>"
    BROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>"

Modifying the test script

Modify the script to use BrowserStack’s capabilities of running parallel tests on numerous device and browser combinations.

The entire modified script browserstack_script.py:

import os, time
from dotenv import load_dotenv
from selenium import webdriver
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.webdriver.common.by import By
from threading import Thread

load_dotenv()

BUILD_NAME = "browserstack-build-amazon-sign-in"

capabilities = [
    {
        "browserName": "chrome",
        "browserVersion": "103.0",
        "os": "Windows",
        "osVersion": "11",
        "sessionName": "Parallel Test Chrome Windows",
        "buildName": BUILD_NAME
    },
    {
        "browserName": "firefox",
        "browserVersion": "102.0",
        "os": "Windows",
        "osVersion": "10",
        "sessionName": "Parallel Test Firefox Windows",
        "buildName": BUILD_NAME
    },
]

def get_browser_option(browser):
    switcher = {
        "chrome": ChromeOptions(),
        "firefox": FirefoxOptions(),
    }
    return switcher.get(browser, ChromeOptions())

def run_session(cap, AMZ_URL="https://amazon.in/"):
    cap["userName"] = os.environ.get("BROWSERSTACK_USERNAME")
    cap["accessKey"] = os.environ.get("BROWSERSTACK_ACCESS_KEY")
    options = get_browser_option(cap["browserName"].lower())
    options.set_capability("browserName", cap["browserName"].lower())
    options.set_capability("bstack:options", cap)
    driver = webdriver.Remote(
        command_executor="https://hub.browserstack.com/wd/hub", options=options
    )
    driver.get(AMZ_URL)
    sign_in_button = driver.find_element(By.ID, "nav-link-accountList")
    sign_in_button.click()
    time.sleep(2)
    AMAZON_EMAIL = os.environ.get("AMAZON_EMAIL")
    AMAZON_PASSWORD = os.environ.get("AMAZON_PASSWORD")
    username_textbox = driver.find_element(By.ID, "ap_email")
    username_textbox.send_keys(AMAZON_EMAIL)
    time.sleep(2)
    continue_button = driver.find_element(By.ID, "continue")
    continue_button.submit()
    time.sleep(2)
    password_textbox = driver.find_element(By.ID, "ap_password")
    password_textbox.send_keys(AMAZON_PASSWORD)
    time.sleep(2)
    sign_in_button = driver.find_element(By.ID, "auth-signin-button-announce")
    sign_in_button.submit()
    time.sleep(2)
    print("Sign in test complete.")
    driver.quit()

for cap in capabilities:
    Thread(target=run_session, args=(cap,)).start()

Running the modified script on BrowserStack

$ python browserstack_script.py

Observing test results in BrowserStack dashboard

  1. In your BrowserStack dashboard, select the build from the All Builds drop-down list on the left navigation pane.
  2. Check the status of the sessions for the selected build.

BrowserStack Dashboard

Automatically running the modified script using GitHub Actions

Using GitHub Actions, set up a CI pipeline such that each push or pull request to the project’s GitHub repository triggers the tests to run on BrowserStack.

  1. Create a .gitignore file to prevent secrets from being pushed to GitHub:

    $ echo ".env" >> .gitignore
  2. Create a GitHub repository named browserstack_automation for the project and push the local project to the remote repository.

    $ git init
    $ git add --all
    $ git commit -m "first commit"
    $ git branch -M main
    $ git remote add origin git@github.com:<username>/browserstack_automation.git
    $ git push -u origin main
  3. In your repository on GitHub, navigate to SettingsSecretsActionsNew repository secret.

  4. Add your BrowserStack secrets:

    • Name: BROWSERSTACK_USERNAME, Value: <your_browserstack_username>
    • Name: BROWSERSTACK_ACCESS_KEY, Value: <your_browserstack_access_key>
  5. Create .github/workflows/browserstack_actions.yml:

    name: 'BrowserStack GH Actions Test'
    on: [push, pull_request]
    jobs:
      ubuntu-job:
        name: 'BrowserStack Test on Ubuntu'
        runs-on: ubuntu-latest
        steps:
          - name: 'BrowserStack Env Setup'
            uses: browserstack/github-actions/setup-env@master
            with:
              username:  ${{ secrets.BROWSERSTACK_USERNAME }}
              access-key: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
          - name: 'BrowserStack Local Tunnel Setup'
            uses: browserstack/github-actions/setup-local@master
            with:
              local-testing: start
              local-identifier: random
          - name: 'Checkout the repository'
            uses: actions/checkout@v2
          - name: 'Setting up the runner'
            run: bash set_up.sh
          - name: 'Running test on BrowserStack'
            run: python3 browserstack_script.py
          - name: 'BrowserStackLocal Stop'
            uses: browserstack/github-actions/setup-local@master
            with:
              local-testing: stop
  6. To test the GitHub Actions workflow, make a minor modification in the project and push the changes to GitHub.

    $ git add <modified_file>
    $ git commit -m "Testing GitHub Actions"
    $ git push
  7. In your GitHub repository, navigate to Actions<your_GitHub_Actions_job> and observe the job logs.

    Warning

    One common reason for failure of the browserstack_actions.yml workflow is the error: ModuleNotFoundError: No module named 'dotenv'.

    Dotenv error in GitHub Actions

    The failure happens due to a known bug. It is not easily reproducible and currently has no universally applicable solution.

  8. In your BrowserStack dashboard, select the GitHub Actions build from the All Builds drop-down list and observe the test status.


Note

A modified and hopefully better version of this project is available at https://github.com/sounix000/browserstack-qa-automation.