Selenium for second-screen login flows#

You can use Selenium to automate browser-based user journeys on a second screen, from the same Stb-tester Python script that is automating the big screen journey. For example, many TV apps use a browser-based login flow, where the TV screen shows a code that you type into a browser on your phone or computer.

Recipe#

Create a config/setup/setup script to install Selenium and a browser (Chromium):

#!/bin/bash -ex

# Install Chromium and Selenium — see https://stb-tester.com/manual/selenium
sudo apt-get update
mkdir -p /tmp/chromium
cd /tmp/chromium
curl --fail \
  -O https://deb.debian.org/debian/pool/main/c/chromium/chromium_120.0.6099.224-1~deb11u1_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/c/chromium/chromium-common_120.0.6099.224-1~deb11u1_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/c/chromium/chromium-driver_120.0.6099.224-1~deb11u1_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/libj/libjpeg-turbo/libjpeg62-turbo_2.0.6-4_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/libj/libjsoncpp/libjsoncpp24_1.9.4-4_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/libw/libwebp/libwebp6_0.6.1-2.1%2Bdeb11u2_arm64.deb
ls -l
sudo apt-get install -y ./*.deb
cd -
rm -rf /tmp/chromium
sudo pip3 install selenium==4.31.0

From your Python tests, use Selenium WebDriver like this:

import selenium.webdriver
from selenium.webdriver.chromium.service import ChromiumService

options = selenium.webdriver.ChromeOptions()
options.add_argument("--headless=new")
service = ChromiumService("/usr/bin/chromedriver")
webdriver = selenium.webdriver.Chrome(options=options, service=service)
webdriver.get("https://example.com")

Demo#

In this short demo we sign into the BBC iPlayer app. We use Stb-tester’s ocr API to read the sign-in code from the TV screen, and enter it into the browser using Selenium.

Details#

The config/setup/setup script in your test-pack git repository is used to install any third-party packages or dependencies that are not installed on the Stb-tester Node by default. See Customising the test-run environment.

Breaking it down:

#!/bin/bash -ex

This is a Bash shell script; the -e option means that the script will fail immediately if any of the commands in the script fail. This is important so that Stb-tester can detect when the environment wasn’t built correctly.

The -x option means that each command is printed to the log before it is executed; this is useful for debugging issues with the script.

sudo apt-get update
mkdir -p /tmp/chromium
cd /tmp/chromium
curl --fail \
  -O https://deb.debian.org/debian/pool/main/c/chromium/chromium_120.0.6099.224-1~deb11u1_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/c/chromium/chromium-common_120.0.6099.224-1~deb11u1_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/c/chromium/chromium-driver_120.0.6099.224-1~deb11u1_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/libj/libjpeg-turbo/libjpeg62-turbo_2.0.6-4_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/libj/libjsoncpp/libjsoncpp24_1.9.4-4_arm64.deb \
  -O https://deb.debian.org/debian/pool/main/libw/libwebp/libwebp6_0.6.1-2.1%2Bdeb11u2_arm64.deb
sudo apt-get install -y ./*.deb
cd -
rm -rf /tmp/chromium

The above commands download & install the Chromium packages from Debian. Stb-tester v34 uses Ubuntu 22.04, and this (Chromium 120, which was released January 2024) is the latest version in Debian that is compatible with Ubuntu 22.04 (the newer Chromium packages need a newer libc etc).

This also downloads some of Chromium’s dependencies (libjpeg62-turbo, libjsoncpp24, libwebp6) that aren’t available in Ubuntu 22.04.

We install Chromium from Debian (instead of Chrome from Google) because Google doesn’t provide Chrome packages for the ARM64 architecture of the Stb-tester Node.

sudo pip3 install selenium==4.31.0

This installs the selenium Python package. We specify an exact version to ensure reproducible builds of the test environment: Every time we run this script, we want the output to be identical. 4.31.0 was the latest version as of this writing.

Now, on to how we use Selenium in our Python tests:

import selenium.webdriver
from selenium.webdriver.chromium.service import ChromiumService

options = selenium.webdriver.ChromeOptions()
options.add_argument("--headless=new")
service = ChromiumService("/usr/bin/chromedriver")
webdriver = selenium.webdriver.Chrome(options=options, service=service)

--headless=new is a command-line option given to Chromium. Without it, Chromium fails to start because there is no display attached to the test environment on the Stb-tester Node.

Normally Selenium uses selenium-manager to find where the chromedriver executable is installed, but selenium-manager doesn’t support the ARM64 architecture. We can bypass it by specifying the path to chromedriver explicitly.

From here on, webdriver is a normal Selenium WebDriver object. You can call get, find_element, etc. For example, in the demo above we used it like this:

webdriver.get("https://bbc.com/account/tv")
pin_field = webdriver.find_element(By.CSS_SELECTOR, "input#pin")
pin_field.send_keys(page.code)
pin_field.submit()

login_field = webdriver.find_element(By.CSS_SELECTOR,
                                     "input#user-identifier-input")
login_field.send_keys(USERNAME)
login_field.submit()

password_field = webdriver.find_element(By.CSS_SELECTOR,
                                        "input#password-input")
password_field.send_keys(PASSWORD)
password_field.submit()

References and further reading#