---
title: "Testing deployed GitLab pages using Cypress and GitLab CI"
url: "https://www.cypress.io/blog/fast-end-to-end-browser-tests-using-cypress-and-gitlab-ci"
description: "In this blog post we will deploy a static site to GitLab Pages, and then we will run end-to-end browser tests against the deployed site to make sure it is…"
---

# Testing deployed GitLab pages using Cypress and GitLab CI

May 5, 2021

By Gleb Bahmutov

In this blog post we will deploy a static site to GitLab Pages, and then we will run end-to-end browser tests against the deployed site to make sure it is working as expected. The Cypress Test Runner makes it extremely simple to write full browser end-to-end (E2E) tests, while GitLab CI is a powerful platform for running such tests.

## The application

Today's example is a static site built from a Markdown source file using [VuePress](https://vuepress.vuejs.org/?ref=cypress-io.ghost.io). You can find the full source code at [gitlab.com/bahmutov/gitlab-pages-example](https://gitlab.com/bahmutov/gitlab-pages-example?ref=cypress-io.ghost.io).

The example repository

The "docs" folder contains the Markdown files to be converted into the static HTML pages.

The "docs" folder keeps the source Markdown and the VuePress settings files

The VuePress settings in the [docs/.vuepress/config.js](https://gitlab.com/bahmutov/gitlab-pages-example/-/blob/main/docs/.vuepress/config.js?ref=cypress-io.ghost.io) file contains the main static site settings.

```js
module.exports = {
  title: 'GitLab + Cypress = ❤️',
  description: 'Static site deployed to GitLab pages ...',
  base: '/gitlab-pages-example/',
  dest: 'public'
}
```

As of this writing, I am using VuePress v1.8 and Cypress v7. In the root [package.json](https://gitlab.com/bahmutov/gitlab-pages-example/-/blob/main/package.json?ref=cypress-io.ghost.io) file I set up a few utility scripts for building and testing the site locally.

```json
{
  "scripts": {
    "test": "cypress run",
    "start": "vuepress dev docs",
    "docs:build": "vuepress build docs",
    "dev": "start-test http://localhost:8080/gitlab-pages-example/ cy:open",
    "cy:open": "cypress open"
  },
  "dependencies": {
    "vuepress": "1.8.2"
  },
  "devDependencies": {
    "cypress": "7.2.0",
    "start-server-and-test": "1.12.1"
  }
}
```

When I want to start the site locally, and open the Cypress Test Runner I execute the `npm run dev` command via [start-server-and-test](https://github.com/bahmutov/start-server-and-test?ref=cypress-io.ghost.io) utility.

## The tests

We probably do not need a lot of tests in this case, just a smoke test to make sure the site is working.

```js
// cypress/integration/spec.js
/// <reference types="cypress" />

describe('Static site', () => {
  it('works', () => {
    cy.visit('/')
    cy.contains('h1', 'GitLab + Cypress = ❤️')
  })
})
```

The local static site tested locally

In our test the URL to visit is taken from the [cypress.json](https://gitlab.com/bahmutov/gitlab-pages-example/-/blob/main/cypress.json?ref=cypress-io.ghost.io) file that contains the Cypress test settings

```json
{
  "fixturesFolder": false,
  "supportFile": false,
  "pluginsFile": false,
  "baseUrl": "http://localhost:8080/gitlab-pages-example/"
}
```

The tests are very lightweight and do not need fixtures, custom commands, or any additional [Cypress plugins](https://on.cypress.io/plugins?ref=cypress-io.ghost.io).

## The GitLab CI

Let's run the above test on GitLab CI. We need to repeat the same steps on CI as we do locally: we need to install NPM dependencies, start the server, and run the tests. The `.gitlab-ci.yml` file can be as simple as:

```yml
image: cypress/base:14.16.0

stages:
  - test

local-e2e:
  stage: test

  script:
    - npm ci --prefer-offline
    - npm start &
    - npx cypress run
```

**Tip:** read the Cypress on GitLab CI guide [here](https://on.cypress.io/gitlab-ci?ref=cypress-io.ghost.io)

To speed up the installation of NPM dependencies on every CI run, we should preserve both the downloaded NPM modules folder and the Cypress binary folder. By default, NPM caches its downloaded modules in `~/.npm` folder, and Cypress [caches](https://on.cypress.io/caching?ref=cypress-io.ghost.io) its binary in the `~/.cache` folder. But the GitLab CI can only cache the folders local to its local working folder. Thus let's tell NPM and Cypress to use the folders relative to the current working folder.

```yml
image: cypress/base:14.16.0

# to cache both npm modules and Cypress binary we use environment variables
# to point at the folders we can list as paths in "cache" job settings
# see the Node caching advice for GitLab CI
# https://docs.gitlab.com/ee/ci/caching/#cache-nodejs-dependencies
# see Cypress caching documentation at
# https://on.cypress.io/caching
variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"

stages:
  - test

local-e2e:
  stage: test

  cache:
    paths:
      - .npm
      - cache/Cypress

  script:
    - npm ci --prefer-offline
    - npm start &
    - npx cypress run
```

Every CI run should be faster from now on, as it reuses the previous install.

## The GitLab Pages

Let's build the HTML site and deploy it to [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/?ref=cypress-io.ghost.io). Our GitLab CI file will use another job to build and deploy; this job will run during the "deploy" stage, which automatically executes after the "test" stage successfully finishes.

```yml
image: cypress/base:14.16.0

stages:
  - test
  - deploy

# to cache both npm modules and Cypress binary we use environment variables
# to point at the folders we can list as paths in "cache" job settings
# see the Node caching advice for GitLab CI
# https://docs.gitlab.com/ee/ci/caching/#cache-nodejs-dependencies
# see Cypress caching documentation at
# https://on.cypress.io/caching
variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"

local-e2e:
  stage: test

  cache:
    paths:
      - .npm
      - cache/Cypress

  script:
    - npm ci --prefer-offline
    - npm start &
    - npx cypress run

pages:
  # this job will deploy the built site to GitLab Pages
  # https://docs.gitlab.com/ee/user/project/pages/
  stage: deploy

  cache:
    paths:
      - .npm
      - cache/Cypress

  script:
    - npm ci --prefer-offline
    # build the static site for publishing
    - npm run docs:build

  artifacts:
    paths:
      # folder to be deployed
      - public

  # NOTE: only deploy from the main branch, otherwise
  # ANY branch will deploy, overwriting the page
  only:
    - main
```

You can find the deployed site at [](https://bahmutov.gitlab.io/gitlab-pages-example/?ref=cypress-io.ghost.io)[https://bahmutov.gitlab.io/gitlab-pages-example/](https://bahmutov.gitlab.io/gitlab-pages-example/?ref=cypress-io.ghost.io).

The deployed site

## Testing the deployed site

Every major transformation like building and deploying the site can break it; it could be the domain name, it could be the links, etc. Even though we have tested the site locally, we should also run all tests or some smoke tests against the deployed site. GitLab CI allows to run the tests against the deployed site during the "confidence-check" stage which automatically runs after the "deploy" stage successfully finishes and the site has been deployed.

```yml
image: cypress/base:14.16.0

stages:
  - test
  - deploy
  - confidence-check

# to cache both npm modules and Cypress binary we use environment variables
# to point at the folders we can list as paths in "cache" job settings
# see the Node caching advice for GitLab CI
# https://docs.gitlab.com/ee/ci/caching/#cache-nodejs-dependencies
# see Cypress caching documentation at
# https://on.cypress.io/caching
variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"

local-e2e:
  stage: test

  cache:
    paths:
      - .npm
      - cache/Cypress

  script:
    - npm ci --prefer-offline
    - npm start &
    - npx cypress run

pages:
  # this job will deploy the built site to GitLab Pages
  # https://docs.gitlab.com/ee/user/project/pages/
  stage: deploy

  cache:
    paths:
      - .npm
      - cache/Cypress

  script:
    - npm ci --prefer-offline
    # build the static site for publishing
    - npm run docs:build

  artifacts:
    paths:
      # folder to be deployed
      - public

  # NOTE: only deploy from the main branch, otherwise
  # ANY branch will deploy, overwriting the page
  only:
    - main

e2e:
  stage: confidence-check

  cache:
    paths:
      - .npm
      - cache/Cypress

  script:
    - npm ci --prefer-offline
    - npx cypress run --config baseUrl=$CI_PAGES_URL

  # NOTE: only the main branch deploys the pages
  # thus we run the E2E tests after deploy on the main branch too
  only:
    - main
```

Notice how we pass the deployed site URL to the Cypress test runner using `--config baseUrl=$CI_PAGES_URL` command line argument; it will overwrite the `baseUrl` set in the `cypress.json` file.

**Tip:** to see all available GitLab CI [environment variables](https://docs.gitlab.com/ee/ci/variables/README.html?ref=cypress-io.ghost.io#predefined-cicd-variables) I use the [print-env](https://github.com/bahmutov/print-env?ref=cypress-io.ghost.io) module like this:

```
# prints all environment variables that start with CI_
- npx @bahmutov/print-env CI_
```

Here is the GitLab pipeline as it runs the tests, deploys the built site, and then tests the deploy.

The GitLab CI pipeline runs with test, deploy, and confidence check stages

## Recording test runs

If the Cypress test fails, the screenshots and videos would offer tremendous help in debugging the failure. We can store the produced test artifacts on GitLab CI, but recording the test results on the [Cypress Dashboard](https://on.cypress.io/dashboard-introduction?ref=cypress-io.ghost.io) is much, much simpler to set up and use.

To record on the Dashboard we need to set the `CYPRESS_RECORD_KEY` environment variable (keep it secret!) through the GitLab CI settings page.

Pass the Cypress record key via an environment variable

We also add the `--record` parameter when calling Cypress from the CI script

```yml
local-e2e:
  ...
  - npx cypress run --record --tag local
 
e2e:
  ...
  - npx cypress run --record --config baseUrl=$CI_PAGES_URL --tag production
```

Every pull request runs the local E2E tests, and once merged to the `main` branch and deployed, the tests run against the "production" site. You can see the tagged run results on the project's public Dashboard page [here](https://dashboard.cypress.io/projects/5qpjcx?ref=cypress-io.ghost.io).

Project's Cypress Dashboard page shows the latest runs

**Tip:** to get even more from Cypress tests, add the [Cypress GitLab integration](https://on.cypress.io/gitlab-integration?ref=cypress-io.ghost.io) to your project.

## See also

-   find the full source code for this blog post at [](https://gitlab.com/bahmutov/gitlab-pages-example?ref=cypress-io.ghost.io)[gitlab.com/bahmutov/gitlab-pages-example](https://gitlab.com/bahmutov/gitlab-pages-example?ref=cypress-io.ghost.io)
-   consult the Cypress [GitLab CI](https://on.cypress.io/gitlab-ci?ref=cypress-io.ghost.io) guide
-   read the [Show Code Coverage on GitLab CI](https://www.cypress.io/blog/2019/10/22/show-code-coverage-on-gitlab-ci/?ref=cypress-io.ghost.io) blog post
-   if you are using GitHub Pages instead of GitLab Pages, read the [Triple Tested Static Site Deployed to GitHub Pages Using GitHub Actions](https://glebbahmutov.com/blog/triple-tested/?ref=cypress-io.ghost.io) blog post