Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel testing authorization to route, middleware auth issue

Tags:

Bear with me, new to testing.

So, I have this current structure of middlewares:

class IsActive
{
    public function handle($request, Closure $next)
    {
        if (self::active()) {
            return $next($request);
        }
        Auth::guard('web')->logout();
        return redirect('/');
    }

    protected function active()
    {
        if (Auth::guard('web')->check()) {
            $state = Auth::guard('web')->user()->state;
            if ($state == 'enabled') {
                return true;
            }
        }
        return false;
    }
}

class IsAdmin extends IsActive
{
    public function handle($request, Closure $next)
    {
        if (parent::active()) {
            if (Auth::guard('web')->check()) {
                $role = Auth::guard('web')->user()->role->name;
                if ($role == 'admin' || $role == 'superAdmin') {
                    return $next($request);
                }
            }
            return redirect('/');
        }
        Auth::guard('web')->logout();
        return redirect('/');
    }
}

This is the route

Route::group(['middleware' => 'admin'], function () {
    Route::get('/', 'ReportingController@reportingPage');
});
//Its registered on RouteServiceProvider that these routes require IsActive and this specific route needs for the admin

And in the Reporting Controller, I got this function

public function reportingPage(Request $request) {
    return view('reporting.reporting');
}

So good so far. If the user has access, great, if not it gets redirected.

Now for the testing, I want to validate if an admin can view it (and an unauthorized can't, but for this question im trying to figure out the admin)

protected $user;

public function setUp()
{
    parent::setUp();
    $this->user = new \App\Models\User(['role_id'    => 6, //admin
                                        'name'       => 'Admin',
                                        'user'       => 'admin',
                                        'email'      => '[email protected]',
                                        'state'      => 'enabled',
                                        'deleted_at' => null]);
    $this->be($this->user);
}

public function testCanAccessReportingPage()
{
    $this->get("/reporting/")->assertStatus(200);
}

Error

This is the error I'm getting and I'm trying to figure out whats the process. Obviously I'm doing something wrong or I'm forgetting something, so tips and ideas on how to test this authorization are greatly appreciated.

Edit:

After an answer that was deleted envolving a bit of refactor and some attempts, I've determined that Auth::guard('web')->user() has a user, Auth::guard('web')->user()->role() is null on testing environment. I've solved by loading the relationship but the question I now have is: Why does this happen on test environment.

like image 775
abr Avatar asked Aug 06 '18 11:08

abr


2 Answers

May be created user (mocked) is not used in $this context.

If you look at documentation https://laravel.com/docs/5.6/http-tests#session-and-authentication, you see method

$this->actingAs($user)

Full example:

<?php

use App\User;

class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $user = factory(User::class)->create();

        $response = $this->actingAs($user)
                         ->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}
like image 145
Andrey Krasilnikov Avatar answered Oct 11 '22 15:10

Andrey Krasilnikov


I have changed your code little bit. Removed duplicate code and added lazy eager loading for user role $user->load('role'). Try it

class IsAdmin
{
    public function handle($request, Closure $next)
    {
        //no need to check active again, because you said IsActive is already applied in RouteServiceProvider
        $user = Auth::guard('web')->user();

        $user->load('role'); //lazy eager load

        $role = $user->role->name; 

        if ($role == 'admin' || $role == 'superAdmin') {
            return $next($request);
        }

        Auth::guard('web')->logout();
        return redirect('/');
    }
}
like image 44
rkj Avatar answered Oct 11 '22 16:10

rkj