Cypress: `within` followed by `should` permanently limits scope

Created on 8 Jul 2019  Â·  12Comments  Â·  Source: cypress-io/cypress

Current behavior:

When within is used to find and return some element within some other element and then followed by should to test the returned element, this breaks _all_ subsequent commands (all, not just in the same chain) by permanently setting the root to the aforementioned other element.

In other words, cy.get('#scope').within(() => cy.get(…)).should(…) breaks the rest of the test, because it makes it impossible to find anything outside #scope.

Desired behavior:

cy.get(…).within(() => cy.get(…)).should(…) shouldn't impact subsequent commands at all. E.g. cy.get(…) used after it should search the entire document as usual.

Steps to reproduce: (app code and test code)

<div id="foo"><p>foo</p></div>
cy.root().should('match', 'html') // passes, as it always should

cy.get('#foo')
  .within(() => cy.get('p')) // returns `#foo p`
  .should('match', 'p') // passes, but causes the scope of preceding `within` to become global

cy.root().should('match', 'html') // fails! root is still `div#foo`

_Obviously this example is contrived, it's just a minimum reproducible sample._

Versions

Cypress 3.3.2
Chrome 75.0.3770.100 (Official Build) (64-bit)
MacOS 10.14.5 (18F132)

pkdriver bug

Most helpful comment

@jennifer-shehane : Any news on this issue ?

All 12 comments

I am able to reproduce this bug with the code below.

  it('within scope', () => {
    cy.visit('https://example.cypress.io/commands/actions')

    cy.root().should('match', 'html') // passes, as it should outside a within

    cy.get('#actions').within(() => {
      cy.get('p') // returns `#foo p`
    }).should('match', 'p') // passes, from docs, should return <div#actions>

    cy.root().should('match', 'html') // fails! root is `div#actions`
  })

Any update on this bug. I am facing this issue in various places.
This is the simplest one, we are facing it everytime. When we do any search and then assert the rows return fro search results using should(have.length,X); and then trying to target next element for further testing, but it finds the new element from inside the returned rows (due to should assertions).

It would be great if we can get work around for this,

@jennifer-shehane : Any news on this issue ?

Was facing the same issue. Using the cy.get() again seems to be resetting the scope.

Also running into this, this cost us a couple hours. This is supremely unintuitive. We found that cy.get after the .should did _not_ reset the scope (we were unable to even cy.get('body') until we removed the call to cy.within(..).should(...))

Had to add command, as a temp solution

Cypress.Commands.add('tempWithin', {
  prevSubject: true
}, (subject, method) => {
  cy.wrap(subject).within(() => method())

  return cy.wrap(subject)
})

I'm seeing this in another situation... I am using .each, and Cypress isn't releasing the subject for the next get:

    cy.get('.interest-mosaic').each(($tile) => {
      cy.wrap($tile).invoke('removeAttr', 'style')
      cy.wrap($tile).should('exist').and('not.have.attr', 'style')
    })
    cy.contains('Master Topics').should('be.visible')

This results in Cypress looking for 'Master Topics' _WITHIN_ the previous subject, which is not what I want:
image

Unless I'm using each wrong?

But if I remove the whole block before cy.contains('Master Topics').should('be.visible'), everything runs fine and it looks for 'Master Topics' on the whole page instead of just within the previous subject. Maybe within and each are doing something similar behind the scenes?

@krinhorn You're encountering this issue #4921

@jennifer-shehane Aha! Thank you!

Hi,

I am facing the same issue but with a different pattern.

Cypress.Commands.add("out", { prevSubject: "element" }, (subject) => {
  return cy.get(subject).within(() => {
    return cy.get(".port-AND-OUT");
  });
});
cy.get(".parentA")
        .out()
        .should("exist");
cy.get(".parentB") --> Failed

I manage to fix it with

cy.get(".parentA")
        .out()
        .as("whatever")
        .should("exist");
cy.get(".parentB") --> Worked

The code for this is done in cypress-io/cypress#8699, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

Released in 5.4.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v5.4.0, please open a new issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brian-mann picture brian-mann  Â·  3Comments

jennifer-shehane picture jennifer-shehane  Â·  3Comments

EirikBirkeland picture EirikBirkeland  Â·  3Comments

carloscheddar picture carloscheddar  Â·  3Comments

dkreft picture dkreft  Â·  3Comments