Summer Sale! All accounts are 50% off this week.

secondman's avatar

Remove a route for testing

I'm working on the RegistrationTest in Jetstream and I'm trying to enable/disable the Features::registration so that the page rendering in each scenario isn't skipped.

In my Pest file I created a helper to update the fortify config so the test will run if registration is enabled, but I also need to unregister the register route so the 404 assertion will return true.

Previously you could use the Auth::routes() facade method, but now that only works if you have laravel/ui installed.

My test looks like so:

it('disables the registration screen render if support is disabled', function () {
  $response = $this->get('/register');

  $response->assertStatus(404);
})->skip(function () {
  disableRegistration(); // see next block

  return Features::enabled(Features::registration());
}, 'Registration support is enabled.');

And here's my helper:

function disableRegistration()
{
  $features = config('fortify.features');

  // registration is always at key 0 
  // unless you change your config.
  if ($features[0] === 'registration') {
    array_shift($features);
  }
  
  config(['fortify.features' => $features]);

  // NOPE, this won't work without laravel/ui
  Auth::routes(['register' => false]);
}

Any ideas would be appreciated.

0 likes
6 replies
secondman's avatar

@martinbean

Hey Martin,

When the Features::registration() key is enabled in fortify config, the registration route is added to the route collection. When it's not enabled the route is not found.

So in this my scenario, I have everything enabled like so:

'features' => [
  Features::registration(),
  Features::resetPasswords(),
  Features::emailVerification(),
  Features::updateProfileInformation(),
  Features::updatePasswords(),
  Features::twoFactorAuthentication([
    'confirm' => true,
    'confirmPassword' => true,
    // 'window' => 0,
  ]),
],

This will cause the test to be skipped. I want to run this test even if my current registration is enabled.

By switching the config in my disableRegistration helper, the test is allowed to run, but the test fails because the registration route still exists in the collection. The status assertion returns a 200 instead of 404.

I think what I need is a route mixin that will remove this route on the fly, but I'm not certain were to go from there.

meduz's avatar

@secondman I’m here because I’m facing a similar situation. I’m using a .env entry to decide if the user registration must be enabled or disabled and I’m looking for an approach to be able to test both scenarios.

The route definition:

<?php

// route/auth.php

use App\Http\…;
// other use statements…
use Illuminate\Support\Facades\Route;

Route::middleware('guest')->group(function () {
    if (config('features.registration')) {
        Route::get('register', [RegisteredUserController::class, 'create'])
                    ->name('register');

        Route::post('register', [RegisteredUserController::class, 'store']);
    }

    // other routes
});

Ideally I’d like to avoid unregistering the route on the fly, because it would make the test way more complicated than what it’s trying to test.

I’ve also tested to run two separated files, each defining the value of config() in beforeEach but it doesn’t do the trick. Here’s how it looks like (Pest):

<?php

// tests/Feature/Auth/RegistrationTest.php

use App\Providers\RouteServiceProvider;

// Test when registration routes should be enabled.

beforeEach(function () {
    config(['features.registration' => true]);
});

test('registration screen can be rendered', function () {
    $this->get('/register')->assertStatus(200);
});

test('new users can register', function () {
    $response = $this->post('/register', [
        'name' => 'Test User',
        'email' => '[email protected]',
        'password' => 'password',
        'password_confirmation' => 'password',
    ]);

    $this->assertAuthenticated();
    $response->assertRedirect(RouteServiceProvider::HOME);
});
<?php

// Test when registration routes should be disabled.

beforeEach(function () {
    config(['features.registration' => false]);
});

test('registration screen can’t be rendered', function () {
    $this->get('/register')->assertStatus(404);
});

test('new users can’t register', function () {
    $response = $this->post('/register', [
        'name' => 'Test User',
        'email' => '[email protected]',
        'password' => 'password',
        'password_confirmation' => 'password',
    ]);

    $this->assertGuest();
    $response->assertStatus(404);
});

Any idea?

secondman's avatar

@meduz

Yeah we're facing the exact same problem. I know there must be some way to disable a route for testing, if not .. then that's just ridiculous.

meduz's avatar

@secondman Yeah, or maybe we don’t have the right approach to test this. If I find something on the long run, I’ll come back here to share. I think I’ll have a look at some popular PHP projects next week-end (maybe Telescope and Horizon will provide hints…).

cwhite's avatar

Previously you could use the Auth::routes() facade method, but now that only works if you have laravel/ui installed.

Just install laravel/ui?

Please or to participate in this conversation.