And the nominees for “Best Cypress Helper” are: Utility Function, Custom Command, Custom Query, Task, and External Plugin
Tags: cypress, testing, automation, qa
Published: 2024-04-27 23:59:26

**And the Oscar goes to…**

---

### ACT 1: EXPOSITION

On numerous occasions, colleagues have come to me with a question that seems to resonate among many Cypress users: Which approach is best for reusing actions or assertions when writing tests? Should they opt for a _JavaScript Utility Function_, a _Custom Command_, perhaps a _Custom Query_, or even one of the so-called _Tasks_? What about an _External Plugin_?

This query isn’t unique to my circle; it’s a topic that even once in a while surfaces in the Cypress.io Discord community. The myriad of methods available in Cypress can be overwhelming, but this versatility is also what makes this tool so powerful.

&nbsp;  
If you’re reading this blog post in the hope of finding a definitive answer as to which Cypress helper deserves the “Oscar,” then this might be the point where you choose to stop reading and check back in my next entry. After all, when it comes to movie tastes, nothing is written in stone.

However, if you’re open to exploring some recommendations and understanding when one method might be more advantageous than another, then I believe you are be in the right place.

I had the idea that presenting a sneak peek of each Cypress Helper on a ‘single screen’ might just help you decide which one to ‘watch’ the full feature film based on your mood or needs on any given day.

My hope is that by the end of this post, you will have a stronger set of strategies to enhance your Cypress toolkit for everyday use. So get the popcorn ready and enjoy the previews. 🍿

---

### ACT 2: CONFRONTATION

In Cypress.io, the decision to use a _JavaScript Utility Function_, _Custom Command_, _Custom Query_, _Task_ or even an _External Plugin_ should depend on the specific needs of your test suite and the scope of functionality you are aiming to achieve.

So… getting to the point, in what situations can each of them lend you a better hand and save you a lot of work?

Let’s look at them one by one.

&nbsp;  
#### JavaScript Utility Function

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ug24dfwotx1eare347m.png" />
</p>

&nbsp;  

- Use _JavaScript Utility Functions_ for simple, **synchronous** operations that don’t need to interact with the Cypress command chain.

- Ideal for data transformations, calculations, or any generic JavaScript functions.

- You could define them directly in your test spec for cases where the operation is very specific to the scope of those tests, or wrap several of them in a helper file in the **`cypress/support`** folder if you plan to use them across multiple test specs.

> _There is nothing preventing you from returning a Cypress chainable object from the call to JavaScript Utility Functions, and in certain cases, it might even be quite convenient._
>
> _However, given that **the majority of JavaScript code is synchronous**, and considering that the nature of Cypress commands is asynchronous and they get queued for execution at a later time, you might want to consider using a **Custom Command** instead of a JavaScript Utility Function when returning a Cypress chainable object._

&nbsp;  
#### Custom Command

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/flq43fc4ihn0jh6k8mj9.png" />
</p>

&nbsp;  
This is when things start to get interesting…

- Use _Custom Commands_ to create reusable sets of Cypress commands that can be called as a single command.

- They are **asynchronous**, and they can return a Cypress chainable object, over which you can run assertions.

- A _Custom Command_ can: start a new Cypress chain (called a parent command), receive a previous subject and continue an existing chain (called a child command), or either start a chain or use an existing chain (called a dual command).

- Added via `Cypress.Commands.add()` and becomes part of the Cypress chainable interface. You can also overwrite existing commands using `Cypress.Commands.overwrite()`.

- They are defined in the **`cypress/support/commnads.js`** and are extremely helpful for actions performed frequently in your tests, like custom login procedures or form submissions.
- They can be reused across multiple test specs in your Cypress project.

- BE AWARE! **Custom Commands are executed once and do not have built-in retry-ability**. If you want your method to have retry-ability, it is better to use a **_Custom Query_**.

