Skip to content

Documentation on mocking users in feature and unit tests #467

@joshembling

Description

@joshembling

Checklist

Description

I am really struggling to figure out how to simply mock a user so that I can test web and api routes.

I have a bundle of routes wrapped in the auth0 middleware for SSO. All of this works as expected.

Route::middleware('auth0.authenticate')->group(function (): void { // ...

However, in my feature and unit every single request I make is a 302 redirect. To state the obvious, when I take the routes out of this middleware, the requests work as expected.

This is my User model:

class User extends Model implements AuthenticatableContract, AuthorizableContract
{
    use Authenticatable;
    use Authorizable;
    use HasApiTokens;
    use HasFactory;
    use Notifiable;

I have tried the following in my tests:

use Auth0\Laravel\Traits\Impersonate;

class ControllerTest extends TestCase
{
    use WithFaker, Impersonate;
  
    public function test_impersonation_as_session_user()
    {
        $user = User::factory()->create();
    
        $cred = CredentialEntity::create($user);
        Auth::login($cred);
    
        // Impersonate the user
        $this->impersonate($cred);
    
        // Perform some action.
        $response = $this->get('/');
        $response->assertStatus(200); // 302
    }

    public function test_impersonation_as_session_user()
    {
        // Create a mock credential.
        $mockCredential = $this->createMock(CredentialEntityContract::class);
        $mockCredential->method('getUser')->willReturn(new ImposterUser([
            'id' => 1,
            'name' => 'Test User',
            'email' => '[email protected]',
        ]));

        /** @var CredentialEntityContract $mockCredential */
        $this->impersonate($mockCredential, \Auth0\Laravel\Guards\GuardContract::SOURCE_SESSION);

        // Assert the user is authenticated.
        $this->assertAuthenticated();
        $this->assertEquals(auth()->user()->id, 1);

        // Perform some action.
        $response = $this->get('/');
        $response->assertStatus(200); // 302
    }
}

This is the only thing I've been able to get to work, but this is not correct:

    public function test_impersonation_as_session_user()
    {
        Route::middleware([])->group(function () {
            Route::get('/', [DashboardController::class, 'dashboard'])->name('dashboard');
        });

        $user = User::factory()->create();

        $this->actingAs($user);

        // Perform some action.
        $response = $this->get('/');
        $response->assertStatus(200); // 200
    }

Please can someone shed some light on how this is supposed to work properly in phpunit and/or pest.

I don't mind writing some documentation if someone can contribute a working answer. Thank you 🙏

Metadata

Metadata

Assignees

No one assigned

    Labels

    Scope: DocumentationProposed changes to the README or other documentation.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions