PhantomWalrus's avatar

How to test Lumen API when retrieving the logged in user's ID in controller constructor?

I'm trying to test CRUD operations for my Lumen controllers. The constructor for each controller looks similar to this:

  private $loggedInUserId;

  public function __construct(Request $request) {
      $this->loggedInUserId = $request->user()->userId;
  }

And here's my test:

  public function testShowOneItemReturnsOnePayroll() {
    $this->withoutMiddleware();
    $this->json('GET', "intranet");
    $this->seeJsonStructure([
      'data' => [
        'prId',
        'userId',
        'firstName',
        'lastName',
        ...
      ]
    ]);
  }

I get this error when running the test:

PHPUnit\Framework\InvalidArgumentException: Argument #2 of PHPUnit\Framework\Assert::assertArrayHasKey() must be an array or ArrayAccess

However, The test is successful when I comment out the $loggedInUserId variable and its constructor initialization.

Question

How can I retrieve the user ID in my controllers and still get my tests to pass?

0 likes
2 replies
hotsaucejake's avatar
Level 6

The test works when you comment out the __construct() because you're not logged in as a user (in the test).

One thing you could try with that line is $this->loggedInUserId = $request->user()?->userId; and see what it outputs for your knowledge.

But since you're testing if someone is authenticated and they're not authenticated in your test, then you should use the actingAs function.

public function testShowOneItemReturnsOnePayroll() {
    $user = factory('App\User')->create();

    $this->withoutMiddleware();
    $this->actingAs($user)->json('GET', "intranetapps/v1/payroll/3");
    $this->seeJsonStructure([
      'data' => [
        'prId',
        'userId',
        'firstName',
        'lastName',
        ...
      ]
    ]);
  }

This is also assuming that the id column on your users table is labeled 'userId' and not 'id'

But the fact remains is that your test is withoutMiddleware which removes the authentication middleware and in your controller you're explicitly asking for a user although one isn't set - and it's not gracefully handled when you try to access an attribute on null.

2 likes
PhantomWalrus's avatar

@hotsaucejake Thank you! For any future readers, I had to make a little adjustment to this answer, because laravel's Model factory was changed., as mentioned here in the documentation. I was unable to reference the factory() method directly.

I created a UserFactory in my database\factories directory and referenced it like so in my test:

  public function testShowAllItemsReturnsAllPayrollRecords() {
    $user = UserFactory::new()->create();
    $this->withoutMiddleware();
    $this->actingAs($user)->json('GET', 'intranet');
    ...
}

Please or to participate in this conversation.