Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How do I test the @can and @cannot directives in Laravel
    Laravel Blade directives @can @cannot unit tests feature tests authorization logic


How do I test the @can and @cannot directives in Laravel


To test the `@can` and `@cannot` Blade directives in Laravel, you can use a combination of unit tests and feature tests. Here's an example of how you can approach this:

1. Unit Tests:
- Create a test class for your authorization logic, such as `AuthorizationTest`.
- Use the `Illuminate\Support\Facades\Blade` facade to test the behavior of the `@can` and `@cannot` directives.
- Mock the user's permissions or roles as needed for your test cases.

Example:

php
   namespace Tests\Unit;

   use Illuminate\Support\Facades\Blade;
   use Tests\TestCase;

   class AuthorizationTest extends TestCase
   {
       public function testCanDirective()
       {
           $this->mockUser(['update-post']);

           $output = Blade::render('@can("update-post", $post) Yes @else No @endcan', ['post' => new \stdClass()]);
           $this->assertStringContainsString('Yes', $output);
       }

       public function testCannotDirective()
       {
           $this->mockUser([]);

           $output = Blade::render('@cannot("update-post", $post) Yes @else No @endcan', ['post' => new \stdClass()]);
           $this->assertStringContainsString('Yes', $output);
       }

       protected function mockUser(array $permissions)
       {
           $user = $this->createMock(\App\Models\User::class);
           $user->method('can')->willReturn(in_array('update-post', $permissions));

           $this->app->instance(\Illuminate\Contracts\Auth\Authenticatable::class, $user);
       }
   }
   

2. Feature Tests:
- Create a feature test class for your application's views, such as `ViewTest`.
- Use the `assertSee` and `assertDontSee` methods to verify the presence or absence of content based on the user's permissions.

Example:

php
   namespace Tests\Feature;

   use Illuminate\Foundation\Testing\RefreshDatabase;
   use Tests\TestCase;

   class ViewTest extends TestCase
   {
       use RefreshDatabase;

       public function testPostUpdateView()
       {
           $user = $this->createUser(['update-post']);
           $this->actingAs($user);

           $response = $this->get('/posts/1/edit');
           $response->assertSee('Update Post');
       }

       public function testPostUpdateViewWithoutPermission()
       {
           $user = $this->createUser([]);
           $this->actingAs($user);

           $response = $this->get('/posts/1/edit');
           $response->assertDontSee('Update Post');
       }

       protected function createUser(array $permissions)
       {
           $user = \App\Models\User::factory()->create();
           $user->givePermissionTo($permissions);
           return $user;
       }
   }
   

In the unit tests, you can mock the user's permissions and test the behavior of the `@can` and `@cannot` directives directly. In the feature tests, you can create users with specific permissions and assert the presence or absence of content in the rendered views.

By combining these two approaches, you can thoroughly test the authorization logic in your Laravel application, ensuring that the `@can` and `@cannot` directives are working as expected.

Citations:
[1] https://laravel.com/docs/5.1/authorization
[2] https://yajrabox.com/docs/laravel-acl/master/directives
[3] https://konekt.dev/acl/master/blade-directives
[4] https://laravel.com/docs/11.x/authorization
[5] https://yajrabox.com/docs/laravel-acl/master/middleware