Adding End to End Cypress to a Web Project Part 3: Getting Set Up with Cypress & Seeding the Database Between Tests

In part one of this series, we covered using Docker to set up test instances for the external dependencies of the project. Part two covered creation of scripts to clear and re-seed the database. This post will cover the basics of getting Cypress installed and ready to go, writing a placeholder test, and resetting the test database between tests.

Getting Setup with Cypress

For starters, we added cypress to our project by following the setup instructions for cypress.

We also installed the start-server-and-test npm module. This module provides a command start-server-and-tests that lets us start the server, wait for a server URL to respond, and then run the tests once the server is ready. We added a script to our package.json file to point our server to the test database, wait for it to start, and then run the cypress tests against the server:

   "cy:test": "DATABASE_HOST=localhost DATABASE_PORT=5433 start-server-and-test cy:start http://localhost:8082 cy:open"

Writing the First Test

Per the Cypress docs, we created test_spec.js file in the cypress/integration file and added a command to go to the home page:


describe('adding our first cypress test!', () => {
    it('first test!'), () => {
        cy.visit('/')
    })
})

We now have one test that brings the user to the home page.  But, as there isn’t any data in the system, there isn’t much to see on the home page yet.

Seeding the Test Database

Let’s put some data into the test database.

In the last post, we created a script to clear and re-seed the test database. All we need to do is invoke this script before each test run.

There is a Cypress task plugin that lets us execute code in node.  We created a db:seed task and used it to invoke our test database seeding script.

In the test, we invoked the seed task like this (db:seed is the name of the task and “default” is a parameter we pass to the task):


describe('adding our first cypress test!', () => {
    it('first test!'), () => {
        cy.task('db:seed', 'default')
        cy.visit('/')
    })
})

Then, in the Cypress plugins file, we added a handler for the db:seed task:

  on('task', {
    'db:seed': async scenarioName => {
      return new Promise((resolve, reject) => {
        const seedProcess = spawn('bash', ['cypress/data-setup/seed_db.sh'])

        seedProcess.stdout.on('data', data => {
          console.log(`stdout: ${data}`)
        })

        seedProcess.stderr.on('data', data => {
          console.error(`db:seed: ${data}`)
        })

        seedProcess.on('close', code => {
          if (code === 0) {
            resolve(true)
          } else {
            reject(`db:seed child process exited with code ${code}`)
          }
        })
      })
    }
  })

The task plugin can return a value or a promise. We’ll make it return a promise.  In the promise, we’ll use the node task handler uses spawn to asynchronously spawn a child process. The child process executes the seeding script via Bash.

We wait for the child process to finish; then, on successful completion of the seed promise, we invoke the resolve callback.  Otherwise — on error — we invoke the reject callback.

In this example, we always invoke the same seed script in bash for each test as we are not using the “scenarioName” argument at all.  If we needed different data setups for different tests, we could invoke the data setup scripts based on the “scenarioName.”

Now we are clearing and seeding the test database for each test before executing any test steps. That means there is content available when we navigate to the home page!

In the next post, we’ll go over the setup needed to get the Cypress tests running in CI.

Conversation
  • Khalid says:

    Hi,

    Thank you Lydia: great work !.

  • Comments are closed.