0

I need to make my routes conditional, based on config:

//routes/auth.php

if (config('auth.allow_registration')) {....

The above config param is set in the config file:

//config/auth.php

'allow_registration' => false,

It is all working fine, until I try to unit-test it

public function test_registration_screen_can_be_rendered()
{
    config()->set('auth.allow_registration', true);
    $response = $this->get('/register');

    $response->assertStatus(200);
}

The test case is failing.

I understand that after I change config, I need to reread routes. But how?

I found only this $this->refreshApplication(); it suppose to reread routes, but it also rereads the config.

How can I only reread routes, but keep my modified config intact?

Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
  • This is happening because when the test has began, the `application` is already loaded, hence routes already sorted out, you cannot change it now. Where are you using that `if` ? And you should be using an `env` instead of a literal `false`, so you can try change it on the `setUp` method (change `env` value). But share more info about it please. – matiaslauriti Sep 09 '21 at 06:14
  • Thank you for stepping in. The `if` is sitting in the `routes/auth.php` file – Yevgeniy Afanasyev Sep 09 '21 at 06:52
  • Look at the source for `refreshApplication()`. What is it doing? – miken32 Dec 03 '21 at 18:46

2 Answers2

1

If you change that config parameter's value to be read from an environment variable, then you can override it for a given test class in the setUp() method. When Laravel reads the config, it will first check if there's an environment variable for the value, then fall back on the default if not.

// config/auth.php

'allow_registration' => env('ALLOW_REGISTRATION', false),
// tests/feature/RegistrationEnabledTest.php

namespace Tests\Feature;

use Tests\TestCase;

class RegistrationEnabledTest extends TestCase
{
    protected function setUp(): void
    {
        putenv("ALLOW_REGISTRATION=true");
        parent::setup();
    }

    public function test_registration_screen_can_be_rendered()
    {
        $response = $this->get('/register');

        $response->assertStatus(200);
    }
}

If you'd like to set it for all of your tests, you can add it to your phpunit.xml in the php environment section:

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="ALLOW_REGISTRATION" value="true"/>
</php>

Unfortunately, setting an env only works for either all tests or a given test class, I also couldn't find a way to get it to work for just a single test within a test class ($this->refreshApplication() doesn't seem to respect the env change), and manually changing routes at runtime is not something Laravel is designed for. However, I think it's a reasonable workaround to separate out tests of various config settings into discrete test classes.

wunch
  • 1,092
  • 9
  • 12
0

You can use a middleware on routes witch you want to have conditions for access. then you can just use the middleware on the route or in your controller. you can learn about it in Laravel good documentation here.

  • This is a good approach, you would return `404` if you don't want those routes to be `on`. – matiaslauriti Sep 09 '21 at 13:27
  • Good idea, voted up, but I cannot accept this answer because it is not answering my question. Creating a middleware is not the best option though. use a controller constructor is a better one, but again, it was not what I asked. – Yevgeniy Afanasyev Sep 09 '21 at 23:26