DEV Community

Natalia D
Natalia D

Posted on

The why and how to reset the database after each test run (Cypress, Mongo 5.0.11, React example)

Image description

As a developer, I frequently find myself working on projects that lack a dedicated testing team or resources. To minimize the amount of manual regression testing I have to do before deployment to staging, I've found that writing end-to-end (e2e) tests for the most critical scenarios is the most effective solution. My preferred tool for e2e testing is Cypress.

However, a question that often arises is: how can we ensure that each of these tests can be

  • run multiple times;
  • run independently.

That's why we need a way to reset the database after each test.

My approach is based on Gleb Bahmutov's post. The difference is that this post is for mongo 5.0.11, and his post is for older mongo versions.

Another difference from Gleb's post is that all the tests I'll talk about will be about app entry flows: Sign up, Log in and Logged in tests.

Let's consider a following example (repository is here)

Btw Cypress recommends to clean up database before each test. I wrote "after" in the post header only for SEO purposes.

Sign up Test

You have written a test for sign up scenario. First time test passed. You try to run the test again and get an error "Email address already exists":

Image description

You might want to skip what I've written below and just take a look to branch feature-cypress-reset in the repository instead. There you will see a signup test that can be run an indefinite amount of times.

File cypress/support/db.js helps to connect to the database.

Image description

If you are a frontend, you don't have to worry much about refactoring this file. Devops that will convert your PR into working version will change uri and client.db("rests") to something that works for your company. They will set up a separate testing environment that includes a test database. This test environment will allow run tests without the fear of damaging or corrupting important data in the production system.

The most interesting file to look at is cypress.config.ts. I spent some time trying to understand why await users.remove({}) doesn't work before I realised that it was deprecated in newer mongo and replaced with deleteMany!

Image description

Then you just add a cypress command for cleanup:

Image description

And use it in the test like this:

Image description

Login Test

When I've started to write tests for logged in users, I've discovered that Cypress doesn't like tests that take too much time to run. If test takes too much time, Cypress can throw one of the following errors (there are GitHub issues about that - first, second):

  • abort test running with some message about web sockets;
  • abort typing into form fields, e.g. instead of typing "somebody@gmail.com" type "somebody@gma".

The best thing is you can do for such tests is to use shortcuts. E.g. instead if imitating user login by typing values into forms, send a POST request using Cypress command. Or change a database record directly using Cypress task.
Also, this setting might help:

Image description

Cypress suggests to do session switching inside tests but we don't use it. Sadly I don't remember any details about why it wasn't useful for our current project.

Let's say you want to test login flow. You'll need to have a user in your DB before the test!

Image description

Image description

Image description

You might wonder how I got an encrypted version for password that I decided to use. I temporarily put in app.js the following code:

Image description

Logged in Test

Let's say we want to test something for a logged in user. We will use a shortcut for logging in, as it is advised in Cypress docs:

Image description

Then we'll use it like this:

Image description

Conclusion

I would like to tell more about Cypress but this post is too long already :( The only thing that I would like to mention (again) is that if you are a dev who worries about QA but doesn't have much time for it Cypress is definitely the best choice based on the ratio how much time you spend writing/maintaining tests vs how much functionality you get tested.

Top comments (0)