Login as multiple users during same test - Laravel and PestPHP

1.7k views Asked by At

I'm trying to run a single test where multiple users are performing actions. There is either a bug in the actingAs() function, or I am completely missing something trivial. So here's the scenario. I have a social media site. I want to login as one user, perform an action (follow another user), then login as the other user and submit a post. The first user passed into the actingAs function persists throughout all subsequent actions, even when I explicitly call actingAs for the 2nd user, or even use my logout route to try and logout the first user. Here is the code:

//Create the user that will make the post
$user = User::factory()->subscriber()->active()->create();

//Create the user that will follow the first user
$follower = User::factory()->subscriber()->active()->create();

//Login as the 'follower' and perform the action to follow the first user
$this->actingAs($follower)->post('/ajax/follow/User/'.$user->id);

//Now, try to login as the first user and make the post
$request = ['id' => 1,'body' => 'I have a body'];
$response = $this->actingAs($user)->post('/posts/add',$request);

The above fails because, even though I call actingAs($user) on the last line, when I data dump the authorized user, I find that I am still logged in as $follower, even though I've specifically tried to make the post as $user. I've tried putting manual Auth::logout() functions inline, I've tried hitting the logout route while acting as $follower, and a few other things. No matter what, it seems that the first user that you actAs becomes the only user that you can act as during a single test.

Does anybody have any experience with this and how to solve the issue? Thanks in advance.

3

There are 3 answers

0
trofusha On

In laravel 9

$this->actingAs($follower)->post('/ajax/follow/User/'.$user->id);
Auth::forgetGuards(); 
Auth::shouldUse('web');
$request = ['id' =>1,'body' => 'I have a body']; 
$response = $this->actingAs($user)->post('/posts/add',$request);
5
William Martins On

I came across the same problem and I did this:

$this->app->get('auth')->forgetGuards();

between my requests

So your code should look like this:

//Create the user that will make the post
$user = User::factory()->subscriber()->active()->create();

//Create the user that will follow the first user
$follower = User::factory()->subscriber()->active()->create();

//Login as the 'follower' and perform the action to follow the first user
$this->actingAs($follower)->post('/ajax/follow/User/'.$user->id);

$this->app->get('auth')->forgetGuards();

//Now, try to login as the first user and make the post
$request = ['id' => 1,'body' => 'I have a body'];
$response = $this->actingAs($user)->post('/posts/add',$request);
0
TheOneDaveYoung On

A little late to the party but... I humbly (and completely) disagree with the opinion that a feature test should be limited to a single atomic "thing". IMO that's what unit tests are for, to test a single "unit" of something.

A feature test should be able to test a chain of events. Otherwise our test classes would end up being MASSIVE and so bloated it would be impossible to find and fix an issue, not to mention the extra time it would take to execute tests due to the fact that each and every one would have to re-initialize the test environment.

Anyway...

I had a similar issue recently and found that if I flushed the session between calls the issue is resolved. From my perspective, actingAs() or be() should do this for us but .

So this will hopefully do the trick as it does for me:

$this->actingAs($follower)->post('/ajax/follow/User/'.$user->id);
Session::flush()
$request = ['id' =>1,'body' => 'I have a body']; 
$response = $this->actingAs($user)->post('/posts/add',$request);