user2407971 user2407971 - 4 months ago 68
PHP Question

Testing unauthorized user restriction in Laravel PHPUnit

Laravel Version 5.2

In my project, users with role_id = 4 has the admin role and can manage users.

I have defined the following ability in AuthServiceProvider:

public function boot(GateContract $gate)
{
$this->registerPolicies($gate);

$gate->define('can-manage-users', function ($user)
{
return $user->role_id == 4;
});
}


I have used this ability in the UserController __construct method as follows:

public function __construct()
{
$this->authorize('can-manage-users');
}


In ExampleTest, I have created two tests to check if the defined authorization works.

The first test for admin user who has role_id = 4. This test passes.

public function testAdminCanManageUsers()
{
$user = Auth::loginUsingId(1);
$this->actingAs($user)
->visit('users')
->assertResponseOk();
}


The second test is for another user who does not have role_id = 4. I have tried with response status 401 and 403. But the test is failing:

public function testNonAdminCannotManageUsers()
{
$user = Auth::loginUsingId(4);
$this->actingAs($user)
->visit('users')
->assertResponseStatus(403);
}


First few lines of the failure message is given below:


A request to [http://localhost/users] failed. Received status code [403].

C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithPages.php:196
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithPages.php:80
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithPages.php:61
C:\wamp\www\laravel\blog\tests\ExampleTest.php:33

Caused by exception 'Illuminate\Auth\Access\AuthorizationException'
with message 'This action is unauthorized.' in
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Auth\Access\HandlesAuthorization.php:28


I have also tried to use 'see' method as follows:

public function testNonAdminCannotManageUsers()
{
$user = Auth::loginUsingId(4);
$this->actingAs($user)
->visit('users')
->see('This action is unauthorized.');
}


But it's failing too. What am I doing wrong? How can I make the test pass?

Answer

The mistake is calling the visit method. The visit method is in the InteractsWithPages trait. This method calls the makeRequest method which in turn calls assertPageLoaded method. This method gets the status code returned and if it gets code other than 200, it catches a PHPUnitException and throws an HttpException with the message

"A request to [{$uri}] failed. Received status code [{$status}]."

This is why the test was failing with the above message.

The test can be successfully passed by using get method instead of visit method. For example:

public function testNonAdminCannotManageUsers()
{
    $user = App\User::where('role_id', '<>', 4)->first();

    $this->actingAs($user)
        ->get('users')
        ->assertResponseStatus(403);
}

This test will pass and confirm that a non admin user cannot access the url.

Comments