Kenshirou's avatar

HttpException thrown after performing test

I'm having trouble to get it to pass the test at 5min video of Build a Laravel App with TDD. This is the code:

use App\User;
use App\Models\Project;
...
/** @test */
public function a_user_can_view_their_project()
{
$this->be(factory(User::class)->create());

$this->withoutExceptionHandling();

$project = factory(Project::class)->create(['owner_id' => auth()->id()]);

$this->get($project->path()) ->assertSee($project->title) ->assertSee($project->description); }

When I run this test, it says:

There was 1 error:

  1. Tests\Feature\ProjectsTest::a_user_can_view_their_project Symfony\Component\HttpKernel\Exception\HttpException

These are my routes:

Route::get('/', function () { return view('welcome'); });

Route::get('/projects', 'ProjectsController@index')->middleware('auth'); Route::get('/projects/{project}', 'ProjectsController@show')->middleware('auth'); Route::post('/projects', 'ProjectsController@store')->middleware('auth');

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

0 likes
8 replies
tykus's avatar

It could be any number of issues, does the stacktrace of the test not give more information whenever you disable exception handling?

I would be checking if the project is getting created, and assigned to the authenticated user (is owner_id fillable? Does the $project->path() expression produce the expected URI? Are your namespaces correct; the Project model is in a different namespace compared with User model?

Kenshirou's avatar

@TYKUS - Hi, Tykus. Thank you for answering my question. I tried both approaches: commenting and uncommenting the line $this->withoutExceptionHandling() before I ran the test. It displayed the same HttpException error.

Is owner_id fillable? Yes. Both User and Project models inherits from EloquentModel that has defined the line 'protected $guarded = []'. EloquentModel inherits from 'Illuminate\Database\Eloquent\Model'.

The line $project->path() returns the string: /projects/the_id_of_current_project. I dd() comparing it with the string '/projects' . $project->id, and it was the same.

Both Project and User models are in different namespaces yes. Project namespace is App\Models\Project while User namespace is App\User. But I added the correct use line on each file that they are used.

Also I checked and the owner_id is the same as auth()->user()->id. I think the error is thrown at the get request, but don't know why since I already have defined the get route at web.php.

Any other suggestion?

tykus's avatar

Ok, what does the full stacktrace look like whenever you disable exception handling?

Kenshirou's avatar

@TYKUS - This is the stack trace when $this->withoutExceptionHandling is enabled:

There was 1 error:

1) Tests\Feature\ProjectsTest::a_user_can_view_their_project
Symfony\Component\HttpKernel\Exception\HttpException:

/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:967
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:46
/Users/emanuel/Sites/laravel-sample-projects/birdboard/app/Http/Controllers/ProjectsController.php:32
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:45
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Route.php:219
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Route.php:176
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Router.php:682
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:30
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php:41
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php:43
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:75
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php:49
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:63
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php:37
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:66
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Router.php:684
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Router.php:659
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Router.php:625
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Router.php:614
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:176
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:30
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/fideloper/proxy/src/TrustProxies.php:57
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:31
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:31
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php:27
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php:62
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:151
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:116
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:345
/Users/emanuel/Sites/laravel-sample-projects/birdboard/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:168
/Users/emanuel/Sites/laravel-sample-projects/birdboard/tests/Feature/ProjectsTest.php:69

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
The terminal process terminated with exit code: 2

From that stack trace, it is shown that the source of the problem might be ProjectsController.php:32. That is the following:

public function show(Project $project)
{
  if (auth()->id() !== $project->owner_id) {
    abort(403);          // line 32
  }

  return view('projects.show', compact('project'));
}

After replacing the !== for !=, the exception is not thrown and the test pass green. Is it possible that even if auth()->id() represents the same value as owner_id it might be an object representing an integer for example instead of an actual integer and that's the reason why it is throwing the exception by using (!==)?

tykus's avatar
tykus
Best Answer
Level 104

More likely, it is an int compared with a string.

Eloquent models have an is() method which is a very readable way to write that same expression:

if (! auth()->user()->is($project->owner)) {
    abort(403);
}

Or even better, since it does exactly what it says:

abort_unless(auth()->user()->is($project->owner), 403);
Kenshirou's avatar

@TYKUS - Thanks again. The first expression works:

if (auth()->user()->is($project)) {
  abort(403);
}

The expression auth()->user()->is($project->owner_id) throws the FatalThrowableError 'Call to a member function getKey() on string. But aborting when auth()->user()->is($project) doesn't make sense to me.

But when I tried using the abort_unless it throws the same HttpException:

Either

abort_unless(auth()->user()->is($project), 403) 

or

abort_unless(auth()->user()->is($project->owner_id), 403)
tykus's avatar

Did you read my answer at all?

I mentioned that the expression was readable, so read auth()->user()->is($project) and tell me that it makes sense? You are asking if the authenticated user is the project; whereas you should be asking if the authenticated user is the project owner!

auth()->user()->is($project->owner)

This assumes a belongs to relation on the Project model called owner

public function owner() 
{
    return $this->belongsTo(User::class, 'owner_id');
}
Kenshirou's avatar

@TYKUS - Thanks and sorry for the misunderstanding. I'm still learning. I thought that owner was a typo for owner_id instead of an eloquent relationship. I understand now why using is($project->owner_id was raising errors. You are absolutely right. It is more readable and it makes sense.

Please or to participate in this conversation.