A Cypress Developer’s Cheat Sheet
Notes and thoughts on how to design and set up a clean and reusable Cypress package structure

For those who want another article saying that Cypress will kill Selenium, this is not the intention of this piece. Instead, the idea is to share the experience of using Cypress on a complex web application and to show a package structure that worked really well for this scenario.
To begin with, let’s understand the direction Cypress is going by doing a quick Google Trends search on the Cypress tests keyword:

We can see that since Cypress was created in 2014, the interest around it skyrocketed after it went public beta in 2017.
Also in April 2019, it was promoted to ADOPT on Thoughtworks Technology Radar, indicating that the direction Cypress is heading is indeed a bright one.

Page Objects
When we start writing tests with Cypress, the first discussion that is brought to the table is a classic one: Use Page Objects or not? The Cypress guys have their say on that: Can-I-use-the-Page-Object-Pattern: “‘Page Object Pattern’ should really be renamed to: ‘Using functions and creating custom commands’.”
So we will take this direction in the article:

TypeScript
The second discussion comes down to: Should we use TypeScript?

This one sometimes is a matter of personal opinion. The way I usually go is to ask two questions:
- Is the application we plan to test complex? 10+ UI’s (or states within the UI), 10+ API calls, 10+ components, etc.
- Are the engineers who will write the code familiar with TypeScript?
If you say yes to either of those questions, then you probably want to go with it; otherwise, don’t overengineer it.

Just choose what fits your use case better, either standardizing your codebase or having more flexibility. If you go with TypeScript, it’s actually really easy to set it up with Cypress.
In this case, we picked standardizing. If you want the steps to configure TypeScript, please follow the Cypress official guide.
A Clean Package Structure
The proposed folders and files are presented below:

The integration, support, plugins, and fixtures folders come out of the box with Cypress. The new structure in our case is the pages_data and functions folder. they will take the role of the well-known page objects.
Did you notice the pizza word in the diagram above? That’s because we’ll be using the Angular Pizza Creator app.

Everyone loves pizza, right?
Let’s go back to the package structure explanation.
pages_data
The idea here is to not confuse it with the classical implementation of page objects, but you could name it virtually anything. Let’s see some code to understand better this class role:
We’re mainly using it to store the page elements selectors, but did you notice the APIs attribute?
Cypress has an amazing feature of stubbing network requests, and most of your UI tests should be leveraging this. In the Pizza application we only have one API call to showcase the structure, but let’s give some food for thought.
Imagine a fictional scenario, where you have more than ten API calls, and you have some CRUD capabilities, which calls the APIs with different HTTP verbs, GET/POST/PUT/DELETE. You can easily get to more than 50 JSON payloads that you will have to maintain, and, trust me, this can easily get messy.
So how do you organize it in a way that makes your life easier?
Let’s dig into the API’s attributes. Each API represents a StubbedAPI, and as you could see in the PizzaOrderPageData class, we have different API files for each context. In this case, we called them: view, edit, remove and create.

The StubbedAPI points to the response that will be returned. This way, it’s easier to understand the scenario and the page that the API call belongs to.
Here’s an example of one of the API files, used by the PizzaOrderPageData class:
One time we had one web application that consumed APIs using alpha versions. When we flipped from alpha to beta, there were major breaking changes, and this structure was really helpful in making those changes.
functions
Do you remember that statement from the Cypress guys, saying Page Objects should really be renamed to “Using functions and creating custom commands”?
So that’s the idea here. This functions layer main goal is reusing code needed to interact with the UI.

You might be asking yourself, “What’s the difference between this and using the classic Page Object pattern?”
There are so many interactions, components, events, and user roles within one UI, that it’s really hard to abstract all that into one Page Object.
So the difference here is that we are splitting the elements selectors from the functions, and by doing that we can try to get the best of both worlds. And please don’t create functions for every UI behavior; otherwise, we are doing the same as the Page Object. Only start creating functions for your spec file when you start repeating yourself.
Also, by using this standardized structure, we can create common functions like this:
Integration spec file
Now let’s take a look at what became of the pizza-order.spec:
If you want the full code, please go to this Github repo. You can also find there the plantuml files used to build the diagrams.
Closing Thoughts
In this piece, we have covered how to create a clean and reusable Cypress package structure, and we used the Angular Pizza Creator Application to showcase the code needed to implement it. We also covered how to work with TypeScript and organize your page selectors and API calls. Hopefully, next time you use Cypress, this will help you get started.
Thank you for your time! And stay tuned for the next piece, where we will add JSON snapshot tests to this structure so we can improve the confidence of our Stubbed API calls. Cheers!
Resources
- Github Repo with the code: https://github.com/mesmacosta/angular-pizza-creator-cypress
- Angular Pizza Creator APP: https://github.com/mesmacosta/angular-pizza-creator
- Thoughtworks tech radar: https://www.thoughtworks.com/radar/tools/cypress
- Cypress Page Objects: https://docs.cypress.io/faq/questions/using-cypress-faq.html#Can-I-use-the-Page-Object-pattern
- Cypress TypeScript config: https://docs.cypress.io/guides/tooling/typescript-support.html#Additional-information
- Cypress Network Requests Stubbing: https://docs.cypress.io/guides/guides/network-requests.html#Stubbing
