Cypress Tip: In-Spec Functions

Cypress Tip: In-Spec Functions

·

3 min read

Let's imagine you have a bunch of repeatable code in your Cypress tests:

it('should do this thing', () => {
  // ...
  cy.get('#thisElement')
    .then($el => {
      // some unusual hackery here
    })
  // ...
})
it('should do that thing', () => {
  // ...
  cy.get('#thatElement')
    .then($el => {
      // some unusual hackery here
    })
  // ...
})
it('should do another thing', () => {
  // ...
  cy.get('#anotherElement')
    .then($el => {
      // some unusual hackery here
    })
  // ...
})

What a mess, right? You might be tempted to immediately break this out into a custom command...

it('should do this thing', () => {
  // ...
  cy.get('#thisElement')
    .doSomething()
  // ...
})

...but it's not necessarily the best solution for a number of reasons. The alternative? I'm calling it an in-spec function. It's an abstraction in the form of a hoisted function contained in the spec file:

describe('some feature', () => {
  it('should do this thing', () => {
    // ...
    cy.get('#thisElement')
      .then(doSomething)
    // ...
  })
    // ...
})
function doSomething($el) {
  // some unusual hackery here
}

Here's why you might want to use an in-spec function:

  1. Like an abstraction into a custom command, this will make your tests much easier to reason about, but if it's only required in a single spec, why bother with a command when you can use plain JavaScript?

  2. It's hoisted from the bottom so that it's out of the way, but because it's in the spec, it's easier to access in the event you need to debug, update or refactor it.

  3. If you need this function outside the spec, it's likely easier to prototype it as an in-spec function first. Then when it's working the way you want, you can convert it to a command.