I'm currently doing some automation, and I'm having trouble getting over the Plaid iframe. This how it looks inside of my app:
This how is setup inside of my app:
<div class="PaneActions PaneActions--no-padding-top"><button
class="TextButton TextButton--is-action TextButton--is-threads-treatment TextButton--no-margin">
<p class="FinePrint FinePrint--is-threads-treatment">By selecting “Continue” you agree to the <u>Plaid End User
Privacy Policy</u></p>
</button><button
class="Touchable-module_resetButtonOrLink__hwe7O Touchable-module_block__WBbZm Touchable-module_wide__EYer3 Button-module_button__1yqRw Button-module_large__1nbMn Button-module_centered__3BGqS"
id="aut-continue-button" type="button" role="button"><span class="Button-module_flex__2To5J"><span
class="Button-module_text__38wV0">Continue</span></span></button></div>
I'm getting the parent and the child elements, I'm looking by the text, and many other options and I'm unable to test this product. Does anyone has been working with plaid before?
I'm currently doing some automation, and I'm having trouble getting over the Plaid iframe. This how it looks inside of my app:
This how is setup inside of my app:
<div class="PaneActions PaneActions--no-padding-top"><button
class="TextButton TextButton--is-action TextButton--is-threads-treatment TextButton--no-margin">
<p class="FinePrint FinePrint--is-threads-treatment">By selecting “Continue” you agree to the <u>Plaid End User
Privacy Policy</u></p>
</button><button
class="Touchable-module_resetButtonOrLink__hwe7O Touchable-module_block__WBbZm Touchable-module_wide__EYer3 Button-module_button__1yqRw Button-module_large__1nbMn Button-module_centered__3BGqS"
id="aut-continue-button" type="button" role="button"><span class="Button-module_flex__2To5J"><span
class="Button-module_text__38wV0">Continue</span></span></button></div>
I'm getting the parent and the child elements, I'm looking by the text, and many other options and I'm unable to test this product. Does anyone has been working with plaid before?
Share Improve this question asked Mar 10, 2021 at 0:26 HvaandresHvaandres 1,0155 gold badges22 silver badges47 bronze badges3 Answers
Reset to default 5Using the Plaid demo page as a test app and following the steps in Working with iframes in Cypress, I managed to get a consistently working test.
From the blog, I used this sequence to ensure the iframe body has fully loaded
iframe -> body -> should.not.be.empty
The page loads a placeholder first while is waits for a GET request to plete, so just getting a loaded iframe body is not sufficient.
placeholder
<p>iframe placeholder for https://cdn.plaid./link/v2/stable/link.html?isLinkInitialize=true&origin=https%3A%2F%2Fplaid.&token=link-sandbox-170bce6a-fe90-44a4-8b8a-54064fbc8032&uniqueId=1&version=2.0.917</p>
We need to wait for the "Continue" button, which takes a bit of time to show so give it a long timeout.
Using .contains('button', 'Continue', { timeout: 10000 })
actually returned two button, although there is only one visible.
I changed the button selector to use an id and all works consistently.
The test
cy.visit('https://plaid./demo/?countryCode=US&language=en&product=transactions');
cy.contains('button', 'Launch Demo').click()
cy.get('iframe#plaid-link-iframe-1', { timeout: 30000 }).then(iframe => {
cy.wrap(iframe) // from Cypress blog ref above
.its('0.contentDocument.body')
.should('not.be.empty') // ensure the iframe body is loaded
.as('iframeBody') // save for further mands within iframe.body
//.contains('button', 'Continue', { timeout: 10000 }) // returns 2 buttons!
.find('button#aut-continue-button', { timeout: 10000 }) // this is the best selector
.click()
cy.get('@iframeBody')
.contains('h1', 'Select your bank') // confirm the result of the click()
})
- You will have to do the call for your app link
- You will have to add the following code:
describe('Plad Testing', () => {
it('Request Loan', () => {
//cy.find('Button-module_large__1nbMn', [0], { timeout: 10000 }).click()
cy.visit('https://plaid./demo/?countryCode=US&language=en&product=transactions');
cy.contains('button', 'Launch Demo').click()
cy.get('iframe#plaid-link-iframe-1', { timeout: 30000 }).then(iframe => {
let plaid = cy.wrap(iframe)
plaid // from Cypress blog ref above
.its('0.contentDocument.body')
.should('not.be.empty') // ensure the iframe body is loaded
.as('iframeBody') // save for further mands within iframe.body
//.contains('button', 'Continue', { timeout: 10000 }) // returns 2 buttons!
.find('button#aut-continue-button', { timeout: 10000 }) // this is the best selector
.click()
let plaid_choose_bank = cy.get('@iframeBody')
plaid_choose_bank
.contains('h1', 'Select your bank') // confirm the result of the click()
.xpath('/html/body/reach-portal/div[3]/div/div/div/div/div/div/div[2]/div[2]/div[2]/div/ul/li[1]/button/div/div[2]/p[1]').click()
let plaid_bank_username = cy.get('@iframeBody')
plaid_bank_username
.find('input[name="username"]').type('user_good', { delay: 100 })
let plaid_bank_password = cy.get('@iframeBody')
plaid_bank_password
.find('input[name="password"]').type('pass_good', { delay: 100 })
let plaid_bank_button = cy.get('@iframeBody')
plaid_bank_button
.find('button#aut-submit-button').click()
})
})
})
It could be possible that you get that you are not able to find the body of your iFrame. To solve this issue, we will need to add some configuration to the Cypress.json file:
{
"chromeWebSecurity": false,
"pageLoadTimeout": 300000,
"viewportWidth": 1536,
"viewportHeight": 960,
"includeShadowDom": true,
}
- Chrome web security will prevent any CORS security from fire-up inside of the current test scenario that we have since you will have that
0.contentDocument.body
will return null if the parent origin is different from the iframe origin. This will cause the CORS security issue! - Page load time will help to slow loading the pages and have more time to process things
- Viewport will help to make the browser window render like a laptop screen
- Include shadow dom will make it easier to look for this type of element without including the "includeShadowDom" inside of your
find()
elements.
All of the other answers here use *.plaid.
as the origin, which is why contentDocument
is not null
.
If you are testing this in the real world, you will be running a cross-origin iframe
which causes contentDocument
to be null a per the MDN page
Cypress is in the process of adding official iframe
support, but until then you can use cypress-iframe
which just worked for me out of the box.
My test
it.only('users should be able to import holdings from their broker', () => {
cy.visit('/portfolios/created');
cy.findByText('Import from broker').click();
cy.frameLoaded();
cy.iframe().findByText('Continue').click();
});