Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save brianjbayer/5a552641fe977e84eeeb116a4a95737d to your computer and use it in GitHub Desktop.
Save brianjbayer/5a552641fe977e84eeeb116a4a95737d to your computer and use it in GitHub Desktop.
Part 1 - Add a docker-compose Framework to Your Browser Tests

Add a docker-compose Framework to Your Browser Tests (Part 1 of 3)

The Flats Cleveland, Ohio - Wendy Bayer


Simplify running and testing your tests and maybe even get more people to run and use them.

Add a simple but easy-to-use docker-compose orchestration framework using a Selenium Standalone browser container to your browser test projects. View the tests using the included Virtual Network Computing (VNC) Server.

Use it locally to simplify using and testing your tests.

Use it in Continuous Integration/Continuous Deployment (CI/CD) to simplify workflows and keep the logic with your tests.

#docker-compose #unixshellprogramming #docker-selenium

In this three part series, I will show you how you can add a docker-compose framework to your automated browser tests (e.g. end-to-end, acceptance) with a single command to spin it up, run it, and tear it all back down.

We'll cover and practice some docker-compose concepts and Unix shell programming.

This is Part 1 where we will cover...

  • The What of this framework (i.e. what we will add)
  • The start of The How of adding this framework, specifically the first piece which is the runtests script

Skip to Part 2 or Part 3


The What

In this 3 part series, you will build this framework by adding...

  1. runtests script to orchestrate (wait on) a remote browser (i.e. Selenium Standalone)
  2. Project Dockerfile to build your browser tests image with a default CMD that can be overridden
  3. Don't Repeat Yourself (DRY) set of docker-compose files to orchestrate the browser tests and the Selenium Standalone browser container
  4. dockercomposerun script that can be used locally and in CI/CD that sets up the browser tests and Selenium Standalone containers, runs the browser tests image, and tears it all down, returning the return code from running the browser tests container

The How

To add this framework to your project, you will need to have a way, ideally an environment variable, to configure the URL of the remote (Selenium) browser in your browser tests application


You Want a runtests Script...

To implement your runtests script, you will need to have a simple way of checking the remote status endpoint in the shell of your particular browser tests' base image and the command to run your tests

You will want a runtests script to wait on the remote browser (i.e. Selenium Standalone) to be fully up and ready before running your tests. Although the Selenium Standalone container may be "up", it still may not be ready for the tests to run and the tests will fail.

Add a runtests Script

I am pretty sure that I originally got this script from Ruiyu(Ryan) Wang and IIRC he said he got it from "some post on the internet".

It is also based on the Selenium Standalone Container using a bash script to wait for the grid. This is where I got the curl command that I will give later and the REMOTE_STATUS endpoint.

Here's an example of a runtests script that you can use and customize. This syntax will work for both ash in Alpine/BusyBox and bash. However, the wget command is specific for Alpine and the bundle exec rspec is only for Ruby-Rspec.

#!/bin/sh
# This script orchestrates running the browser tests
# with a remote browser if its status point is set
#
# Assumes Alpine (Busybox) and uses wget

if [ ! -z "${REMOTE_STATUS}" ];
then
  COUNTER=0
  echo "Waiting for ${REMOTE_STATUS} to become available"
  until wget --spider -q "${REMOTE_STATUS}" &>/dev/null; do
    printf "."
    sleep 1
    COUNTER=$((COUNTER + 1))
    if [ $COUNTER -eq 30 ] ; then
      echo ""
      exit 1
    fi
  done

  echo ""
fi

# Run the tests with the underlying testing framework
# (with any passed in args)
bundle exec rspec "$@"
Where to put your script...

You will want a directory in your project for your runtests script and the dockercomposerun script that you will add later if you do not already have one. Some people use bin/, but I prefer that for actual binaries and use script/. You do you.

Make sure your script is executable...

Captain Obvious says, you will want to make sure that your runtests script is executable (i.e. chmod ug+x runtests)


How It Works

The script is intended to be run from the project root directory (e.g. ./script/runtests).

The line if [ ! -z "${REMOTE_STATUS}" ]; checks whether the REMOTE_STATUS environment variable is set and non-empty and if so, then enters the wait on remote browser logic. If the REMOTE_STATUS environment variable is not set or is empty, then the wait logic is skipped and the script simply runs the command to run the tests (for example if running with a local browser).

The REMOTE_STATUS endpoint is the /status route off of the base URL for your remote Standalone Container browser (e.g. http://localhost:4444/wd/hub/status).

The line until wget --spider -q "${REMOTE_STATUS}" &>/dev/null; do starts an "until" loop which checks every second 30 times if the REMOTE_STATUS endpoint shows ready.

Here we are using the wget --spider -q "${REMOTE_STATUS}" command to check if the endpoint is ready since this an Alpine/BusyBox base image.

To use a curl command instead...

For a base-image with the curl command present, you can use...

curl -fsSL "${REMOTE_STATUS}"

If the endpoint check does not return ready after the 30 tries, the script exits with a non-zero return code indicating failure.

If the endpoint check does return ready, then the loop exits and the script runs the command to run the tests, here bundle exec rspec "$@" since this is a Ruby-RSpec example.

The "$@" argument contains any arguments passed to the runtests scripts thus forwarding them on to the command to run the tests. This allows you to pass arguments to the runtests command that are supported by the underlying testing framework (e.g. RSpec) for example, passing "filters" to run or exclude specific tests.

Put any default arguments that you want, particularly for CI/CD, for the command you use to run your tests (e.g. bundle exec rspec --format documentation "$@"). in your runtests script for consistency, a single source of truth, and easier maintenance and testing


Test it

Test your runscript script to ensure that it...

  1. Runs locally when REMOTE_STATUS is not set, for example
    REMOTE_STATUS= ./script/runtests
    
  2. Fails if the REMOTE_STATUS is set but not available, for example...
    REMOTE_STATUS=foo ./script/runtests
    
  3. Runs the tests when the REMOTE_STATUS is available, for example...
    docker run -d -p 4444:4444 -p 5900:5900 -p 7900:7900 -v /dev/shm:/dev/shm selenium/standalone-chrome
    REMOTE='http://localhost:4444/wd/hub' REMOTE_STATUS=${REMOTE}/status BROWSER=chrome ./script/runtests
    
  4. Passes any arguments to the command to run your tests, for example...
    ./script/runtests --dry-run
    

This is the end of Part 1. Continue to Part 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment