Reputation: 395
I am using Laravel policies to control authorisation on my api routes. I want to only allow the current user to update their own post. This works fine when i manually run it through the application, but the unit tests fail. The unit tests, redirect to the login screen.
route:
Route::post('/posts/{post:reference}/editDetails', [PostDetailsApiController::class, 'update'])
->middleware('can:update,post');
policy:
public function update(User $user, Post $post)
{
return $post->user_id === $user->id;
}
unit test:
$this->user = User::factory()->create();
$post = Post::factory()->create(['user_id' => $this->user->id]);
Passport::actingAs($this->user);
$response = $this->call('POST', 'http://test/api/posts/' . $post->reference . '/editDetails');
$response->assertStatus(200);
but this test fails saying 'Failed asserting that 200 is identical to 302'. If i add followingRedirects() and actingAsClient then it passes. If i dd in the controller, it doesnt get fired, so i'm pretty sure the controller isnt getting hit? if i remove the middleware, it runs fine. any advice welcomed. thanks
Upvotes: 0
Views: 529
Reputation: 18976
This has nothing to do with the policy as the status code 302 is a redirect. The problem lies within this snippet.
$this->call('POST', 'http://test/api/posts/' . $post->reference . '/editDetails');
Normally you would call it with a relative URL
.
$this->call('POST', 'api/posts/' . $post->reference . '/editDetails');
A better approach is to use the route helper for named routes. I have a example project, where i used this approach.
$this->call('POST', route('posts.edit-details', ['reference' => $post->reference]));
Remember to add a name to your route.
Route::post('/posts/{post:reference}/editDetails', [PostDetailsApiController::class, 'update'])
->middleware('can:update,post')
->name('posts.edit-details');
Upvotes: 2