Cypress: Add Iframe Switching API's

Created on 23 Sep 2017  路  28Comments  路  Source: cypress-io/cypress

UPDATE

As of 0.20.0 it's possible to run cy.* commands on iframe elements as documented here: https://github.com/cypress-io/cypress/issues/136#issuecomment-328100955

However you still can't "easily" switch to iframe context which prevents you from using commands like cy.get()

What users want

  • To be able to "switch" into <iframe> and then utilize all the regular cy.* commands within this context.

What we need to do

  • Add new cy commands to switch into iframes and then also switch back to the "main" frame.

Things to consider

  • How will we handle snapshotting? Currently we don't take snapshots for anything inside of an <iframe>.
  • How will we handle cross origin frames? It's possible to enable these with { chromeWebSecurity: false }.
  • How will we show context switching in the Command Log? It should probably look / be colored differently than the 'normal' main commands

Examples of how we could do this

// switch to an iframe subject
cy
  .get('#iframe-foo').switchToIframe()
  .get('#button').click() // executed in <iframe id='iframe-foo' />

// or pass in $iframe object in hand
cy
  .get('#iframe-foo').then(($iframe) => {
    cy.switchToIframe($iframe)
    cy.get('#button').click()
  })

// now switch back to the main frame
cy
  .switchToMain()
  .get(':checkbox').check() // issued on the main frame
duplicate

Most helpful comment

+1, this is blocking my company from using cypress. Otherwise, Cypress looks amazing.

All 28 comments

This would be amazing! I like to try and keep all of the work in beforeEaches and have my assertions be pure (no side affects like clicking or visiting).

Such a shame this is not in, I can not use the tool witouth this feautre :( makes it very hard to test legacy aplications

+1

+1

+1

What about having Cypress automatically switch to the iframe if the element you .get() is an iframe?

@ianwalter how would Cypress know to find the element in the iframe?

Iframes are completely separate windows and documents. It's not going to just "automatically" find them unless it queried across every single one. What if you did cy.get('button') and it was found in multiple frames?

The only way to do to this is with frame switching APIs.

@jusefb I'm confused... you can utilize iframes right now per this comment: https://github.com/cypress-io/cypress/issues/136#issuecomment-309090376

Sure it's not as nice as iframe switching API's but it does work right now.

@brian-mann No I meant if you specifically get an iframe element it would automatically switch, so instead of cy.get('#someiframe').switchToIframe() you would just write cy.get('#someiframe'). Cypress would need some logic added to get() to detect if the element is an iframe, but it would just be a shorter syntax.

Another idea:
Just add a switchTo function to the API, if it's passed no selector switch to main, if it contains an iframe selector (e.g. #someiframe) it would switch to that iframe.

Sure, the switchToIframe signature is not the problem here. That's the easy part. It could take an existing subject, or a DOM element as first argument, or a selector as first argument. All that is 馃憤

The harder part is doing all of the rest of the things that we do for the parent <window>. Things like automatically waiting for page loads, and XHR calls, and various page events.

Also when it comes to snapshotting, we currently don't snapshot inside of iframes. We'd have to do that (else this feature would be worthless) - but it may mean we'd have to snapshot both the parent document AND the iframe. Those API's don't currently take this into account. Same thing for element highlighting.

There are some other complexities that I can't remember at the moment but are in my notes somewhere. That's the stuff that's been blocking this from getting done. The half ass solution is mostly good enough which is why this hasn't been a super high priority.

Oh for sure, I understand that this is a big feature and I'm only talking about the API layer. Just wanted to add some ideas to make the API nicer to use once all the hard parts are taken care of. IMHO, I would rather not have to chain commands like in the initial example, but using an alias or a promise is fine with me.

+1

+1

+1

+1, this is blocking my company from using cypress. Otherwise, Cypress looks amazing.

any news on the completion of this new function

@brian-mann are there any updates on where this sits in the roadmap?

This feature is still in the 'proposal' stage. No work has been done on this feature as of yet. We're a small team and as much as we'd love to work on everything, we have to choose what to work on based on a multitude of things.

@jennifer-shehane I totally understand (particularly when things are open source), just wanted to see if there's anything that can be done from the outside to help make progress. It sounds like there are a number of people here who may be willing to contribute to it moving forward.

I see that on the road-map this is listed as "partially complete", just wondering if there's any code anywhere for it, would love to help.

However you still can't "easily" switch to iframe context which prevents you from using commands like cy.get()

So actually there IS a "not-so-easy" way to switch to iframes. Would you mind to point me to the docs that explain how to do it?

Many people have listed some workarounds to iframes in this issue: https://github.com/cypress-io/cypress/issues/136

for many SAAS / Cloud offerings the lack of this feature is showstopper, as integrations mostly happen within IFrames

+1 - Just faced this when trying to test a Payment form that uses Stripe Elements which happens to use iFrame too

Greetings. I am also facing this issue for a website I'm writing Cypress tests.

Many people have listed some workarounds to iframes in this issue: #136

Something like:

.get('iframe.stripe_checkout_app')
.then(function ($iframe) {
    const $body = $iframe.contents().find('body')

    cy
      .wrap($body)
      .find('input:eq(0)')
      .type('4242424242424242')

    cy
      .wrap($body)
      .find('input:eq(1)')
      .type('1222')

    cy
      .wrap($body)
      .find('input:eq(2)')
      .type('123')
})

same was used here I guess https://medium.com/bratislava-angular/testing-an-app-inside-an-iframe-using-cypress-434a4d8b8bbe but with checking if the element is ready already

Duplicate of #136

I'm closing this to better consolidate our tracking of iframe support - these are essentially duplicates. If you have comments on what you'd like the API to be or what you need supported - please comment in #136

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zbigniewkalinowski picture zbigniewkalinowski  路  3Comments

simonhaenisch picture simonhaenisch  路  3Comments

rbung picture rbung  路  3Comments

jennifer-shehane picture jennifer-shehane  路  3Comments

tahayk picture tahayk  路  3Comments