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