How to use Laravel Dusk to test Stripe (Cashier)

Bryan Heath
4 min readJul 4, 2017

--

I could not find any one describing how to do this. If there is a better way or resource please let me know.

Please be sure to read the warnings at the bottom of the post.

Stripe.js or Stripe v2

This is the older deprecated method but still used by a number of sites.

First a quick overview of what happens to better understand the challenge of testing it. When the pay button is clicked, a iframe is overlayed on top of the screen. Inside of this frame is the payment modal. After a payment is made the frame goes away.

So we need to click on the payment button, move to the Stripe iframe, enter in the payment and misc information, click the pay button, wait for it process, and then leave the frame.

In this example I used this code to create the button and modal:

Which creates this button:

And this modal:

Note that zip code entry is enabled, however it doesn’t show up until you start entering your credit card number. Which is another challenge.

Here is the test:

The important parts:

Wait for the the iframe overlay to open:

->waitFor('iframe[name=stripe_checkout_app]')

Switch to using that iframe:

$browser->driver->switchTo()->frame('stripe_checkout_app');

Wait for the iframe to go away:

->waitUntilMissing('iframe[name=stripe_checkout_app]')

Note: I have the most problems with this. It fails constantly because it takes awhile to POST and then go away. Just be aware you might need to add more of a delay if you have problems

Go back to the default:

$browser->driver->switchTo()->defaultContent();

Note: This part isn’t necessary unless you have more tests you want to run after Stripe has done it’s thing.

You might be asking yourself, for the fields, why did I use the placeholder as the selector? Lets look at my example Credit Card field

Notice the actual input element:

<input type="tel" class="Fieldset-input Textbox-control" id="1340dc70-60e3-11e7-9637-4d63652b5c74" value="" inputmode="numeric" placeholder="Card number" autocomplete="cc-number" autocorrect="no" autocapitalize="no" spellcheck="no">

The id is a random field. There is also not name. I am guessing that is to stop things like this. So using the placeholder is the only thing that seems usable. However it makes this test VERY brittle.

Stripe v3 or Stripe Elements

For this example I used the code Stripe has a Example 3 on their quick start page.

It gives an entry that looks like:

First a quick overview of what happens to better understand the challenge of testing it. When the page loads a iframe is loaded over an element or elements you have, with the credit card entry input elements on it.

So in the example:

<div id="card-element" class="field"></div>

Gets swapped out with he card input you see on in the screen shot.

The problem is that since it is on a different frame it makes getting to it a bit more complicated. To test we need to wait for the those elements to load, fill out all other the information, go to the Stripe iframe, fill out the credit card elements, leave and go back the to the main window and click the pay button, and finally wait for it process.

Here is the Dusk test I used:

Here are the important parts:

Wait for the stripe elements to load:

->waitFor('iframe[name=__privateStripeFrame3]')

Change to the Stripe iframe:

$browser->driver->switchTo()->frame('__privateStripeFrame3');

Go back to the default:

$browser->driver->switchTo()->defaultContent();

Keep in mind that these elements can very depending on what you used. However this should be enough to get you started. Really the most important part is going to an iframe and back.

Cleanup

Ben Wrigley ask how to delete the user from Stripe when the test was complete.

You will not be able to do this during tearDown() as you need the user. So this will have to be at the end of the test itself

//Delete the subscription
$user->subscription()->delete();
//Delete the customer from Stripe
\Stripe\Stripe::setApiKey(\Config::get('services.stripe.secret'));
\Stripe\Customer::retrieve($user->stripe_id)->delete();

Note: Running the last bit can take a few seconds.

Warnings

These tests are VERY brittle. All it will take is for Stripe to rename something and your Dusk tests will stop working.

I have had on a few occasions where the iframe hasn’t fully loaded and the test failed. This seems rare, but something to be aware of.

Finally Stripe doesn’t seem to like this and will sometimes put a verification page up to prove you are a human. I only ran into this once, so I don’t know what triggers it. Obviously this could be very problematic.

There you go. Testing Laravel Cashier Stripe using Laravel Dusk.

I haven’t used Braintree, however I would image that it would use a similar method.

If you have any better ideas or comments please let me know below or on Twitter.

As always thank you to Taylor Otwell

--

--

Bryan Heath
Bryan Heath

Responses (9)