Jwt-auth: [Question] Generate a Token when testing with PHPunit

Created on 13 Jan 2015  路  3Comments  路  Source: tymondesigns/jwt-auth

Hello,

I would like to know if you can give a little hand here. Im using your package (L5 branch) to secure some of my API uri's.
So now decided to dive in the testing world(nood here) and I can't seem to get this right when testing a protected uri.

$this->call('GET', 'v1/me', [], [], [], ['HTTP_Authorization' => 'Bearer <token here>' ]);

If I hard code the token in the call method it works fine but off course I first wanna get a User from my testing DB and then generate a token to pass it the call method(if this even make sense for a test)

Do you have a small example on how to this or point me in some direction?

Thanks in advance,
Helder

Most helpful comment

Thank you @denaje for the code. That helped a ton. Here is a slightly revised version that functions more like the parent call method.

Extend the TestCase class with:

    protected function createAuthenticatedUser()
    {
        $this->user  = factory(App\Models\User::class, 'test')->create();
        $this->token = JWTAuth::fromUser($this->user);
        JWTAuth::setToken($this->token);
        Auth::attempt(['username' => $this->user->username, 'password' => $this->user->password]);
    }

    protected function callAuthenticated($method, $uri, array $data = [], array $headers = [])
    {
        if ($this->token && !isset($headers['Authorization'])) {
            $headers['Authorization'] = "Bearer: $this->token";
        }

        $server = $this->transformHeadersToServerVars($headers);

        $this->call(strtoupper($method), $uri, $data, [], [], $server);

        return $this;
    }

Then use in tests like any other method:

    public function testGetUser()
    {
        $this->createAuthenticatedUser();
        $this->callAuthenticated('GET', route('auth::user'))->seeJsonStructure(['id']);
    }

All 3 comments

Hi. Did you managed to get your tests working ? I have the same problem and could use some help.

Not OP, but here's how I did this in my code.

For most tests, I need to be logged in but I don't want to test auth, so I have this function in my base TestCase class that logs in as a specific user that I call before running each test:

    protected function login($user_id = 1)
    {   
        $user = User::find($user_id);
        $this->token = JWTAuth::fromUser($user);

        JWTAuth::setToken($this->token);

        Auth::login($user);
    }

Every time I call a route, I then pass in the token in the headers:

    protected function callRoute($method, $route, $data = [], $headers = [])
    {
        if ($this->token && !isset($headers['Authorization'])) {
            $headers['HTTP_Authorization'] = "Bearer: $this->token";
        }

        return $this->call(
            $method,
            "/api$route",
            [],
            [],
            [],
            $headers,
            json_encode($data)
        );
    }

For testing auth itself, I do this:

    public function testLogin()
    {
        $this->seed('UserSeeder');

        // callRoute's parameters: 1. Method  2. Url  3. Data  4. Headers
        $resp = $this->callRoute('POST', '/auth', ['email' => '[email protected]', 'password' => 'password']);
        $this->assertOk($resp);

        // Get the token
        $data = json_decode($resp->getContent(), true);
        $this->assertArrayHasKey('token', $data);

        // At this point, I could call another api endpoint and pass in the token. Something like this:
        // $this->callRoute('POST', '/example', $data, ['HTTP_Authorization' => 'Bearer: ' . $data['token']]);
    }

$this->callRoute and $this->assertOk are custom shortcut functions that I wrote to avoid lots of boilerplate.

Thank you @denaje for the code. That helped a ton. Here is a slightly revised version that functions more like the parent call method.

Extend the TestCase class with:

    protected function createAuthenticatedUser()
    {
        $this->user  = factory(App\Models\User::class, 'test')->create();
        $this->token = JWTAuth::fromUser($this->user);
        JWTAuth::setToken($this->token);
        Auth::attempt(['username' => $this->user->username, 'password' => $this->user->password]);
    }

    protected function callAuthenticated($method, $uri, array $data = [], array $headers = [])
    {
        if ($this->token && !isset($headers['Authorization'])) {
            $headers['Authorization'] = "Bearer: $this->token";
        }

        $server = $this->transformHeadersToServerVars($headers);

        $this->call(strtoupper($method), $uri, $data, [], [], $server);

        return $this;
    }

Then use in tests like any other method:

    public function testGetUser()
    {
        $this->createAuthenticatedUser();
        $this->callAuthenticated('GET', route('auth::user'))->seeJsonStructure(['id']);
    }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

heroghost picture heroghost  路  3Comments

agneshoving picture agneshoving  路  3Comments

NaelsonBrasil picture NaelsonBrasil  路  3Comments

loic-lopez picture loic-lopez  路  3Comments

therealmjk picture therealmjk  路  3Comments