cy.get return invalid jquery element

I'm not quite sure what you are looking for at this stage, but have found a way to reset the effect of the zepto library.

To summarize,

  • zepto is a jquery-compatible library that takes over the $ global on your app window ref

    $ = function(selector, context) {
    return zepto.init(selector, context)
    }

  • the result is that cy commands like .get() and .wrap() yield a zepto-wrapped form of the jquery result that's not compatible with chai expect() without some destructuring.

Experimenting with Cypress.$ I found this is still referencing jquery propper, for example

const h2 = Cypress.$('h2')

returns a jquery object not a zepto object, so we can reset the app global $ from Cypress.$.

it('title display', () => {

  cy.visit('index.html')  // zepto takes effect here

  // Reset $
  const win = cy.state('window');
  win.$ = Cypress.$;

  cy.get('h2')
    .should($el => {
      expect($el).to.have.text('dress')  // passes
    })
})

The reset code could be incorporated into an overwrite of the cy.visit() command to make it less pervasive.

Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
  return originalFn(url, options).then(_ => {
    const win = cy.state('window')
    win.$ = Cypress.$
  })
})
...

it('title display', () => {

  cy.visit('index.html')

  cy.get('h2')
    .should($el => {
      expect($el).to.have.text('dress')  // passes
    })
})

NOTE This affects the way zepto works in the app.


Work around that leaves Zepto functional

This version of the cy.visit() overwrite will leave the Zepto library functional, but allow Cypress to .should() to receive the correct jQuery object.

Essentially we add our own proxy (on top of zepto's proxy) and examine the type of the selector on each call.

Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
  return originalFn(url, options).then(_ => {
    const win = cy.state('window')
    const zepto_$ = win.$;
    win.$ = function(selector, context) {
      return typeof selector === 'string' 
        ? zepto_$(selector, context) 
        : Cypress.$(selector, context);
    }
  })
})

Use this html fragment to test it. If the two logs are identical, zepto is not affected.

<body>
  <h2>dress</h2>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>

  <script>
    console.log('from app, call #1', $('h2'))
    setTimeout(() => {
      console.log('from app, call #2', $('h2'))
    }, 1000)
  </script>

</body>

I feel like using .and("contain", "dress") would solve your issue.

EDIT :

I've tried running a snippet similar to yours on my machine. Using should didn't seem to have the expected results and I encountered the same jquery weird behavior. However, when using then, it works like a charm. $el and $el[0] both return the jquery element normally

cy.get("h1.h2:first").then(($el) => {
    cy.log($el)
    cy.log($el[0])
    expect($el).to.have.text('measure')
    expect($el[0]).to.have.text('measure')
})