0

On my Laravel(7) project, I'm using spatie/laravel-permission for authorization and have Policies for each Model (auto bound) being called via the controller. Also I return views from my controller.

Controller looks like this:

class RoleController extends Controller
{
    
    public function __construct() {
        $this->middleware('auth:webadmin');
        $this->authorizeResource(Role::class, 'role');
    } 

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\System\Role  $role
     * @return \Illuminate\Http\Response
     */
    public function show(Role $role)
    {
        return view('admin.role.show', compact('role'));
    }
...

I use @can blade directive on the view to control elements available based on permissions.

Ex:

@can('edit role')
    <a href="{{ route('admin.roles.edit', $role->id) }}" class="btn btn-primary">{{ __('Edit') }}</a>
@endcan

Note: 'edit role' is actually a permission name defined in Permissions (spatie/laravel-permission).

This setup works perfectly except for testing.

For testing I'm using PhpUnit and mocking the authorization as below.

    /**
     * @test
     * @covers ::show
     */
    public function loggedin_user_can_view_a_selected_role()
    {
        $this->withoutExceptionHandling();
        //prepare data
        $role = factory(Role::class)->create();
        $user = factory(AdminUser::class)->create();
        
        $this->mock(\Illuminate\Contracts\Auth\Access\Gate::class, function ($mock) use ($role) {
            $mock->shouldReceive('authorize')
                 ->with('view', [$role->fresh()])
                 ->once()
                 ->andReturn(true);
        });

        //request
        $response = $this->actingAs($user, 'webadmin')->get(route('admin.roles.show', $role->id));

        //assertions
        $response->assertOk();
        $response->assertViewIs($this->viewPathPrefix.'.show');
        $response->assertViewHas('role', $role);
    
    }

It's giving me this error when I execute the test.

$ php artisan test --filter loggedin_user_can_view_a_selected_role
Warning: TTY mode is not supported on Windows platform.

   RUNS  Tests\Feature\Admin\RoleCrudTest
  • loggedin user can view a selected role

  Tests:  1 pending

   FAIL  Tests\Feature\Admin\RoleCrudTest
  ✕ loggedin user can view a selected role

  Tests:  1 failed

   ErrorException

  file_get_contents(C:\project\secret-project\vendor\mockery\mockery\library\Mockery\Loader\EvalLoader.php(34) : eval()'d code): failed to open stream: No such file or dire
ctory

  at C:\project\secret-project\vendor\facade\ignition\src\Views\Compilers\BladeSourceMapCompiler.php:11
     7| class BladeSourceMapCompiler extends BladeCompiler
     8| {
     9|     public function detectLineNumber(string $filename, int $exceptionLineNumber): int
    10|     {
  > 11|         $map = $this->compileString(file_get_contents($filename));
    12|         $map = explode("\n", $map);
    13|
    14|         $line = $map[$exceptionLineNumber - 1] ?? $exceptionLineNumber;
    15|         $pattern = '/\|---LINE:([0-9]+)---\|/m';

  1   C:\project\secret-project\vendor\facade\ignition\src\Views\Compilers\BladeSourceMapCompiler.php:11
      file_get_contents("C:\project\secret-project\vendor\mockery\mockery\library\Mockery\Loader\EvalLoader.php(34) : eval()'d code")

  2   C:\project\secret-project\vendor\facade\ignition\src\Views\Engines\CompilerEngine.php:97
      Facade\Ignition\Views\Compilers\BladeSourceMapCompiler::detectLineNumber("C:\project\secret-project\vendor\mockery\mockery\library\Mockery\Loader\EvalLoader.php(34) :
 eval()'d code")

But works perfectly as soon as I remove the @can blade directive from view.

What am I doing wrong/What am I missing here?

Also, If i change my test to give the permission to user instead of mocking authorization, it works even with the @can directive in view. But this doesn't assert that the correct permission is used and I have to write an additional test case for each method. So I prefer to get the Mocking working.

i.e.

$user = factory(AdminUser::class)->create();
$user->givePermissionTo('view role');

Thanks in Advance

Jude F'do
  • 127
  • 2
  • 11
  • Could you try `partialMock` instead of `mock`. – Remul Jul 06 '20 at 08:14
  • @Remul - tried that but still the same. Error message changed slightly confirming that when view is being parsed/compiled (not sure of correct word), `@can` directive is trying to access some closures via Gate facade. – Jude F'do Jul 06 '20 at 15:01

0 Answers0