Cypress and Angular in a Jenkins Pipeline via Docker
Tags: cypress, angular, jenkins, docker
Published: 2020-03-25 21:51:25

### What's the objective?

In this post I'm going to show you how to run Cypress in a Jenkins pipeline (via Docker) to test an Angular application. 

The main focus of this tutorial is not on these individual technologies. Instead, it's how to pull them all together to give you an example of how continuous integration could look for your project.

---

### What's needed before starting?

This tutorial assumes that you have...

- An Angular application (built with the CLI) with Cypress installed and at least one test written.

- Docker installed & configured on your machine

- Experience working with these technologies before

*This example was developed using macOS*

---

### Jenkins Initial Setup, Startup and Configuration

Start by creating some volumes for your Jenkins Docker container:

```shell
# from the terminal
docker volume create jenkins-data 
docker volume create npm-cache
docker volume create cypress-cache
```

Next, use the `docker run` command to pull down the Jenkins Docker image, configure the volumes you've created and run the container serving the Jenkins app on localhost:8080:

```shell
# from the terminal
docker run -u root -d --name jenkins-tut -p 8080:8080 --ipc=host \
-v jenkins-data:/var/jenkins_home \
-v npm-cache:/root/.npm \
-v cypress-cache:/root/.cache \
-v /var/run/docker.sock:/var/run/docker.sock jenkinsci/blueocean:latest
```

Once that completes, open a browser and navigate to: `http://localhost:8080` and wait until you see the 'Unlock Jenkins' page appear.

This page should prompt you for an administrator password. To retrieve it, peek at the Docker logs for the jenkins-tut container you have running:

```shell
# from the terminal
docker logs jenkins-tut
```

The password should appear in the log under the 'Jenkins initial setup is required...' statement. It's a long alphanumeric string - you can't miss it! It looks like this: `2f064d3663814887964b682940572567`.

Copy and paste that puppy in and select 'Continue'!

After you make it past the 'Unlock Jenkins' page, you will be prompted to create a user and login for returning sessions. Create your desired user and continue on.

Next, you'll be prompted with the 'Customize Jenkins' page. Select 'Install Suggested Plugins' and continue on.

You should now see the Jenkins Dashboard!

---

### Prepping Angular/Cypress for Deployment

Now hop over to your Angular project (that has Cypress installed and configured with at least one running test) and wire up the build process.

First, we need to install 2 packages that will allow Angular and Cypress to run together on the Jenkins node.

Inside the root directory of your Angular project, run:

```shell
# from the terminal
npm install angular-http-server --save-dev
npm install start-server-and-test --save-dev
```

`angular-http-server` allows the built Angular code (in /dist) to be served on the Jenkins node during the Pipeline. We want it running so that Cypress can call it.

`start-server-and-test` enforces a sequential start up between the Angular app and the Cypress tests. This prevents the issue of Cypress trying to call the app before it's running.

Next we'll need to add some scripts to the `package.json` file. These scripts will make use of the new packages and orchestrate the startup of the Angular app and the Cypress test suite.

In the `package.json`:

```json
...
"scripts": {
    ...
    "cy:run": "cypress run",
    "cy:verify": "cypress verify",
    "ci:start-ng": "angular-http-server --path ./dist/YOUR_APP_NAME -p 4200",
    "ci:cy-run": "start-server-and-test ci:start-ng http://localhost:4200 cy:run",
    ...
}
...
```

**If you're using Angular 9** you may want to add this line as well to the `package.json` scripts section:

```json
    # for Angular 9 only
    "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points",
```

This works with v9's Ivy view engine and will speed up compilation time when running `ng build`.

Lastly, well create a `Jenkinsfile` at the root of the project that Jenkins will read from and define some stages for the build to go through.

Create a `Jenkinsfile`

```
pipeline {
    agent {
        docker {
            image 'cypress/base:12.16.1' 
            args '-p 3000:3000' 
        }
    }
    stages {
        stage('Install Dependencies') { 
            steps {
                sh 'npm ci'
                sh 'npm run cy:verify'
            }
        }
        stage('Build') { 
            steps {
                sh 'npm run build'
            }
        }
        stage('Test') { 
            steps {
                sh 'npm run ci:cy-run'
            }
        }
    }
}
```

The `agent` section will allow our Jenkins container to pull in a Cypress Docker image (with Node 12.16.1) for the duration of the build. The steps that follow will actually be run in that environment.

We also add in 3 steps that will install the projects dependencies, verify a successful Cypress installation, build the Angular project and then run the compiled Angular code with Cypress using the sequential start provided by the `angular-http-server` and `start-server-and-test` packages.

With all that added, **save and commit your changes**!

---

### Create the Jenkins Pipeline Project

Now head back to your Jenkins instance...

- From the dashboard view, click 'Create New Jobs' in the middle or 'New Item' at the top of the left menu.

- Enter a name for your item.

- Select 'Pipeline' as the type and click 'OK' at the bottom of the page.

- Add an **optional** description for your pipeline.

- Click the 'pipeline' tab at the top of the page to bring the 'pipeline' section into view.

- In the 'Definition' field, select: 'Pipeline script from SCM'

- In the 'SCM' field, select: 'Git'

- In the 'Repository URL' field, enter the path to your project **on your local system** translated to the /home directory of the Jenkins container. For example, if your project is at `/Users/YOUR_NAME/Development/YOUR_PROJECT` then you would enter `/home/Development/YOUR_PROJECT`. Jenkins will perform some validation against your entry to let you know if it can reach the project.

- Lastly, 'Save' your configuration!

---

### Run the Build!

With your new pipeline created, it's time to run a build!

**From the Jenkins dashboard view**, you should see your new pipeline listed. Select the project name and then in the details view select 'Build Now'.

Once you've started the build, you should see a new entry in the 'Build History' menu to the left. If you click on the flashing dot next to the build number, you can view the log of the build.

**Verify success and celebrate!**

---

### Resources

This tutorial came from a collection of resources. I encourage you to further explore these technologies and improve upon this process!

https://jenkins.io/doc/tutorials/build-a-node-js-and-react-app-with-npm/

https://www.cypress.io/blog/2019/08/02/guest-post-angular-adding-cypress-ui-tests-to-your-devops-pipeline/

https://github.com/cypress-io/cypress-example-kitchensink/blob/master/Jenkinsfile

*Cover photo by JJ Ying on Unsplash*