We are using the Protractor testing framework in order to test our Gentics Mesh AngularJS Admin UI Webapp. In this blogpost I will explain our setup and how we use docker to run the protractor tests.
Protractor uses Selenium in order to test the application.
The easiest way to setup a selenium node is to use the webdriver-manager tool but it is also possible to use selenium docker images.
Our tests use the Firefox selenium node but it is also very easy to run tests using chrome.
The command docker run -d -p 4444:4444 selenium/standalone-firefox
will spawn a new docker container which runs the selenium node.
Next we need our AngularJS application. In our case this is Gentics Mesh. You can start the Gentics Mesh Demo Docker Container via docker run -p 8080:8080 gentics/mesh-demo
.
The started container will run the Gentics Mesh backend server and also serve the Admin UI.
We have two test cases:
The login test will log in using the default demo credentials and verify that the demo project is being displayed.
/login-test.js
describe('mesh login test', function() {
it('should be able to login', function() {
browser.get('http://' + browser.params.meshHost + ':' + browser.params.meshPort + '/mesh-ui');
element(by.model('vm.userName')).sendKeys('admin');
element(by.model('vm.password')).sendKeys('admin');
element(by.model('vm.password')).sendKeys('\n');
var projectList = element.all(by.repeater('project in vm.projects'));
expect(projectList.count()).toEqual(1);
expect(projectList.get(0).getText()).toEqual('demo');
});
});
The demo test will just access the demo endpoint which displays a simple AngularJS dummy webapp which displays the demo contents.
/demo-test.js
describe('mesh demo test', function() {
it('should be list the demo', function() {
browser.get('http://' + browser.params.meshHost + ':' + browser.params.meshPort + '/demo');
});
});
Both tests use browser.params
in order to access params we specify during protractor startup.
The main protractor configuration file is currently set up to run both tests using firefox.
/protractor.conf.js
exports.config = {
specs: ['login-test.js', 'demo-test.js'],
capabilities: {
'browserName': 'firefox'
}
};
Finally it is time to execute the protractor tests.
You can run the tests locally using a local selenium node which you can start using the webdriver-manager start
command.
Once the selenium node and your Gentics Mesh application is ready you can invoke the protractor tests:
protractor conf.js --params.meshHost localhost --params.meshPort 8080 --seleniumAddress http://localhost:4444/wd/hub
Of course you could now glue everything together using <$INSERT_YOUR_TOOL> here. In our case we use docker-compose and a little bit of bash for this.
The /docker-compose.yml file contains three services.
- tester: An image which contains the protractor tests. This will also execute these tests.
- selenium: The selenium node which will be used by the tester service.
- mesh: The application which will be tested. The selenium service must be able to access it.
The entrypoint value is customized in order to insert a bash script which will block execution until the needed service is ready. The /api/v1/admin/status
endpoint is polled in order to verify that mesh is ready to accept requests. Similarly the selenium hub url is also checked.
version: '2'
services:
tester:
build: .
entrypoint: bash -c "while ! timeout 1 wget -qO- http://selenium:4444/wd/hub > /dev/null ; do sleep 1; done; protractor --seleniumAddress http://selenium:4444/wd/hub --params.meshHost mesh --params.meshPort 8080 /app/protractor.conf.js"
selenium:
image: selenium/standalone-firefox
ports:
- "4444:4444"
entrypoint: bash -c "while ! timeout 1 wget -qO- http://mesh:8080/api/v1/admin/status > /dev/null ; do sleep 1; done ; ./opt/bin/entry_point.sh"
mesh:
image: gentics/mesh-demo:latest
ports:
- "8080:8080"
A very simple docker file which adds the protractor configuration and test files to a new image which we will use to run our tests.
/Dockerfile
FROM jotschi/protractor
RUN mkdir -p /app
COPY *.js /app/
The test runner script is used to startup the docker-compose setup and wait until the tests have been executed. The test results will be printed to stdout and the exitcode of protractor will be passed along.
The following script is an adaptation of the test.sh script which was written by Harrison Harnisch. He also wrote an excellent blog post on integration testing using docker.
/test.sh
#!/bin/bash
# define some colors to use for output
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
# kill and remove any running containers
cleanup () {
docker-compose kill
docker-compose rm -f
}
# catch unexpected failures, do cleanup and output an error message
trap 'cleanup ; printf "${RED}Tests Failed For Unexpected Reasons${NC}\n"' HUP INT QUIT PIPE TERM
# build and run the composed services
docker-compose build && docker-compose up -d
if [ $? -ne 0 ] ; then
printf "${RED}Docker Compose Failed${NC}\n"
exit -1
fi
# wait for the test service to complete and grab the exit code
TEST_EXIT_CODE=`docker wait integrationtests_tester_1`
# output the logs for the test (for clarity)
docker logs --tail=all integrationtests_tester_1
# inspect the output of the test and display respective message
if [ -z ${TEST_EXIT_CODE+x} ] || [ "$TEST_EXIT_CODE" -ne 0 ] ; then
printf "${RED}Tests Failed${NC} - Exit Code: $TEST_EXIT_CODE\n"
else
printf "${GREEN}Tests Passed${NC}\n"
fi
# call the cleanup fuction
cleanup
# exit the script with the same code as the test service code
exit $TEST_EXIT_CODE
Finally you can run ./test.sh which will set up your docker-compose environment and execute the tests.
./test.sh
mesh uses an image, skipping
selenium uses an image, skipping
Building tester
Step 1 : FROM jotschi/protractor
---> ffd0a8bd68a6
Step 2 : RUN mkdir -p /app
---> Using cache
---> b22bae66ffa7
Step 3 : COPY *.js /app/
---> Using cache
---> bacc34b8df2d
Successfully built bacc34b8df2d
Creating integrationtests_mesh_1
Creating integrationtests_selenium_1
Creating integrationtests_tester_1
[11:50:41] I/hosted - Using the selenium server at http://selenium:4444/wd/hub
[11:50:41] I/launcher - Running 1 instances of WebDriver
Started
..
2 specs, 0 failures
Finished in 4.84 seconds
[11:50:52] I/launcher - 0 instance(s) of WebDriver still running
[11:50:52] I/launcher - firefox #01 passed
Tests Passed
Killing integrationtests_selenium_1 ... done
Killing integrationtests_mesh_1 ... done
Going to remove integrationtests_tester_1, integrationtests_selenium_1, integrationtests_mesh_1
Removing integrationtests_tester_1 ... done
Removing integrationtests_selenium_1 ... done
Removing integrationtests_mesh_1 ... done
https://unsplash.com/photos/TtN_obfWlGw
https://unsplash.com/@wesleycaribe Wesley Caribe via unsplash