5

Laravel v5.7.1

I have multiple tests with same assertions and want to move them in one function and call it from tests. Here is example of function:

private function admin_only($url, $method = 'GET', $data = []) {
    // \Auth::logout();
    $response = $this->json($method, $url, $data);
    $response->assertStatus(401);
    $response = $this->actingAs($this->user(),'api')->json($method, $url, $data);
    $response->assertStatus(403);

    $response = $this->actingAs($this->admin(),'api')->json($method, $url, $data);
    $response->assertStatus(200);
}

In this I firstly check for unauthenticated user and everything works as expected, but there are some functions, where API calls toggle some state, so I want to revert it back by calling function second time:

$this->admin_only('/api/service/toggle-state', 'POST', $data);
$this->admin_only('/api/service/toggle-state', 'POST', $data);

And second call in same test results in failure because first $this->json() used as admin and returns success code.

That \Auth::logout() supposed to solve problem, but instead throws error BadMethodCallException: Method Illuminate\Auth\RequestGuard::logout does not exist.

Solutions like "Separate test for second call", "No toggle revert", "Same response code for non-admin users and guests" should work, but seems wrong for me.

Jakupov
  • 1,656
  • 2
  • 11
  • 14

2 Answers2

7

Luckily RequestGuard is Macroable, so we can extend it with our own methods. Try to do the following:

use Illuminate\Auth\RequestGuard;

// ...

RequestGuard::macro('logout', function() {
    $this->user = null;
});

$this->app['auth']->guard('api')->logout(); // or omit `->guard('api')` part

This is opposite of what ->actingAs does. All the following requests will not have the authenticated user.

This can be added to the base test class as a method, and then used as $this->actingAsGuest() or something similar. Anyway, it would be convenient to have this by default in Laravel.

Damir Miladinov
  • 1,224
  • 1
  • 12
  • 15
  • Should be the accepted answer. You can also use the `Auth` facade to logout – andrewtweber Jul 14 '20 at 22:19
  • @andrewtweber using the Auth facade for me results in the sam error. – digout May 10 '21 at 12:40
  • Thank you Damir. While the answer itself lead me to the correct direction, it unfortunately didn't actually solve the issue. Then I found this detailed explanation https://stackoverflow.com/a/57941133/741782 from @patricus – gorodezkiy Apr 25 '22 at 18:49
0

it might you have different guards >> so this might work

Auth::guard('admin')->logout();

you can change 'admin' to whatever the guard name

  • Unfortunately, it doesn't. I have 2 default laravel guards for auth, and this is `api` one `['middleware' => ['auth:api']`. `\Auth::guard('api')->logout();` throws same error – Jakupov Nov 07 '18 at 12:41