Send With Confidence
Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.
Time to read: 9 minutes
cypress.json
file is where you can set all the configuration for your Cypress tests such as base timeouts for your Cypress commands, environment variables, and other properties.
{ timeout: timeoutInMs }
throughout your Cypress commands. Tinker with the numbers until you find the right balance for settings such as “defaultCommandTimeout,” “requestTimeout,” and “responseTimeout.”cy.task(‘someTaskPluginFunction)
, Cypress.env(‘someEnvVariable’)
, or cy.customCommand()
).
cypress.json
file and loading up a separate Cypress configuration file for each test environment, such as a staging.json
when you run different Cypress scripts in your package.json
. The Cypress documentation does a great job of walking you through this approach.
cypress
folder with a guided structure when you first start up Cypress in your codebase. This includes other folders such as integration
for your spec files, fixtures
for JSON data files, plugins
for your cy.task(...)
functions and other configuration, and a support
folder for your custom commands and types.
pages
folder partitioned by feature name such as “SenderAuthentication” to hold all the page objects underneath the /settings/sender_auth
route such as “DomainAuthentication” (/settings/sender_auth/domains/**/*) and “LinkBranding” (/settings/sender_auth/links/**/*). In our plugins
folder, we also did the same thing with organizing all the cy.task(...)
plugin files for a certain feature or page in the same folder for Sender Authentication, and we followed the same approach for our integration
folder for the spec files. We’ve scaled our tests to hundreds of spec files, page objects, plugins, and other files in one of our codebases—and it’s easy and convenient to navigate through.
cypress
folder.
integration
folder (where all your specs live) is potentially splitting up spec files based on the test’s priority. For example, you may have all the highest priority and value tests in a “P1” folder and the second priority tests in a “P2” folder so you can easily run all the “P1” tests by setting the --spec
option like --spec ‘cypress/integration/P1/**/*’
.
--spec ‘cypress/integration/SomePage/**/*’
, but also by some other criteria like priority, product, or environment.
hooks.ts
file that manages and exports an object with a readable key name for the element and the actual string CSS selector for the element as the value. We will call these the “Read Selectors” as we need to read and use the CSS selector form for an element in calls such as Enzyme’s wrapper.find(“[data-hook=’selector’]”)
in our unit tests or Cypress’s cy.get(“[data-hook=’selector’]”)
in our page objects. These calls would then look cleaner like wrapper.find(Selectors.someElement)
or cy.get(Selectors.someElement)
.
{ “data-hook”: “selector” }
as the value. We will call these the “Write Selectors” as we need to write or spread these objects onto a React component as props to successfully add the “data-hook” attribute to the underlying elements. The goal would be to do something like this
and the actual DOM element underneath—assuming props are passed down to the JSX elements correctly—will also have the “data-hook=” attribute set.
[data-hook=”selector”]
CSS selector string for each element name. If a key’s corresponding value is null
, we’ll assume the element name in the input object will be the same as the “data-hook” value such as { someElement: null } => { someElement: ‘[data-hook=”someElement”] }
. Otherwise, if a key’s corresponding value is not null, we can choose to override that “data-hook” value such as { someElement: “newSelector” } => { someElement: ‘[data-hook=”newSelector”]’ }
.
{ “data-hook”: “selector” }
objects for each element name. If a key’s corresponding value is null
, we’ll assume the element name in the input object will be the same as the “data-hook” value such as { someElement: null } => { someElement: { “data-hook”: “someElement” } }
. Otherwise, if a key’s corresponding value is not null
, we can choose to override that “data-hook” value such as { someElement: “newSelector” } => { someElement: { “data-hook”: “newSelector” }’ }
.
Selectors.unknownElement
or WriteSelectors.unknownElement
in our TypeScript files as well. Before exporting our read selectors, we also allow adding extra element and CSS selector mappings for third-party components that we do not have control over. In some cases, we cannot add a “data-hook” attribute to certain elements, so we still need to select by other attributes, ids, and classes and add more properties to the read selector object as shown below.
cypress.json
such as “defaultCommandTimeout” and “responseTimeout”. We would go back and adjust certain pages that needed longer timeouts, but then over time, the number of arbitrary timeout values grew and maintaining it became harder for large scale changes.
cy.get(...)
or cy.contains(...)
. Beyond that default timeout, we would scale up to “short”, “medium”, “long”, “xlong”, and “xxlong” within a timeout object we can import anywhere in our files to use in our Cypress commands such as cy.get(“someElement”, { timeout: timeouts.short })
or cy.task(‘pluginName’, {}, { timeout: timeouts.xlong })
. After replacing our timeouts with these values from our imported object, we have one place to update to scale up or scale down the time it takes for certain timeouts.
Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.