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":
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.
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!
Then you just add a cypress command for cleanup:
And use it in the test like this:
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:
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!
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:
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:
Then we'll use it like this:
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)