Laravel Dusk - How to test Stripe (Cashier)

Who is this article for?

Anyone looking for how to test stripe effectively with Laravel Dusk.

In this article, I’m going to walk through, how to effectively test Stripe with Laravel Dusk. We will use using Stripe Elements as our test case.

Before You Begin

Lets quickly review how Stripe Elements work and what are the challenges we need to address.

To use Stripe Elements, we first add CSS in the <head> and a JavaScript before </body>. Within the <body> we then add a <div> something like this

<div id="example-card" class="input"></div>.

The id of the div is reference within the JavaScript which load an iframe inside the above div. The rendered page code looks something like this -

Alright, so we need to have dusk input values inside an iframe. We know that dusk is built on top of facebook php-webdrive and it can switch between frames and type in iframes.

$myFrame = $driver->findElement(WebDriverBy::id('my_frame'));
$driver->switchTo()->frame($myFrame); 

Lets, give this a try. The first version of the test looks something like this.

Ok, this seems to be working. But there are a few things I don't like with this approach. Below we will address each point and refactor our test case.

Refactor 1

As you can see above, we are directly referencing the iframe name "__privateStripeFrame3". If Stripe changes the name of the iframe, our Dusk tests will stop working. So we need to use a relative path to get the iframe. Luckily, the $browser object has a way to execute Javascript from within the tests.

This can be used like

$browser->script($scripts); // $scripts can be an array.

So, now rather than referencing iframe name "__privateStripeFrame3" we will use our main div id #example-card and try to locate the iframe within. After first refactoring, our code looks something this.

Refactor 2

Dusk tends to input values in the text box at lighting fast speed. Stripe Elements drop in is pretty Javascript heavy, this causes dusk to input the cc numbers incorrectly as Stripe JS tries to parse and validate cc numbers of every keystroke.

To avoid this, we are going to add pauses after every digit. We will be using the append() method for the same.

Refactor 3

This is starting to look good and is working very smoothly. The only thing I would now like to refactor is to abstract out the switch to iframe and back. It currently looks like a lot of things are happening in this line.

$browser->driver
    ->switchTo()
    ->frame($browser->script('return $("#example-card iframe").attr("name");')[0]);

We will be using Dusk browser macros, using macros makes the code a little more readable.

Let's create a macro inside DuskServiceProvider.php.

The last refactor is entirely optional.

Clean Up

In the medium article, the author is deleting the subscription from the user and then removing the customer from Stripe. I use SQLite disposable DB for Dusk tests and a totally unrelated stripe account. Since the dusk .env file is by default under source control, I don't use any keys which are in any shape or form related to my working environment. I do a regular cleanup of my test Stripe account depending on my test activities. Click here to find how to delete all test data from Stripe.

In the next articles, I will talk about how to test a multi-database Laravel project using SQLite in-memory DB for all databases.

References

https://github.com/facebook/php-webdriver/wiki/Alert,-tabs,-frames,-iframes#frame-iframe https://github.com/laravel/dusk/blob/master/src/Concerns/InteractsWithJavascript.php#L13 https://github.com/laravel/dusk/issues/558 https://github.com/laravel/dusk/blob/master/src/Concerns/InteractsWithElements.php#L154 https://laravel.com/docs/5.7/dusk#browser-macros https://medium.com/@phpTechnocrat/how-to-use-laravel-dusk-to-test-stripe-cashier-c27471c0383 https://stackoverflow.com/questions/35542621/how-to-delete-the-logs-on-stripe-in-a-test-environment/44653616

Posted in LARAVEL, PHP, TESTING, BLOG
Akki K

Akki

Experienced Backend Developer.