Two weeks ago, Cypress was open-sourced and made available to everyone.
Cypress is a tool, that (allegedly) lets you write your end to end tests faster, and with minimum to none setup.
Fast, easy and reliable testing for anything that runs in a browser.
Let’s give it a try and verify if that’s true!
We will integrate Cypress with one of our projects — Eedi. Eedi is a fantastic educational platform for UK teachers, students and their parents. It is crucial, that anyone who uses it, have nice and smooth experience while browsing, and that all works as expected.
Inside our application root folder, let’s add Cypress as a dev dependecy:
<rte-code>$ yarn add --dev cypress<rte-code>
Adjust the <rte-code>"scripts"<rte-code> entry in <rte-code>package.json<rte-code>:
Run your server locally, just like when normally developing, and then, in new terminal window lets open Cypress:
<rte-code>$ yarn run cypress:open<rte-code>
After a while, Cypress should open and we should see a window pop up.
Here we have access to all our tests, there’s even one provided out of the box!
Cypress have created new directory <rte-code>cypress<rte-code> with subfolders <rte-code>fixtures<rte-code>, integration and <rte-code>support<rte-code>. It also added empty <rte-code>cypress.json<rte-code> config file.
Since we will be accessing our root path often, it’s a good practice to abstract it to settings file. Open <rte-code>cypress.json<rte-code> file, and add an new entry with key <rte-code>baseUrl<rte-code> and url as a value:
In the <rte-code>example_spec.js<rte-code> file we can see ‘Kitchen Sink Tests’ that can come in handy when we want to browse some common testing scenarios. But let us write our own tests for now.
Testing Sign In
Signing in is one of most important features of any app. If it’s done poorly, users won’t be able to see the rest of our work, and there’s no point in doing anything else.
Create a new file <rte-code>login_spec.js<rte-code>. Here we will test all our logic regarding signing in.
Let’s go, and write our first test — let’s check if happy path is working as expected:
Now, go to Cypress app and select test that we’ve just created. It should run all tests in a file, and we can watch how they perform:
At the left pane of test runner, we can see all actions performed by Cypress, elements found and redirects made by browser. We can also use nice time travel feature and inspect every single step of our tests.
Let’s brake something! Change line 12 of the test:
It fails. And that’s good, we have established that happy path is indeed happy. Cypress provides us with detailed stack trace — what went wrong and where it happened.
Add some more cases:
- unsuccessful log-in action should yield error message, and
- unauthorized user should not be able to visit restricted URLs.
After we save the test file, Cypress should re-run all tests:
Testing Sign Out
Next feature to cover is logout action. We would want to establish that user can sign out from our app correctly. Sounds easy, right?
But let’s think about it for a second… In order to log out, we need to be logged in in a first place, right? Should we reuse the code from the previous test, and then add some more logic to it? Sounds silly, we are developers, we can do better!
Cypress, comes with another handy feature — commands. They allow us to create our own custom actions that can be reused in any tests. And since most scenarios should be written for logged users, this action is perfect candidate for a custom command.
Open <rte-code>commands.js<rte-code> file located in the <rte-code>support<rte-code> folder. Cypress provides us with some examples, and there’s even a stub of a login command already there!
Enhance this login command with our custom behavior, but first let’s think about what we want to do.
We have tested logging in already, haven’t we? So there’s really no point in repeating the same steps with each and every test we will write next. We can even read in the docs:
Fully Test the Login Flow — But Only Once!
And further in same guide:
Do not use your UI to login before each test.
So what can we do?
We can make direct network request to our backend service using <rte-code>cy.request()<rte-code> to log in, and then proceed as we normally would. Here’s how it looks like:
Now, inside every test, we can call <rte-code>cy.login('username','password')<rte-code> and it should perform login action without engaging UI.
Now we are ready to test logout actions. Create <rte-code>logout_spec.js<rte-code> and add some assertions:
Watch them fail:
Then fix lines 14 and 20 <rte-code>(changefirst()<rte-code> to <rte-code>last()<rte-code> and <rte-code>cy.visit('log-out')<rte-code> to <rte-code>cy.visit('logout')`<rte-code>and watch how tests pass:
In summary — writing tests with Cypress was real fun.
As advertised, setup is close to none, writing assertions is easy and feels natural, and GUI is, well, awesome! You can time travel, debug all steps, and since it all launches as an Electron app, we can even access developer tools to learn more about each action that happens.
The web has evolved. Finally, testing has too.
Let’s all write some tests, and may the force be with you!