DRY = Don’t repeat yourself
End-to-end tests can sometimes be repetitive. Although you may try your best at keeping number of your tests at an optimal level, there are cases when you cannot avoid repeating yourself.
Take an example here. We will be testing Slido admin interface. Slido provides users with the ability to moderate participant questions on live event. Approved questions are displayed on present view for the audience to see. There are various types of question filters, and all of them have their own sorting:
If we want to test sorting of each question category, in each test will consist of:
- opening the dropdown
- choosing sort type
- asserting a change in order of questions
Step 3 will be different every time, but first two steps will be painfully similar across tests. If we aim to cover all sorting types, we need to repeat those in 11 tests. That’s too much repetition.
Personally, I prefer readability over minimalism, so I don’t mind when tests are repetitive sometimes. There are cases though, where repetitiveness gets in the way of readability.
Cypress gives us the ability to create a custom command, which can group all the repetitive parts into one simple line. We end up something like this:
Since these are normally used in only few of my tests, I keep them in a separate folder, and add them to my tests using
import method. Giving a good name to the custom command can improve readability of your test.
Let’s go back to our example.
As we can see, sorting appears in each question category (Incoming, Live, Starred, Archived). There are two menus that do the sorting, one being on left panel (Incoming), other being on right panel (Live, Starred, Archived).
In tests, we want to create a setup for our test, and then click on the filter to see sorting of questions change. Clicking on filter in a dropdown menu is the repetitive part, which we can hide in a custom command that looks like this:
To make this custom command more versatile, we have added two arguments. One being the desired type of order (Top, Oldest, Recent) and one for the type of questions (Incoming, Live, Starred, Archived).
Desired ordering type is resolved by
cy.contains() command, which selects an element according to text and then clicks on it. This allows us to target the exact type of ordering we need for each test.
Second argument helps us resolve the existence of two separate menus, one being on each panel. Since we will mostly be using right panel, we can default to that one and add an argument only when it is necessary. Using this command in tests looks like this:
This allows us to use them both in same test, while saving a lot of space across 11 tests.
We can, of course, go crazy and use a custom command for handling more complicated logic, but in that case I strongly advise to examine value of such approach. Then again, if it works for you, go ahead.
Are you using custom commands in Cypress? Do you use them for complex logic? Let me know in comments, I bet we can learn something from each other.
EDIT: You can also add your custom commands to “cy” object for intellisense. That way you can not only keep your code clean, but write it faster. Thanks for the tip Gleb Bahmutov 👍
EDIT #2: While I do like the idea of DRY, I don’t think it is a silver bullet. Sometimes, you may want to repeat yourself in order to make your test more readable. Kent C. Dodds wrote a great blog about AHA programming, a concept that really makes sense in my opinion, if you want to write good tests.
If you liked this article, you’re going to love my new course on Cypress.io. It’s called test automation for people in a hurry, and it is exactly what you’d expect. A compact, fast and straight-to-the-point course with lots of practical examples and challenges. Click on this link to check it out!