Last active
July 13, 2021 07:44
-
-
Save mike-mccormick/9390e9044612dbb4d3fd1868dd067048 to your computer and use it in GitHub Desktop.
Handle Stripe 3DS/SCA in Cypress, using Puppetter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Automating Stripe card testing with cypress is pretty easy (especially with 'cypress-plugin-stripe-elements') | |
but SCA/3DS testing really isn't. | |
When using a SCA/3DS test card, to simulate the approve/denial Stripe fires what appears to be a modal, however | |
it's actually an iFrame, within an iFrame within an iFrame that shows in a lightbox. | |
The innermost iFrame is very difficult to generate with because of how it's rendered (even when you've managed | |
to find and scope into each one), however the source URL can be browsed to. | |
This approach uses Cypress to burrow down, grab the URL, then have puppeteer browse to it, and approve or fail the transaction. | |
*/ | |
//commands/stripe.js | |
Cypress.Commands.add("processStripeSCA", (action) => { | |
//Find the first frame - Named differently each load ( __privateStripeFrameXXXX ) | |
cy.get("iframe[name*='__privateStripeFrame']") | |
.within(($element) => { | |
//Get the body from the first frame | |
const $body = $element.contents().find("body"); | |
let topLevel = cy.wrap($body) | |
//Find the second frame | |
topLevel.find("iframe[name*='__stripeJSChallengeFrame']") | |
.within(($secondElement) => { | |
//Get the body from the second frame | |
const $secondBody = $secondElement.contents().find("body"); | |
let secondLevel = cy.wrap($secondBody) | |
//Find the third frame - acsFrame | |
secondLevel.find("iframe[name*='acsFrame']") | |
//Scope into the actual modal | |
.within(($thirdElement) => { | |
//Grab the URL of the stripe popup, then have puppeteer browse to it! | |
cy.task('processSCA', {url: $thirdElement[0]["baseURI"], action: action}); | |
}) | |
}) | |
}) | |
}) | |
// support/sca-helper.js | |
const puppeteer = require('puppeteer') | |
exports.processSCA = async function processSCA({url, action}) { | |
const creds = await puppeteer | |
.launch({headless: false}) | |
.then(async browser => { | |
try{ | |
let page = await browser.newPage(); | |
debugger | |
//Navigate to Login Page | |
await page.goto(url); | |
//lazy wait to handle Stripe loading | |
await page.waitFor(5000) | |
let element; | |
if(action === 'pass') | |
{ | |
element = '#test-source-authorize-3ds' | |
} | |
else | |
{ | |
element = '#test-source-fail-3ds' | |
} | |
await page.click(element) | |
await page.waitForSelector('.FallbackMessageTitle') | |
await browser.close() | |
await browser.close() | |
console.log(localStorageData) | |
return true | |
} catch (error) { | |
console.log(error) | |
} | |
}) | |
return true | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tip: If you do use this, you'll also need to burrow down into the iFrame overlay and click 'Close' after you've authenticated. For me, I use this:
(
.iframe
comes from cypress-iframe)