Hi there. First of all, thanks for the awesome work.
I'm writing unit tests for my API. When I use WithoutMiddleware, work's fine. But there is some endpoints that I need to parse the current user:
$user = JWTAuth::parseToken()->authenticate();
When I need this, I write my tests like this:
$user = factory(User::class)->create(['active' => 1]);
$token = JWTAuth::fromUser($user);
$headers['authorization'] = 'Bearer ' . $token;
$server = $this->transformHeadersToServerVars($headers);
$data = factory(Product::class)->make(['title' => 'Lorem Ipsum'])->toArray();
$response = $this->call('POST', '/api/v1/itens', $data, [], [], $server);
But in the test above, I always get an JWTException. Researching more, I checked the Tymon\JWTAuth\JWTAuth class, parseAuthHeader method. The headers authorization simply don't exists. So, I changed the method to:
protected function parseAuthHeader($header = 'authorization', $method = 'bearer')
{
// $header = $this->request->headers->get($header);
$header = request()->headers->get($header);
if (! starts_with(strtolower($header), $method)) {
return false;
}
return trim(str_ireplace($method, '', $header));
}
This work's fine. A think the Request object passed into the __construct method is not the same. Don't know exactly if it is a Laravel problem or a package problem (or I'm doing something wrong).
A think the Request object passed into the __construct method is not the same.
You're correct. During tests, Laravel constructs the Request object a bit differently. The problem is that, in production, Laravel is booted with an incoming request, but in testing it has to create a placeholder, while it waits for you run $this->call or a similar function. Thus, the Request object that gets injected during construct isn't exactly the one you want. (Which I believe is why jwt-auth no longer injects it in v1.0)
One option you have is to set the request manually:
$user = JWTAuth::setRequest($request)->parseToken()->authenticate();
(Of course, the middleware already uses setRequest like this, so it might just be simpler to enable the middleware for these specific tests.)
Oh, now I get it. I just enable the middlewares from test's like this and it worked correctly. Thanks!
@luisdalmolin, could you share your test code?
thanks
In most tests, I just enabled the middleware and it worked.
But in some tests, I had to do this in some controllers:
if ((app()->environment() == 'testing') && array_key_exists('HTTP_AUTHORIZATION', \Request::server())) {
JWTAuth::setRequest(\Route::getCurrentRequest());
}
It's not the ideal but it's better to have this and a test that really test something.
Hope it helps.
@luisdalmolin Thanks a lot for your reply :)
Most helpful comment
In most tests, I just enabled the middleware and it worked.
But in some tests, I had to do this in some controllers:
It's not the ideal but it's better to have this and a test that really test something.
Hope it helps.