Continuous Integration
In this section we will setup continuous integrations to address the following:
- Have a basic CI task for each module: like running unitary tests, etc
- Automatically build and publish docker images: to update the images in a docker registry
- Run integration tests (docker composed): we basically want to have the integations tests that we dockerized automatically being run
Basic CI for our projects
To follow our example app from scratch we need to do step 1 but if you are using your own project and already have tests and CI then you can just skip this part.
Testing the frontend
First we need to create at least one test for our React component :P
So install dependencies to test
yarn add -D mocha chai enzyme react-dom react-test-renderer react-addons-test-utils
Then we need to setup babel (should have done this before :P)
Edit .babelrc and add 'react' preset
{
"presets": ["es2015", "stage-0", "react"],
"plugins": [
["transform-runtime", {
"polyfill": false,
"regenerator": true
}]
]
}
Now add a "test" script to package.json
"test": "mocha --compilers js:babel-register test/**/*_spec.js",
And lets create a test
First we need to edit the src/components/UsersList.jsx file in order to export the bare component (without artemisa decoration, so we don't test actual fetching). Add the following
export const UserListComponent = UsersList
Now create a test
mkdir test
touch test/UserListComponent_spec.js
With the content:
import React from 'react';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';
import { UserListComponent } from '../src/components/UsersList';
describe('<UserListComponent/>', () => {
it('should render nothing if it is not fetched', () => {
const wrapper = shallow(<UserListComponent users={{ state: 'fetching' }}/>)
expect(wrapper.text()).to.contain('IdNameCreated')
})
it('should render two users', () => {
const value = [
{ _id: 1, name: 'docker', created_at: '2017-01-01' },
{ _id: 2, name: 'dockerCompose', created_at: '2017-01-02' }
]
const wrapper = shallow(<UserListComponent users={{ state: 'fetched', value }} />)
expect(wrapper.contains(<td>docker</td>)).to.equal(true)
expect(wrapper.contains(<td>dockerCompose</td>)).to.equal(true)
})
})
And now just run:
yarn test
:)
CI for the frontend
Now we will use travis as CI service. So go ahead to https://travis-ci.org/ create an account if you don't have one, and give it permission to access your frontend's github repository.
Then create a file .travis.yml in the project with content
language: node_js
node_js:
- "7"
cache: yarn
And add the badge to the README.md
[](https://travis-ci.org/javierfernandes/docker-e2e-frontend)
Now git push and you will see it building and the badge should be green like this
Testing the backend
We should do the proper in the backend, like creating some mocha tests for routes and models. I'll skip that here.
Travis configuration is the same as we did for the frontend.
Building & Publishing Docker images from CI
Now the fun part, we want travis to build each project docker image and publish it in a repository.
First of all, before making this automatic we will do it manually, so, lets publish our images
Manually publishing docker images
First you will need to go to https://hub.docker.com/ and register.
Now go to your frontend repo folder and build the image manually (we are providing a name here for the image)
docker build -t e2e-frontend .
Now lets grab some information from it
docker images e2e-frontend
REPOSITORY TAG IMAGE ID CREATED SIZE
e2e-frontend latest 7380611160ab 49 seconds ago 768 MB
We will need the IMAGE ID to now tag it
docker tag 7380611160ab jfernandes/e2e-frontend
And now before pushing we need to provide credentials to the docker command
docker login --username=jfernandes
(of course change your username)_
Now lets publish it
docker push jfernandes/e2e-frontend
It will take some time to upload the layers, and after that you will be able to see the image in dockerhub
For example https://hub.docker.com/r/jfernandes/e2e-frontend/
That is it, we did a manual publishing of our frontend image. We should do the same with backend and e2e-tests modules.
Building Images from Travis
Now we will configure travis to do this automatically for us.
We need to edit .travis.yml. To be able to use docker we need to add
sudo: required
services:
- docker
And then we will setup in the following way:
- Only trigger executing on pushes to master branch
- Build an image using travis build number (autonumeric) as the version
- Publish that using user and password configured as env vars in travis.
after_success:
- if [ "$TRAVIS_BRANCH" == "master" ]; then
docker build -t jfernandes/e2e-frontend:$TRAVIS_BUILD_NUMBER .;
docker login --username="$DOCKER_USERNAME" --password="$DOCKER_PASSWORD";
docker push jfernandes/e2e-frontend:$TRAVIS_BUILD_NUMBER;
fi
Now you need to go to travis settings for this project and add two en vars DOCKER_USERNAME and DOCKER_PASSWORD

That is all, now just push the commit and it will run automatically. After execution you will see a new tag in dockerhub.

CI for e2e tests
Now for the e2e-tests module we need to use the same approach, just that travis configuration is different since we don't want to build the image, but just run it, and we also use docker-compose instead of docker with Dockerfile.
This is .travis.yml file
sudo: required
services:
- docker
before_install:
- docker-compose build
script:
- docker-compose run tests
Now again enable travis for this repo and push it. It should run the tests fine ! :)

Conclusion so far
We were able to automatize a couple of tasks for each module of the app: frontend, backend, and e2e-tests. Those tasks are:
- what we usually (wrongly) call C.I., which is to run each individual module tests/checks.
- build and publish each module's docker image into dockerhub registry (with some small changes this could also apply to private registries. See "Extras")
- Automatically run e2e tests in a server (which is not so easy, since running GUI-dependent tests is not a trivial task. We were able to wrap those tests in a virtual environment by using docker, and that introduced the need to build docker images.
This is great, but we are still not done. We need to link each module development lifecycle so that e2e tests run upon changes to any of the modules besides itself. And ideally providing "acceptance" checks to Pull requests as the modules regular CI does by integrating with Github hooks/Status API.
Lets continue then !