Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

AndrykVP's avatar

How to Test API endpoints on Isolated Package

I'm developing an isolated Package for Laravel 8 and I've decided to create PHPUnit Tests to make sure I don't break anything while improving/refactoring my code. I just ran into a problem while attempting to test unauthorized access to an API endpoint, using the default auth:api guard provided by Laravel since before version 7 (which still works in 8), but instead of returning a Status Code of 401, it returns 500 (Server Error).

This is my Test file so far:

function guest_cannot_access_permission_api_index()
{
   $response = $this->getJson(route('api.auth.permissions.index'));
   $response->assertUnauthorized();
}

/** @test */
function user_cannot_access_permission_api_index()
{
   $response = $this->actingAs($this->user, 'api')->getJson(route('api.auth.permissions.index'));
   $response->assertUnauthorized();
}

/** @test */
function admin_can_access_permission_api_index()
{
   $response = $this->actingAs($this->admin, 'api')->getJson(route('api.auth.permissions.index'));
   $response->assertSuccessful()->assertJsonCount(15, 'data');
}

Both, guest and admin functions work, but the user one doesn't. The way I handle authorization for this route is with the following Policy:

public function before(User $user, $ability)
{
    if($user->is_admin) return true;
}

public function viewAny(User $user)
{
    return $user->hasPermission('view-permissions')
            ? Response::allow()
            : Response::deny('You do not have permissions to view permissions.');
}

And finally, the $user->hasPermission() method is done with this Trait:

public function hasPermission($param)
{
    if($this->is_admin) return true;

    if($this->roles()->exists())
    {
        $permissions = $this->roles()->with('permissions')->get()->pluck('permissions')->collapse()->merge($this->permissions)->unique();

        return $permissions->contains('name', $param);
    }
    if($this->permissions()->exists())
    {
        return $this->permissions->contains('name', $param);
    }
    
    return false;
}

I can't seem to figure out what the problem is with the user function of my test. The only issue that came to mind at first, was that the auth:api guard uses an api_token column on the Users table, which is not added by my package's migrations, so I went on and added a temporary migration to add this column, but the problem persists in PHPUnit and not when testing it manually with Insomnia, where I do get the expected 401 error code.

Any help or insight would be appreciated. Thanks

0 likes
3 replies
martinbean's avatar

@andrykvp Add ->withoutExceptionHandling() before you make the HTTP request and it will display the error causing the 500 response in your terminal.

1 like
AndrykVP's avatar

Thanks, that helps a bit. I'll certainly use it in the future if I need to find what the problem in PHP is. In this particular case, this is what I got:

TypeError: Illuminate\Routing\Middleware\ThrottleRequests::addHeaders(): Argument #1 ($response) must be of type Symfony\Component\HttpFoundation\Response, null given, called in /Users/andrykvp/Dev/PHP/packages/Rancor/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php on line 133

Would you happen to know what's missing in the request?

AndrykVP's avatar
AndrykVP
OP
Best Answer
Level 2

I just figured it out!

I was using a custom Middleware that was not returning anything if a condition failed; thus the. null given in the error message. Thanks @martinbean for pointing out the ->withoutExceptionHandling() method, it definitely helped :)

1 like

Please or to participate in this conversation.