> _If you would like to dig deeper in the intricacies of Custom Commands you can visit the Cypress documentation [Custom Commands](https://docs.cypress.io/api/cypress-api/custom-commands), [Building Cypress Commands](https://learn.cypress.io/advanced-cypress-concepts/building-the-right-cypress-commands), and [Custom Cypress Command Examples](https://learn.cypress.io/real-world-examples/custom-cypress-commands)._

&nbsp;  
#### Custom Query

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkiztiw4jdlltlcvk5x6.png" />
</p>

&nbsp;  

- _Custom Queries_ were a special ‘feature film’ introduced in the Cypress series at the end of 2022, debuting in version 12.

- Use _Custom Queries_ to query the state of your application, for instance, to find elements based on custom logic or conditions not covered by [Cypress build-in queries](https://docs.cypress.io/api/table-of-contents#Queries). Examples of built-in queries include `get()`, `find()`, `filter()`, `url()`, and `window()`.

- They can be particularly useful when integrating with UI libraries or frameworks that require specific selectors or patterns to interact with their components.

- Queries are **synchronous** and can return a Cypress chainable object, over which you can also run assertions.

- _Custom Queries_ are **retry-able**, meaning they will continuously attempt to retrieve whatever you have requested until they succeed or a timeout is reached. It is important that the Custom Query callback function does not change the state of your application.

- New queries are added via `Cypress.Commands.addQuery()`, but you can overwrite an existing query using `Cypress.Commands.overwriteQuery()`.

- They are defined in the **_cypress/support/commands.js_** file and are useful when you can encapsulate complex or repeated DOM queries that you will reuse across your test framework.

- However, for repeatable behavior, it is often more efficient to write a JavaScript Utility function rather than a _Custom Query_, and after all both behave “synchronously” (by default, JavaScript is a synchronous).

- TAKE CAUTION! If your method needs to be asynchronous or only to be called once, then you should write a **_Custom Command_** instead.

- STAY ALERT ! When piecing together lengthy sequences of queries, ensure that you avoid incorporating standard Cypress commands, as their inclusion will disrupt the test’s ability to retry the full chain.

> _For more information about Custom Queries you can visit the Cypress documentation [Custom Queries](https://docs.cypress.io/api/cypress-api/custom-queries) and [Retry-ability](https://docs.cypress.io/guides/core-concepts/retry-ability#Only-queries-are-retried)._

&nbsp;  
#### Task

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmmrcyi510gxlwhoz3m7.png" />
</p>

&nbsp;  

- _Tasks_ are used for handling operations that need to be executed outside the browser context.

- They run in Node.js, executed by the Cypress process, and can be invoked from your tests using the `cy.task()` command. This bridges the gap between the Node.js server and browser-based tests, enabling a more comprehensive testing strategy.

- `Tasks` are ideal for database operations such as seeding, querying, or cleanup. They are also useful for file system interactions, such as downloading files, or any server-side feature not accessible within the browser.

- Additionally, they are great for storing state in Node that needs to persist between spec files, running parallel tasks like making multiple HTTP requests, and for executing an external process or system command.

- The _Task_ event handler can return a value or a promise. Returning undefined, or a promise resolved with undefined, will cause the command to fail.

- Tasks are typically defined in the project’s **`cypress.config.js`** file within the `setupNodeEvents()` function. Alternatively, you can define them in the project's **`cypress/plugins/index.js`** file.

> _For more information about Tasks you can visit the Cypress documentation [Tasks](https://docs.cypress.io/api/commands/task) and [Real World Example tasks](https://docs.cypress.io/guides/references/best-practices#Real-World-Example-1)._

&nbsp;  
#### External Plugin

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdi6knsa1tynhbxiopc9.png" />
</p>

&nbsp;  

- Cypress _External Plugins_ are used to extend the functionality of Cypress tests beyond the capabilities provided by the core framework.

- These plugins are typically installed via **Node Package Manager** and configured within the Cypress project to provide additional capabilities tailored to specific testing needs. They help make Cypress a more powerful and versatile tool for end-to-end testing.

- You can host your External Plugins on multiple repositories such as **GitHub** or **Bitbucket**, and distribute them publicly via the software registry **NPM** or internally within your organization via **Nexus**.

- They are extraordinarily useful when you have common tools, commands, and assertions that will be reused across multiple Cypress frameworks.

- There is a vast array of Cypress _External Plugins_ available; some are very well-maintained and supported by the Cypress community, while others… are not maintained at all.

- Therefore, be selective and critical when choosing a Cypress plugin for your application. I recommend opting for plugins that are clean, light-weighted, frequently updated, and supported by credible creators. After all, each time you load a plugin in your test or framework, you are adding time to your test run.

&nbsp; 
Some common uses for External Plugins in Cypress include:

✔️ Visual Testing (such as Applitools’ `cypress-eyes`)

✔️ Accessibility Testing (such as Andy’s `cypress-axe`, which utilizes Deque's `axe-core`).

✔️ Reporting (such as Yousaf’s `cypress-multi-reporters` for generating more informative and styled test reports)

✔️ API Testing (such as Filip’s `cypress-plugin-api`)

✔️ A Toolkit of useful extra Query Commands (such as Gleb’s `cypress-map`)

✔️ Firing native system events (such as Dmitriy’s `cypress-real-events`)

✔️ Filtering Tests (such as `@cypress/grep`)

> _For more information about available External Plugins, you can visit the Cypress documentation on [Plugins](https://docs.cypress.io/plugins) (however this list seems a little dated)._

---

### ACT3: RESOLUTION

Each of these Cypress Tools serves a different purpose and can be used in conjunction to create a robust and maintainable testing suite. So, in my opinion, ALL OF THEM truly deserve to share the “Oscar” for “Best Cypress Helper”. 🏆

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddfvpo1dzebufz2hvv7i.png" />
</p>

&nbsp;  
_JavaScript Utility Functions_, _Custom Commands_ and _Custom Queries_ are primarily about organizing code within your tests, while _Tasks_ and _External Plugins_ are for interacting with the system and environment outside the browser or for extending Cypress’s capabilities.

_Custom Commands_ can enhance the readability of your tests by tackling repetitive sets of commands at once. Similarly, _Custom Queries_ can abstract the querying logic, making the tests easier to understand at a glance.

Remember to use _Custom Commands_ and _Custom Queries_ judiciously, as each addition to your testing framework increases the maintenance overhead and can potentially introduce complexity. Keep them well-documented and ensure they provide clear value over the standard set of queries provided by Cypress.

However, I have to say that Cypress _External Plugins_ hold a special place in my 💖, and that’s why I will dedicate a full blog post to them in the future.

&nbsp;  
> _**Disclaimer**: Keanu Reeves has neither won an Oscar, Golden Globe, or Emmy, and nor even been nominated for any of these awards. Maybe in his next John Wick feature film!_ 🤞 😉

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zxzz6meip4m9p9084x6k.png" />

(Image from Marvelous Videos)

**Don't forget to leave a comment, give a thumbs up, or follow my Cypress blog if you found this post useful.**

Happy reading!