Configure Cypress to wait the Java backend in a Docker based CI
- Docker Compose
- Healthcheck ... wainting the start of the Java application
- Docker files
- Cypress configuration
The main (pain-)points and solutions here are:
- Create a Docker compose that doesn't require to modify the existing modules (backend and frontend), the Cypress Docker Compose configuration is all in the same directory.
- The Cypress tests don't have to go in TIMEOUT, they have to wait that the container with the server starts before to launch the tests.
- We want to publish the results with the JUnit format to be integrated with an external monitoring platform.
- The code has to be minimalistic, as usual.
- The solution is part of an automatic Pipeline (in Azure)
Our goal is to create a Docker Compose configuration to deploy and test our Angular/Java application using Cypress.
In the real world we are deploying this configuration in Azure.
Docker Compose
For our example we use the same structure of our full-stack application: https://marmo.dev/angular-with-java
We add an e2e
directory in our SpringAngularDemo. The goal is to confine the e2e tests in this directory and don't add these tests or configuration in the frontend or backend modules of the webapp.
The docker compose file declare the 2 images that will be created, 1 for the webapp (backend + frontend) and 1 for the cypress tests.
version: '3'
services:
webapp:
build:
dockerfile: ../e2e/delivery-dev-e2e.Dockerfile
context: ../delivery
container_name: webapp
restart: always
healthcheck:
test: ["CMD-SHELL", "curl -f http://webapp:8080/actuator/health || exit 1"]
interval: 30s
timeout: 20s
retries: 10
e2e:
container_name: cypress-tests
depends_on:
webapp:
condition: service_healthy
environment:
- CYPRESS_baseUrl=http://webapp:8080
build:
dockerfile: e2e.Dockerfile
context: .
volumes:
- ./results:/target/cypress/results
command:
- npx cypress run
Two points are particularly important here:
dockerfile: ../e2e/delivery-dev-e2e.Dockerfile
allows us to use thedelivery
context (a different module) with our local dockerfile.
This allows us to don't pollute the backend or delivery directory with configuration files related to the cypress tests.
healthcheck
is a feature of docker that check if a container is healthy (started) according to a criteria that we can define.
The risk with a webapp and cypress is that the instance of cypress starts before the webapp server ends the initialization. Cypress call the home page and the server doesn't answer yet. Cypress tries few times and it stops with an error because the home page is not available.
Healthcheck ... wainting the start of the Java application
What we are doing with healthcheck is declaring the webapp container not healty until when Spring Boot doesn't answer OK.
To do this we have to activate actuator in Spring Boot.
Docker will monitor the url we defined as test and when this will answer with a 200 then Docker will start the Cypress tests.
The cypress container will be initialized only when webapp is healthy.
depends_on:
webapp:
condition: service_healthy
Docker files
Our Docker files are standard.
For the delivery (or webapp):
FROM eclipse-temurin:17-jre
COPY ./target/[webapp-name-*].jar /opt/webapp/webapp-name.jar
CMD ["java", "-jar", "/opt/webapp/webapp-name.jar"]
For the Cypress docker image:
FROM cypress/included:12.7.0
COPY cypress.config.js .
ADD cypres ./cypress
COPY package.json .
COPY package-lock.json .
RUN npx cypress verify
Cypress configuration
const {defineConfig} = require('cypress')
module.exports = defineConfig({
chromeWebSecurity: false,
reporter: 'junit',
reporterOptions: {
mochaFile: '/target/cypress/results/results-[hash].xml',
toConsole: false
},
e2e: {
baseUrl: 'http://webapp:8081'
}
})
In this configuration we have 2 particularly important parameters.
chromeWebSecurity: false
mitigates/avoids the TIMEOUTCypressError: Timed out retrying: cy.wait() timed out waiting 60000ms for the 1st request to the route
.reporter: 'junit'
allows to save the results in junit format and integrate the results in external tests platforms.