← Other topics

Dynamic environment configs in Laravel Dusk (duskapiconf)

Video Notes

When writing Laravel Dusk tests, sometimes you need to change your application configs on the fly to test different scenarios.

For a bare bones example, imagine you were building an e-learning platform and had an app config called openEnrollment. When this config is true, your homepage should display a link for new students to enroll. When false, your homepage should display a message saying enrollments are closed:

@if (config('app.openEnrollment'))
    <p dusk='enrollment-open'><a href='/enroll'>Click here to enroll</a></p>
@else
    <p dusk='enrollment-closed'>Enrollments are closed</p>
@endif

Now imagine you wanted to test the correct output was being displayed in both scenarios. In pseudo code, your tests would look like this:

If openEnrollment == true, assert that enrollment link is visible.
If openEnrollment == false, assert that “enrollments are closed” message is visible.

Accomplishing this requires you to be able to change the config allowNewStudents before reach test.

Instinctually, you might try and use Laravel’s config helper in your test to make this config change. E.g.:

public function testEnrollmentOpen(): void
{
    $this->browse(function (Browser $browser) {

        # This won’t work as expected...
        config('app.openEnrollment', true);

        $browser->visit('/')
                ->assertPresent('@enrollment-open');
    });
}

The problem with this is the config will change for your Dusk instance, but not the instance of your app that is being tested.

To address this we can use a package called AlexandreBellas/duskapiconf. This package adds a route in your application that lets you set configs. When you invoke the duskapiconf setConfig method during testing, it will visit that route, changing the config for the test.

Set up

To set up the duskapiconf package, first install it via Composer:

> composer require alebatistella/duskapiconf --dev

Then add the UsesDuskApiConfig trait to your DuskTestCase.php file:

<?php

use Laravel\Dusk\TestCase as BaseTestCase;
use AleBatistella\DuskApiConf\Traits\UsesDuskApiConfig;

abstract class DuskTestCase extends BaseTestCase {
    use UsesDuskApiConfig;

    // ...
}

You will now have access to the methods getConfig, setConfig, and resetConfig in your Desk tests. Examples:

$appName = $this->getConfig('app.name');
$this->setConfig('app.name', 'Demo');
$this->resetConfig();

Applying these methods, here’s what our tests would look like for our hypothetical e-learning application described above:

class ExampleTest extends DuskTestCase
{
    public function testEnrollmentOpen(): void
    {
        $this->browse(function (Browser $browser) {

            #  ⭐ Use duskapiconf to setConfig ⭐ 
            $this->setConfig('app.openEnrollment', true);
            
            $browser->visit('/')
                    ->assertPresent('@enrollment-open');
        });
    }

    public function testEnrollmentClosed(): void
    {
        $this->browse(function (Browser $browser) {

            #  ⭐ Use duskapiconf to setConfig ⭐ 
            $this->setConfig('app.openEnrollment', false);
            
            $browser->visit('/')
                    ->assertPresent('@enrollment-closed');
        });
    }
}

Tear down

I suggest adding a tearDown method to DeskTestCase.php that invokes the resetConfig method, ensuring that any config changes made during testing are not persisted:

/**
*
*/
protected function tearDown(): void
{
    parent::tearDown();
    $this->resetConfig();
}
If this info helped you out, toss a coin in the tip jar?
← Other topics