0

I'm quite new to cypress, but I am wondering if there is some way to end a command chain conditionally? I know that conditional testing should be avoided in cypress, but I want try this out anyway.

What I've tried

I tried to solve it by passing in the chain to a custom command, but it doesn't seem to work.

Cypress.Commands.add('ifExists', { prevSubject: true }, (subject: object, element: string) => {
    cy.get('body').then(($body) => {
        if ($body.find(element).length) {
            cy.wrap(object).end();
        } else {
            // something else
        }
    })
})

and also

Cypress.Commands.add('ifExists', { prevSubject: true }, (subject: JQuery<HTMLBodyElement>, element: string) => {
    cy.wrap(subject).then(($body) => {
        if ($body.find(element).length) {
            return cy.wrap(subject);
        } else {
            return cy.wrap(subject).end();
        }
    })
})

And just a clarification on what I want from this command. I want to be able to add it to a chain like this:

cy.get('body > #specialThing').ifExists().then((thing) => ...)

or this:

cy.ifExists('body > #specialThing').then((thing) => ...)

All help and advice is appreciated!

2 Answers2

1

I'd check out the Cypress documentation on conditional testing, in particular the part about element existence. The tl;dr is you just need to search for a more general element that yields something that you can then assert on.

y.get('body')
  .then(($body) => {
    // synchronously query from body
    // to find which element was created
    if ($body.find('#specialThing').length) {
      // input was found, do something else here
      return 'input'
    }

    // else assume it was textarea
    return 'textarea'
  })
  .then((selector) => {
    // selector is a string that represents
    // the selector we could use to find it
    cy.get(selector).type(`found the element by selector ${selector}`)
  })
agoff
  • 5,818
  • 1
  • 7
  • 20
0

You can adapt the jQuery OR operator shown here Function to check if element exist in cypress.

You cannot it call using the cy.get('body > #specialThing').ifExists()... because the cy.get() will fail if the element isn't there, so this implies your custom command must be a parent command (no prevSubject).

Cypress.Commands.add('ifExists', { prevSubject: false }, (selector: string) => {

  const orSelector = `${selector}, body`;    // note comma, if "selector" fails return body
  return Cypress.$(orSelector);

})

cy.ifExists('#specialThing').then((thing) => ...)

You may find it more useful to return null rather than body so that you can test the result more easily,

Cypress.Commands.add('ifExists', { prevSubject: false }, (selector: string) => {

  const result = Cypress.$(selector);
  return result.length ? cy.wrap(result) : null;

})

cy.ifExists('#specialThing').then((thing) => if (thing) ... else ... )

Warning this will inevitably lead to flaky tests. There is no retry in this command.

See Element existence

You cannot do conditional testing on the DOM unless you are either:

  • Server side rendering with no asynchronous JavaScript.
  • Using client side JavaScript that only ever does synchronous rendering.

It is crucial that you understand how your application works else you will write flaky tests.

Using cy.get('body').then(...) does not give you retry on the element you want to test conditionally.