DEV Community

Preston Lamb
Preston Lamb

Posted on • Originally published at prestonlamb.com on

Shared Cypress Assets in an Nx Workspace

tldr;

Many times Nx workspaces have multiple applications, and being able to share custom Cypress commands between the end to end test projects. I spent several months manually copying these commands between the different projects, and would inevitably forget to update one when a change was made. Finally I decided to solve the problem and find a way to share the Cypress assets among the projects. This article will cover one way to do this.

To follow along, you'll need an Nx workspace with at least one end to end project.

Create the Shared Assets Library

Let's get started by creating a shared end to end assets library. This will be similar to creating any other library in an Nx workspace. The only potential difference will be the type of library you create. Nx provides a way to create Angular specific libraries, for example. In this case, we don't want to create a framework specific library. That can be accomplished with the following command:

$ nx g @nrwl/workspace:library e2e-assets --directory shared
Enter fullscreen mode Exit fullscreen mode

This command creates a generic Nx workspace library called e2e-assets and puts it in the libs/shared directory. In this library we'll add custom Cypress commands which we can then use in all our end to end projects.

Create Custom Command File

Let's now add a file that contains a custom Cypress command in our new shared library. This custom command will make it easier to select elements by the data-cy HTML attribute. Create a file in the e2e-assets/src/lib folder called data-cy.commands.ts. Here are the contents of that file:

// data-cy.commands.ts

// load the global Cypress types
/// <reference types="cypress" />

declare namespace Cypress {
  interface Chainable {
    /**
     * Custom command to get elements by data-cy attribute.
     * @example cy.dataCy('greeting')
     */
    dataCy(selector: string): Chainable<Element>;
  }
}

Cypress.Commands.add('dataCy', (value) => cy.get(`[data-cy=${value}]`));
Enter fullscreen mode Exit fullscreen mode

The first two lines of the file load the types for Cypress and prevent errors from showing in your IDE. The next portion of the file essentially extends the Cypress object for your tests by declaring the new custom command. If you leave this out and try to use the dataCy command you will get an error and the command will not work. The last line of the file is the code to actually add the custom command. The first argument to the Cypress.Commands.add method is the name of the new command, and the second argument is a callback function that provides the functionality for the custom command.

This custom command returns the cy.get method and selects an element by the data-cy HTML attribute. We'll look at how it's used later.

Importing the Custom Command

The next step is to import the new custom command so it can be used in our Cypress tests. The first import belongs in the e2e-assets/src/index.ts file:

// e2e-assets/src/index.ts

import './lib/data-cy.commands';
Enter fullscreen mode Exit fullscreen mode

This makes the new command available when we import this library into our Cypress tests, which we'll do next. The second import belongs in the app-e2e/src/support/index.ts file. By importing the library here, this new command will be available in the app-e2e Cypress tests.

// app-e2e/src/support/index.ts
import '@my-org/shared/e2e-assets';
Enter fullscreen mode Exit fullscreen mode

Now that you have imported your shared e2e assets library, you can use the new command.

Using The New Custom Command

Here's an example of using the new custom command in a Cypress test:

// app-e2e/src/integration/test.ts

it('should show the homepage', () => {
  cy.dataCy('homepage').should('be.visible');
});
Enter fullscreen mode Exit fullscreen mode

If you didn't use this custom command, your test would like this:

// app-e2e/src/integration/test.ts

it('should show the homepage', () => {
  cy.get('[data-cy=homepage]').should('be.visible');
});
Enter fullscreen mode Exit fullscreen mode

There's not a big difference here, but speaking from experience it gets tiresome to repeat the attribute selector each time you need access to an element based on the data-cy attribute. This simple custom command is much easier to use.

Conclusion

One of the biggest benefits of Nx workspaces is the ability to share code between projects. It's natural to share code between Angular or React apps, but the same process can be used to share code for your Cypress end to end tests. It becomes especially useful the more apps you have in your workspace, and for more complicated Cypress commands

Discussion (0)