ThePoet444's avatar

testing that a user can edit profile

Simple enough situation, a user can edit their own profile. Run it through a browser test, works like a charm. Make a test for it... well now we have something interesting.

/** @test */
    function auth_user_can_edit_own_profile()
    {
        $user = factory('App\User')->create();
        $user->setProfile();  //this just makes an empty profile so a 1-1 relation exists
        $this->actingAs($user);
        $response = $this->post('profile/'.$user->id.'/update',[
            'quote'=>'Hello World',
        ]);
        $response->assertSee('Hello World');
    }

I get a failure. what displays on the screen is a redirect to the main page. O.o Nothing in my code should make that happen.

I believe it has something to do with my form request's authorize() method. However, I fail to see how. I have tried using $this->withoutExceptionHandling() in my test with no change.

storeProfile form request:

public function authorize()
    {
        $profile = $this->route('profile');
        if ($this->user()->can('edit profile') || $this->user()->id == $profile->user_id)
        {
            return true;
        }
        return false;
    }


Profile Controller update:

public function update(storeProfile $request, Profile $profile)
    {
        $profile->update($request->except('name'));
        $profile->save();

        if($profile->user->name != $request->input('name'))
        {
            $profile->user()->update(['name' => $request->input('name')]);
            //TODO event to track name changes
        }

        return redirect()->action('ProfileController@show',['id' => $profile->user_id]);
    }

Any insights to this would be really helpful, but I truly don't understand what is happening. Thank you all for taking the time to read and help!

0 likes
10 replies
Tray2's avatar

Does it work if you remove the authorize and acting as?

jasonfrye's avatar

Shouldn't you be passing the profile id to the post route rather than the user's?

ThePoet444's avatar

@tray2 if I just return true in the authorize method, the test still fails with the redirect. Manual browser testing remains fine.

@jasonfrye I have getRouteKeyName() set to the user_id in the profile model for simplicity sake. Since I will never get a profile without a user, and since the user is tied into everything it just makes things easier code wise. For me anyway.

jasonfrye's avatar

That makes sense. I wasn't sure with what was provided.

mariohbrino's avatar

In your controller you are expecting a field as name, in your test you are passing a field as quote.

mariohbrino's avatar

Since you are updating the current user profile, I dont think you should allow the user to pass the id.

You can fetch the current user and update what you need.

$profile = auth()->user()->profile();

Make sure that you have the relationship in your model to make it work.

// User.php

public function profile ()
{
    return $this->hasOne('App/Profile');
}
ThePoet444's avatar

That's the point of the test though, to see if someone who passes an id through can get an edit through.

The profile table has a lot of info in it other than name. passing the quote through is just a random field I picked that's quick to view on the site.

mariohbrino's avatar

That's why you have the fillable in your model, to avoid that the user can change sensitive information. You need to know what you allow the user to do.

p4rz1val's avatar

Try $this->flushSession(); at the start of your test, if your already authenticated a user in another test then you can't log in until you logout / flush the session, basically, if you are authenticated you can't authenticate, there´s a RedirectIfAuthenticated middleware in Laravel.

ThePoet444's avatar

@mariohbrino chaning the fillable field to an empty guarded field makes no difference. I still get the same response to the test. Even if I specify everything in the fillable field.

@p4rz1val A good thought, however it made no change.

Let me know if you need me to post any other data. I'm scratching my brain on this one.

Please or to participate in this conversation.