mstdmstd's avatar

Using Policy to check permissions in a controller can I make http tests for it ?

In laravel 10 app I use Policy to check permissions in a controller :

class TaskController extends Controller
{
    protected CrudRepositoryInterface $taskCrudRepository;
    protected DBTransactionInterface $dbTransaction;
    protected AppLoggingInterface $appLogging;

    public function __construct()
    {
        $this->authorizeResource(Task::class, 'task');
    }

    public function done(int $taskId): JsonResponse
    {
        $this->authorize('done', $task); // For methods which are not standard for authorizeResource
        ...
    }

and in Policy file I use custom service userCheckAccess for checking of any method

namespace App\Policies;

use App\Models\Task;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class TaskPolicy
{
    use HandlesAuthorization;

    protected UserCheckAccessInterface $userCheckAccess;

    public function __construct(UserCheckAccessInterface $userCheckAccess)
    {
        $this->userCheckAccess = $userCheckAccess;
    }

    public function create(User $user): bool
    {
        return $this->userCheckAccess->userTaskHasCreateAccess(user: $user);
    }
}

Question is if there are some way to test Policy checking in http tests, where usually I use actingAs method to simulate user logged:

  $taskModel = Task::factory()->userId(self::$loggedUser->id)->make();  // model only in memory

     $response = $this
         ->actingAs(self::$loggedUser, 'sanctum')
         ->postJson(route('tasks.store'), $taskModel->toArray());
     $response
         ->assertStatus(JsonResponse::HTTP_CREATED); // 201

Which tests are possible here ?

0 likes
3 replies
martinbean's avatar

@mstdmstd Just mock the policy class to return whatever result you want:

public function testCanCreateTask(): void
{
    $this->mock(TaskPolicy::class, function (MockInterface $mock): void {
        $mock->shouldReceive('create')->once()->andReturnTrue();
    });

    $this
        ->actingAs(static::$loggedUser, 'sanctum');
        ->postJson('/tasks', $taskModel->toArray())
        ->assertCreated();
}

public function testCannotCreateTask(): void
{
    $this->mock(TaskPolicy::class, function (MockInterface $mock): void {
        $mock->shouldReceive('create')->once()->andReturnFalse();
    });

    $this
        ->actingAs(static::$loggedUser, 'sanctum');
        ->postJson('/tasks', $taskModel->toArray())
        ->assertForbidden();
}
1 like
mstdmstd's avatar

@martinbean Please give a link where "mock" is explained. That is not in my prior expierence

Please or to participate in this conversation.