Odd behavior with `cy.get` with promises and jQuery DOM elements
See original GitHub issue- Operating System: Windows 10
- Cypress Version: 2.1.0 Beta
- Browser Version: Chrome 64
Is this a Feature or Bug?
I assume it is a bug? Unless my understanding of JS promises completely fails me.
Current behavior:
I’m trying to use cypress and have run into an issue which I could not explain. I’m using cy.get().contains()
and working on the result with chained promises (using a simple .then()
), e.g.
cy.get('some selector').contains('some text').then(el => console.log(el));
So far so good, the element gets printed to the console, or rather the jQuery wrapper around it. Now I need to access the ownerDocument
property of the element. Since this is a jQuery wrapper around a single element, I need to access its first element through array subscript 0 (even though the Cypress docs state that contains()
returns a single DOM element – ».contains()
yields the new DOM element it found.«):
cy.get('some selector').contains('some text').then(el => console.log(el[0].ownerDocument));
Still dandy (el.ownerDocument
would not work).
But since we are all striving to have reusable and composable code it would make perfect sense to move the array access out of the actual logic:
cy.get('some selector').contains('some text')
.then(els => els[0])
.then(el => console.log(el.ownerDocument));
But this does not work! el.ownerDocument
is undefined (el[0].ownerDocument
is defined though). Logging el alone (console.log(el)
) will log the jQuery wrapper, not the DOM element itself as I would expect. What gives? Why is this behaving so strangely? It looks like the result of my first then
is ignored (if I comment the line, I get no change in behavior).
Desired behavior:
Results from promises should be fed as input into chained promises.
How to reproduce:
Test code:
cy.get('some selector').contains('some text')
.then(els => els[0])
.then(el => {
console.log(el);
console.log(el[0]);
});
edited replaced TS code with JS code
Issue Analytics
- State:
- Created 5 years ago
- Comments:8 (4 by maintainers)
Top GitHub Comments
As for cypress yielding a
jquery
instance after a.eq(..)
this is normal and inline with how the rest of our apis work in relation to jquery. (in jquery,.eq(0)
still returns you ajquery
instance).@efdknittlfrank @raduflp however, you are rightfully confused about chaining
.then
’s resulting in the subject being re-wrapped. This is unfortunately expected behavior, albiet not optimal for composability and predictability for users looking to extend cypress.Basically, a
cypress
.then
is just like a promise, but checks the subject right before yielding it to you, and if it’s a dom element, it wraps it in jquerythe reason we do this is so that users can use
cy.wrap
with regular dom elements, and cypress commands, expecting a jquery instance, can use themthis will likely change in a future major version of cypress, as we understand this is confusing behavior
for now, you’ll have to do what @efdknittlfrank mentioned above
or you could try the following, that will use a real promise:
tl;dr: Basically, a
cypress
.then
is just like a promise, but checks the subject right before yielding it to you, and if it’s a dom element, it wraps it in jquery@efdknittlfrank did you ever managed to find a solution?
@Bkucera it doesn’t look like its related to TS or a specific selectors. It looks like regardless of what it is returned from
eq
,first
,then
etc, it will always wrap the returned value in jQuery before passing it on.I set up a new project with this minimal test to confirm the behavior
so basically even if you chain
eq(0)
later you still have to doel[0]
.In case of
eq
this behavior is consistent with the TS typing: Chainable<JQuery<E>>
but it is not consistent with the docscould you confirm that this is the expected behavior?