E2E testing using Docker, Cypress, VueJS, Golang and Postgres
End-To-End testing is focused to test the entire application flow, simulating the user’s interaction, ensuring that all components work as expected.
You probably have seen companies running a manual E2E testing in a staging environment. But what about to run automated E2E testing integrated with the CI process?
I will show up how I automated testing running the Cypress test runner for a single page application (SPA) using VueJS, Go and PostgreSQL, working on Docker containers, triggered by a Jenkins build. It’s a good cheap solution for personal projects and startups.
Containers architecture
Docker creates a private network where containers can be connected together. I used Docker Compose to simplify the containers’ creation and manages the dependencies.
This is how I written the docker-compose.yml
:
version: "3"
services:
frontend:
build:
context: ./frontend
args:
- VUE_APP_API_URL=http://backend:11080
container_name: frontend
hostname: frontend
ports:
- "2015:2015"
expose:
- "2015"
depends_on:
- backend
environment:
- VUE_APP_API_URL=http://backend:11080
backend:
build: ./backend
container_name: backend
hostname: backend
ports:
- "17000:17000"
expose:
- "11080"
depends_on:
- db
environment:
- DATABASE_URL=postgres://admin:password@db:5432/todos?sslmode=disable
db:
image: postgres:alpine
container_name: db
hostname: db
ports:
- "5432:5432"
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=password
- POSTGRES_DB=todos
tests:
build: ./tests
container_name: tests
depends_on:
- frontend
- backend
- db
environment:
- DATABASE_URL=postgres://admin:password@db:5432/todos?sslmode=disable
- CYPRESS_FRONTEND_URL=http://frontend:2015
volumes:
- "./tests/cypress:/home/node/tests/cypress"
- "./tests/report:/home/node/tests/report"
Writing tests
Cypress is a test runner similar to Selenium/Webdriver. It is faster and doesn’t need a graphical environment to run. Cypress has good integration with CI tools like Jenkins, CircleCI, Semaphore, Gitlab, and Travis.
In order to have repeatable tests it seems a good idea to have a test database populated with known data against which to write the tests. Populating this database is straightforward and resetting it could be as simple as dropping it at the end of the test or before to start the next. There are many ways to achieve it, developer’s imagination is the limit. Here, I just create a shell script that uses the Postgres Command Line Tool (psql
) to drop table and insert one registry.
Script resetdb.sh
runned before each test:
echo "Reseting database..."
psql ${DATABASE_URL} <<EOF
DROP TABLE IF EXISTS tasks;
CREATE TABLE tasks (id SERIAL NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, description VARCHAR, done BOOL NOT NULL DEFAULT false, CONSTRAINT id_pk PRIMARY KEY (id));
INSERT INTO tasks (description) VALUES ('Create a TODO app as example of e2e testing');
EOF
A simple test written in Javascript:
describe('Todo tests', () => {
// CYPRESS_FRONTEND_URL defined in docker-compose.yml
const baseUrl = Cypress.env('FRONTEND_URL')
beforeEach(() => {
// Run the script resetdb.sh
cy.exec('sh resetdb.sh')
})
context('When page is opened', () => {
it('Creates a new task and add it in top of the list', () => {
const task = 'todo test 1 cypress'
cy.visit(baseUrl)
.get('input[type="text"]').clear().type(task)
.get('button.button').click()
// Check if the saved task is on top
cy.get('ul > li:first > .tasks__item__toggle')
.should(($item) => {
expect($item).to.contain(task)
})
})
})
})
Configure Jenkins
I created a Freestyle Job with Execute shell
property:
# Clear the Workspace
rm -rf * 2>/dev/null
# Clone the repository
git clone https://github.com/gustavohenrique/e2e-tests-using-docker-cypress-vuejs-golang-postgres.git
# Run the containers
cd e2e-tests-using-docker-cypress-vuejs-golang-postgres
docker-compose up --exit-code-from tests --force-recreate
I also configured the Job to public tests report in JUnit format in Post-build actions
option:
# Report path
e2e-tests-using-docker-cypress-vuejs-golang-postgres/tests/report/output.xml
Conclusion
I run E2E or integration tests in containers in these scenarios:
- I don’t want to pay for a staging environment for my personal projects
- I don’t have a QA tester available in my team
- I need to run tests in the CI process
- I fell into a legacy project with no tests and I need feel safe before refactoring the code
Source code
The source code of the example is available in https://github.com/gustavohenrique/e2e-tests-using-docker-cypress-vuejs-golang-postgres.