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 the conclusion of 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 3 where we will cover...
- The conclusion of The How of adding this framework, specifically the
dockercomposerun
script (the final piece)- Using your newly added docker compose framework
Because laziness is a virtue in computer science, you want a
dockercomposerun
script that sets up, runs, and tears down
your docker-compose framework for you. You can then use this
single command locally or in CI/CD.
And you value transparency, especially in CI/CD, so you will want to have the script output version and environment information. This is especially helpful when debugging any issues.
Finally, to ensure that the CI/CD job fails when your tests fail,
you will want to capture the return code of the test run and
return that as the return code for your dockercomposerun
command.
To make your
dockercomposerun
script more flexible and usable, you will pass any arguments to the script to thedocker-compose run
command so that this command overrides theruntests
CMD in yourDockerfile
Here is a basic dockercomposerun
script that you can add...
#!/bin/sh
# This script runs the project docker-compose framework.
#
# - The arguments to this script are passed to the browsertests service
# as command override
#
# - Any environment variables set when calling this script are passed
# through to the docker-compose framework
# (e.g. configuration other than the defaults
#
# Exit script on any errors
set -e
echo ''
echo "ENVIRONMENT VARIABLES..."
env
echo ''
echo 'DOCKER VERSION...'
docker --version
docker-compose --version
echo ''
echo 'DOCKER-COMPOSE COMMAND...'
docker_compose_command='docker-compose -f docker-compose.yml -f docker-compose.selenium.yml '
echo "...COMMAND: [${docker_compose_command}]"
echo ''
echo 'DOCKER-COMPOSE CONFIGURATION...'
$docker_compose_command config
echo ''
echo 'DOCKER-COMPOSE PULLING...'
set +e
$docker_compose_command pull
echo '...Allowing pull errors (for local images)'
set -e
echo ''
echo 'DOCKER IMAGES...'
docker images
echo ''
echo "DOCKER-COMPOSE RUNNING [$@]..."
# Allow to fail but catch return code
set +e
$docker_compose_command run browsertests "$@"
run_return_code=$?
# NOTE return code must be caught before any other command
set -e
echo ''
if [ $run_return_code -eq 0 ]; then
run_disposition='PASSED'
else
run_disposition='FAILED'
fi
echo "...RUN [${run_disposition}] WITH RETURN CODE [${run_return_code}]"
echo ''
echo 'DOCKER-COMPOSE DOWN...'
$docker_compose_command down
echo ''
echo "EXITING WITH ${run_disposition} RUN RETURN CODE ${run_return_code}"
exit $run_return_code
This is pretty basic Unix shell programming because... well... me.
The set -e
command ensures that the script will exit with an error
code on any unexpected errors. We never want to risk that our tests
falsely "pass" if they do not actually run.
The env
command outputs the current environment variables for
transparency.
The docker --version
and docker-compose --version
commands
output the respective version information again for transparency.
The command
docker_compose_command='docker-compose -f docker-compose.yml -f docker-compose.selenium.yml '
assigns the sequenced calling of the framework's docker-compose
files
to a local variable. This is that Don't Repeat Yourself principle
in practice again.
This is also useful to conditionally add another docker-compose file...
This is also useful if you need to conditionally add another
docker-compose
file for reasons.
Here's an example where I conditionally add a development
environment docker-compose
file if a browser tests image is specified...
echo 'DOCKER-COMPOSE COMMAND...'
docker_compose_command='docker-compose -f docker-compose.yml -f docker-compose.selenium.yml '
if [ ! -z ${BROWSERTESTS_IMAGE} ]; then
echo "...Using Development Environment with Image [${BROWSERTESTS_IMAGE}]"
docker_compose_command="${docker_compose_command} -f docker-compose.dev.yml "
fi
echo "...COMMAND: [${docker_compose_command}]"
echo ''
The $docker_compose_command config
command outputs the final
docker-compose configuration with all additions and overrides
for transparency.
This following block pulls the images but uses set +e
to unset
the exit-on-failure setting to allow pull failures for local images.
It then sets the exit-on-failure setting.
echo 'DOCKER-COMPOSE PULLING...'
set +e
$docker_compose_command pull
echo '...Allowing pull errors (for local images)'
set -e
echo ''
This explicit pulling of images means that the script will pull any name:tag images if they exist in your remote container registry (e.g. Docker Hub) overriding any local images with the name:tag. This behavior is intended for CI/CD where control and certainty is required.
TIP: To test local images, use a tag that does not exist in your container registry.
Again for transparency and debugging (especially with local images),
the docker images
command outputs all the docker images present.
This following block runs any supplied command line arguments in the
browsertests
container. This allows you to override the default
runtests
command in your image. If there are no arguments, it runs
the default Dockerfile
CMD
(i.e. the runtests
script.)
echo "DOCKER-COMPOSE RUNNING [$@]..."
# Allow to fail but catch return code
set +e
$docker_compose_command run browsertests "$@"
run_return_code=$?
# NOTE return code must be caught before any other command
set -e
echo '
It also once again unsets exit-on-failure so that the
docker-compose run can fail without the script exiting.
run_return_code=$?
stores the return code of the run
(e.g. tests) to return it at the end of the script.
The script then uses the run_return_code
to set and
output a 'PASSED'
or 'FAILED'
local variable in this
following block...
if [ $run_return_code -eq 0 ]; then
run_disposition='PASSED'
else
run_disposition='FAILED'
fi
echo "...RUN [${run_disposition}] WITH RETURN CODE [${run_return_code}]"
echo ''
The $docker_compose_command down
command shuts down and cleans up
the docker-compose framework.
Finally, the exit $run_return_code
command exits with the value of the
stored run_return_code
indicating if the run passed or failed.
Test your dockercomposerun
command and your framework to ensure that
they work and run your tests.
Be sure to...
-
Make sure you have your browser tests image already built if you are pulling (and not building) the image in your
docker-compose.yml
file -
Use the script's output to verify and debug your script and framework
Test that...
-
Your defaults work, for example...
./script/dockercomposerun
-
Your environment variables work, for example...
SELENIUM_IMAGE=selenium/standalone-firefox BROWSERTESTS_TAG=foo ./script/dockercomposerun
-
You can supply run commands to override the default
runtests
command, for example to run your framework interactively..../script/dockercomposerun sh
Now that you have added your docker-compose framework, you can use it in many ways.
-
You can use it to run and develop your tests more easily locally
- Use the
BROWSERTESTS_TAG
environment variable to run and test your own images
- Use the
-
You can use it in your CI/CD framework to simply your workflows for running the tests, this is especially useful if several applications run your tests as acceptance tests as part of their CI/CD
- Here's an example from one of my projects where I use
dockercomposerun
to simplify my GitHub Actions CI...run-tests-default-chrome: needs: build-deploy runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: dockercomposerun (Run tests) with defaults run: ./script/dockercomposerun run-tests--specified-firefox: needs: build-deploy runs-on: ubuntu-latest env: BROWSER: firefox SELENIUM_IMAGE: selenium/standalone-firefox:latest steps: - uses: actions/checkout@v1 - name: dockercomposerun (Run tests) with Firefox run: ./script/dockercomposerun
- Here's an example from one of my projects where I use
-
You can also use it with the command override ability to perform actions in your container such as linting and static security scanning, for example...
./script/dockercomposerun bundle exec rake rubocop ./script/dockercomposerun bundle exec rake bundle:audit
This concludes this series on adding a docker-compose framework to your browser tests project.