Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to reload Auth::user() when doing integration testing

This is a follow up of How to wait for a page reload in Laravel integration testing

What I am doing is to edit a user's profile and then redisplay the view.

My profile action: (UserController)

public function profile(){
    return view('user/profile');
}

The view contains code like

{{ Auth::user()->firstname }}

now during my test, the old (unchanged) user data is displayed.

The test:

protected function editUserProfile()
{
    $this->visit('/user/profile');
    $firstName = $this->faker->firstname;
    $lastname = $this->faker->lastname;

    $this->within('#userEditForm', function() use ($firstName, $lastname) {
        $this->type($firstName, 'firstname');
        $this->type($lastname, 'surname');
        $this->press('Save')
            ->seePageIs('/user/profile')
            ->see($firstName)   # here the test fails
            ->see($lastname);
    });
}

When I change the UserController like this:

public function profile(){
    Auth::setUser(Auth::user()->fresh());
    return view('user/profile');
}

everything works fine.

Now I want to understand, why that is like this.

Why does the integration test behave differently to the browser in that case? Is there a better way to align that behavior so the tests do only fail if there is a "real problem"? Or is my code just bad?

like image 337
Alex Avatar asked Oct 06 '16 09:10

Alex


1 Answers

You're probably using update (int $uid) for the request?

The most likely explanation is that Laravel only uses a single application instance during the test. It's taking the input you give it, building a request object, and then sending it to the controller method. From here it can render the view and check that it contains your text.

In the authentication implementation once you call Auth::user() it doest one of two things:

  • If no user is loaded it attempts to retrieve it from storage.
  • If a user is already loaded it returns it.

Your update method (I'm guessing) is retrieving a new instance of the user from storage and updating it, not the cached one.

For example:

\Auth::loginUsingId(1234);
\Auth::user()->email; // '[email protected]'

$user = \App\User::find(1234);
$user->email; // '[email protected]';

$user->update(['email' => '[email protected]']);
$user->email; // '[email protected]'

\Auth::user()->email; // '[email protected]'
like image 174
Sturm Avatar answered Oct 03 '22 18:10

Sturm