Open mike-mccormick opened 3 years ago
Share a failing test with me here so I can reproduce this? Otherwise it'll be high friction for me to look into it. Thanks!
Hey @dbalatero, sorry should have gotten something set up.
I'm using cypress-cucumber-preprocessor
here too, as well as but this is the demo test I threw together to test your plugin.
If you swap the card number in the line: cy.enterStripeDetails('4000002500003155', '12/23', 123)
over to the standard 4242...
one, it works great, I just can't find any way to get inside that complete/fail modal!
Thanks for your time, and let me know if there's anything else you need from me!
cypress/stripe.feature
Feature: Checkout
Scenario: Pay through Stripe
Given I visit the stripe demo page
And I enter the standardContact contact information
And I enter card details
And I click the Pay button
Then The success message will appear on screen
cypress/integration/stripe/stripe.js
import {And, Given, Then} from "cypress-cucumber-preprocessor/steps";
import 'cypress-plugin-stripe-elements';
const testUsers = require("../../fixtures/testUsers")
Given('I visit the stripe demo page', function() {
cy.visit('https://stripe-payments-demo.appspot.com/');
});
And('I enter the {} contact information', function(record) {
//Name
cy.get("input[name='name']")
.type(`${testUsers[record].forename} ${testUsers[record].surname}`)
//Email
cy.get("input[name='email']")
.type(testUsers[record].email)
//Address
cy.get("input[name='address']")
.type(testUsers[record].address1)
//City
cy.get("input[name='city']")
.type(testUsers[record].city)
//State
cy.get("input[name='state']")
//This uses a 'Force' because on the DOM, technically the 'ZIP' field
//Appears over the top, even though it doesn't visually.
.type(testUsers[record].state, {force: true})
//Zip
cy.get("input[name='postal_code']")
.type(testUsers[record].state)
})
Then('I enter card details', function() {
cy.enterStripeDetails('4000002500003155', '12/23', 123)
})
And(`I click the {} button`, function(buttonText) {
cy.clickButtonWithText(buttonText)
})
Then(`The success message will appear on screen`, function() {
//Ensure the success message is visible on the page
cy.get('.success h1')
.should('be.visible', {timeout: 10000})
//Assert the success message is correct
cy.get('.success h1')
.should('contain', 'Thanks for your order', {timeout: 10000})
})
cypress/support/stripe.js
//An example of a custom command.
Cypress.Commands.add("enterStripeDetails", (cardNumber, cardExpriy, cardCVV) => {
cy.fillElementsInput('cardNumber', cardNumber);
cy.fillElementsInput('cardExpiry', cardExpriy);
cy.fillElementsInput('cardCvc', cardCVV);
})
cypress/fixtures/testUsers.js
I know this isn't how the Cypress docs show fixtures being used, I just find this cleaner :)
module.exports = {
"standardContact": {
"forename": "Standard",
"surname": "Contact",
"address1": "123 Fake Street",
"city": "Spring Field",
"state": "OH",
"zip": 12345,
"email": "test@example.com"
},
"contactWithInvalidEmailAddress": {
"forename": "Invalid",
"surname": "EmailAddress",
"address1": "123 Fake Street",
"city": "Spring Field",
"state": "OH",
"zip": 12345,
"email": "test@@example.com"
}
Hmm, actually – can I ask you to make a focused test inside this repo on a development branch? You can start a PR for this.
Then we can work together to add something to assist with the 3DS modal to this library, once we have a failing test.
Setting up tests in this repo should be fast, follow this short readme.
Your demo app doesn't seem to support SCA, so both SCA and Non-SCA cards react the same, I think it needs set up to handle paymentIntents and Charges before the SCA challenge process has a change to jump in.
I did however spend a bunch more time trying to get into the iFrame to click the button, and managed to get cypress inside the frame!
Stripe's SCA test modal is three iFrames deep. On the top level is __privateStripeFrameXXXX
where XXXX
is a randomly generated numbers for that session (hence the wildcard selector), so we have to grab that, then scope into it.
Within that is __stripeJSChallengeFrame
, which we also have to scope into.
Finally, grab acsFrame
and scope into that, where the buttons live.
//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) => {
//Get the body of the modal
const $actualModal = $thirdElement.contents().find("body");
//Find, and click the 'Complete Authentication' Button
cy.wrap($actualModal)
.find('button')
.contains('Complete authentication')
.click()
})
})
})
There's no need to find iFrames by name after the top level one, and this can be refactored down a whole bunch, but I think the raw and messy version shows the process better
Update: It seems there is more than one type of SCA confirm/deny test screen on Stripe, with different button labels (I'm guessing these run through actual card processors?) - this code only works on 4000002500003155
Inspiration struck me the other day while implementing Puppeteer to handle azure login on another project.. we can actually dig down, grab the source URL of the iFrame and have puppeteer browse to it!
I've found this really reliable so far, so hopefully it helps someone else: Link to gist
+1 to this issue, it would be great to have support on this on the plugging!
Hey,
Firstly, this plugin's fantastic, and saves a ton of time, thanks!
I'm wondering if anyone has any process worked out for handling the 3DS iFrame/Modal styled popup when using test cards like
4000002760003184
.Even in element inspector in Chrome, I don't feel like the contents of the frame's really being surfaced in a way you'd be able to interact with (short of using a fixed window size, and using x & y to click the screen)..
This would be very useful to me for testing transaction state in applications under test, as handling drop-offs during SCA approval is it's own challenge.
Thanks!