I've written the following end-to-end test with Laravel Dusk to test my site's PayPal and Stripe Element forms:
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class PaymentsTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* A Dusk test example.
*
* @return void
*/
public function test_payments_are_working()
{
$this->browse(function (Browser $browser) {
$browser->visit("/manufacturers/oneplus")
->type('email', "[email protected]")
->press('Continue')
->waitForLocation('/payment')
->waitFor("#paypal-button-container iframe")
->withinFrame('#paypal-button-container iframe', function($browser) {
$browser->click(".paypal-button");
})
->waitFor(".paypal-checkout-sandbox-iframe")
->withinFrame('.paypal-checkout-sandbox-iframe', function($browser) {
$browser->click(".paypal-checkout-close");
})
->waitFor('.__PrivateStripeElement iframe')
->withinFrame('.__PrivateStripeElement iframe', function($browser) {
$browser
->pause(1000)
->keys('input[placeholder="1234 1234 1234 1234"]', 4242424242424242)
->keys('input[placeholder="MM / YY"]', '0125')
->keys('input[placeholder="CVC"]', '123')
->select('select[name="country"]', 'GB')
->keys('input[name="postalCode"]', 'SW1A 1AA')
->pause(500);
})
->clickAndWaitForReload("@stripe-payment-button")
->pause(10000) // for debugging purposes
->assertSeeAnythingIn(".text-success");
});
}
}
The entire test works right up until the final assertion:
Time: 00:19.175, Memory: 30.00 MB
There was 1 error:
1) Tests\Browser\PaymentsTest::test_payments_are_working
Facebook\WebDriver\Exception\NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"body .text-success"}
(Session info: headless chrome=100.0.4896.75)
Looking at the screenshot generated by my GitHub Action workflow at the point of failure, I can see that immediately after the button is pressed it becomes a blank page instead of redirecting to the expected route, even though prior to this all the routes are working.
What could be going on here that would cause this one route to become blank?
What I've Tried So Far:
- Setting
APP_URL
in.env.dusk.testing
tohttp://127.0.0.1:8000
and running Dusk withphp artisan dusk --env=testing
- Adding a step to run migrations in my GitHub Action, which was missing from the example in the documentation
After a few days of trying to debug this infuriating issue in order to test my Stripe and PayPal payments - made only a little easier by watching the tests run locally using
php artisan dusk --browse
- I eventually realised the primary cause of the issue was a HTTPS issue despite having already set myAPP_URL
to HTTP... although even after solving that issue I still had to fix a few other issues with the Dusk documentation's example GitHub Action just to get the whole setup working.I first combed through my Stripe client side code and confirmed that my
return_url
variable was hardcoded to a HTTPS link on successful payment, which is why that route alone was failing to display. Simply changing this variable tohttp
(neither the Stripe nor PayPal payment success routes accept relative links) would solve the problem, but pushing this file into version control will also cause the live site to redirect the insecure HTTP route, which itself will cause the Stripe live integration to fail. Therefore this requires a solution which avoids hardcoding the payment return URLs into the JavaScript.I decided to solve it by using Laravel Mix's ability to dynamically inject variables from my .env file into my JavaScript, as briefly described in the documentation here.
First, make sure your
.env.dusk.testing
file contains the following values:Second, make sure your
.env.dusk.local
file contains the following values:Finally, make sure the
.env
file on your production server has something like the following:In my client-side JavaScript code, such as for Stripe payments, I can then grab the environment's relevant
APP_URL
by doing:...where
/success
represents the rest of the path to my payment success route.Next, add the standard
setup-node
action to install a recent version of NPM to your GitHub Action, followed by a build step to run Laravel Mix and replaceprocess.env.MIX_APP_URL
your other Mix variables with the appropriate values:Lastly, change the environment file preparation stage to copy environment variables from
env.dusk.testing
(or.env.dusk.local
if that's all you have) instead of the default.env.example
used by the documentation:This should result in a complete testing workflow for GitHub Actions that looks similar to the following:
...and most importantly, successfully runs your Laravel Dusk tests.