Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ajsmith_codes's avatar

Newbie needs help testing.

I am building on the app Birdboard that was created in the TDD series. I have a bunch of tests from that series that already work, but I'm lacking one to test for updates to the task body of a project. What I'm having trouble with is getting the value of the task.

Here is what I have so far:

function test_updating_a_task() { $this->withoutExceptionHandling();

    $project = ProjectFactory::withTasks(1)->create();

    $this->actingAs($project->owner)
        ->patch($project->tasks[0]->path(), [
            'body' => 'foobar',
            'updated' => true
        ]);

    $this->assertCount(3, $project->activity);

    $this->patch($project->tasks[0]->path(), [
        'body' => 'foobar',
        'updated' => false
    ]);

    $project->refresh();

    $this->assertCount(4, $project->activity);

    $this->assertEquals('updated_task', $project->activity->last()->description);
}

This is the existing Update method in my ProjectTasksController:

public function update(Project $project, Task $task)
{

    $this->authorize('update', $task->project);

    $task->update(request()->validate(['body' => 'required']));


    //catch the changes to the task body and if it changes with complete or incomplete
    request('completed') ? $task->complete() : $task->incomplete();

    return redirect($project->path());
}
0 likes
33 replies
zoltiecodes's avatar

Well you changed the code in your post in the meantime... Now it's not clear what do you want to do.

ajsmith_codes's avatar

Unfortunately, I get a "no such column: body"

The projects table doesn't have a body, but tasks does. That's telling me I'm not getting the property value.

I changed the test code based on another test in the file:

$project = ProjectFactory::withTasks(1)->create();

$this->actingAs($project->owner)
    ->patch($project->tasks[0]->path(), [
        'body' => 'foobar',
        'updated' => true
    ]);

$this->assertCount(3, $project->activity);

$this->patch($project->tasks[0]->path(), [
    'body' => 'foobar',
    'updated' => false
]);

$project->refresh();

$this->assertCount(4, $project->activity);

$this->assertEquals('updated_task', $project->activity->last()->description);

} to this:

ajsmith_codes's avatar

Wow, I'm making a mess of this. Sorry about that! Should I go back to the original code? I'm still trying to get the value of the task.

zoltiecodes's avatar

Well your original code should work. 😀 The problem was that you tried to compare the string 'updated' to your Task model. Can you try my solution above with the original code you posted? If doesn't work post the code again please.

ajsmith_codes's avatar

Ok, I changed it back (I think). I get "Trying to get property 'body' of non-object'

Here is what I have:

function test_updating_a_task()
{
    $this->withoutExceptionHandling();

    $project = ProjectFactory::withTasks(1)->create();

    $originalTask = $project->task->body;

    $project->update(['body' => 'Changed']);

    $this->assertCount(2, $project->activity);

    tap($project->activity->last(), function ($activity) use ($originalTask) {
        $this->assertEquals('updated_task', $activity->description);

        $expected = [
            'before' => ['body' => $originalTask],
            'after' => ['body' => 'Changed']
        ];

        $this->assertEquals($expected, $activity->changes);
    });
}
ajsmith_codes's avatar

For this I'm using ProjectFactory:

$factory->define(App\Project::class, function (Faker $faker) { return [ 'title' => $faker->sentence(4), 'description' => $faker->sentence(4), 'notes' => 'fake notes', 'owner_id' => factory(App\User::class) ]; });

Should I be using TaskFactory instead:

$factory->define(App\Task::class, function (Faker $faker) { return [ 'body' => $faker->sentence, 'project_id' => factory(\App\Project::class), 'completed' => false ]; });

ajsmith_codes's avatar

I tried a dd() right after declaring $originalTask and the result is null.

Is there something else I should try? Like I said, I'm a major newbie. :)

ajsmith_codes's avatar

Also, it appears that the ProjectFactory I'm referring to is a test, not a factory:

public function create() { $project = factory(Project::class)->create([ 'owner_id' => $this->user ?? factory(User::class) ]);

    factory(Task::class, $this->tasksCount)->create([
        'project_id' => $project
    ]);

    return $project;
}
ajsmith_codes's avatar

@zsoltgyure I changed task to tasks and got the values. $originalTask = $project->tasks;

However, if I try to add ->body on the end, I get Property [body] does not exist on this collection instance.

zoltiecodes's avatar

Great! Do this now:

$originalTask = $project->tasks->first()->body;

I hope your Project Factory creates the project and the task too. :D If it does - the code above should work...

ajsmith_codes's avatar

If I do another dd, I get "Aut qui atque temporibus fugit et." as the value. However, if I take out the dd, it fails again with Illuminate\Database\QueryException : SQLSTATE[HY000]: General error: 1 no such column: body (SQL: update "projects" set "body" = Changed, "updated_at" = 2020-03-31 15:53:04 where "id" = 1)

I did another dd right after this line: $project->update(['body' => 'Changed']); and get the same error.

I think I must be checking for the project change instead of task change. I tried changing that line of code to this:

$originalTask->update(['body' => 'Changed']); but that didn't work.

ajsmith_codes's avatar

@zsoltgyure

Updated code:

function test_updating_a_task()
{
    $this->withoutExceptionHandling();

    $project = ProjectFactory::withTasks(1)->create();

    $originalTask = $project->tasks->first()->body;

    tap($project->activity->last(), function ($activity) use ($originalTask) {
        $this->assertEquals('updated_task', $activity->description);

        $expected = [
            'before' => ['body' => $originalTask],
            'after' => ['body' => 'Changed']
        ];

        $this->assertEquals($expected, $activity->changes);
    });
}

This gets me:

Failed asserting that two strings are equal. Expected :'updated_task' Actual :'created_task'

I think the problem lies with the Activity()

public function activity()
{
    return $this->morphMany(Activity::class, 'subject')->latest();
}
zoltiecodes's avatar

This is fine now because the last activity you did is created a Task. Now the problem is that you never update your task. Let me add a few lines to your code. Hold on.

zoltiecodes's avatar

Now I think this is what you need. I added a lot of comments so you know what's happening. Let me know if you still have issues - of course I could not test this code.

function test_updating_a_task()
{
    $this->withoutExceptionHandling();

    $project = ProjectFactory::withTasks(1)->create();

    // Get the first task that belongs to the project created above - this is the Task model
    $task = $project->tasks->first();

    // Store the Task body so we can compare later ...
    $originalBody = $task->body;

    // Update the Task
    $task->update(['body' => 'Changed']);

    // Refresh the Task just in case ... So this means retrieve fresh data from the database
    $task->refresh();

    // Now we want to check if an 'updated_task' activity has been created

    // Store the last project activity in this variable
    $activity = $project->activity->last();

    // Check the Activity description
    $this->assertEquals('updated_task', $activity->description);

    $expected = [
        'before' => ['body' => $originalBody],
        'after' => ['body' => 'Changed']
    ];

    // Check the activity changes
    $this->assertEquals($expected, $activity->changes);

    // You can also check the body to make sure it has been updated
    $this->assertEquals('Changed', $task->body);
}
ajsmith_codes's avatar

@zsoltgyure I still get this error:

Failed asserting that two strings are equal. Expected :'updated_task' Actual :'created_task'

zoltiecodes's avatar

Ok so now we are sure that something is wrong with the Activity system.

You should check your Task model - it has to use the RecordsActivity trait so something like this:

class Task extends Model
{
    use RecordsActivity;

Also make sure that RecordsActivity trait content is the same as in the Birdboard lesson.

Here is the repo if you need: https://github.com/laracasts/birdboard

zoltiecodes's avatar

Can you share your code? The whole project maybe on Github?

ajsmith_codes's avatar

I'm a newbie with Github too. :)

I will try to share. One minute.

1 like
zoltiecodes's avatar
Level 14

So the issue was in your Task model:

protected static $recordableEvents = ['created', 'deleted'];

You only record create and delete activities...

Change it to:

protected static $recordableEvents = ['created', 'deleted', 'updated'];
ajsmith_codes's avatar

Awesome! In the series, he had us take that out.

Thanks so much for your help!!

1 like
ajsmith_codes's avatar

Hi, again. I was working on this and found that even though we now have green on the test listed above, two other tests are broken: completing_a_task and incompleting_a_task.

Can you take a look? I left you on GitHub and pushed the latest changes.

ajsmith_codes's avatar

Actually, hold for a minute. I am working through the errors and failures and have already corrected one. :)

ajsmith_codes's avatar

@zsoltgyure I now have all tests green, but I'm not sure I'm doing it correctly. I had to change the assertCount code, which makes sense now that both projects and tasks have 2 new input fields. However, I think the count is off.

When I complete or incomplete a task, I get two activity entries: one for updating the task and one for completing (or incompleting) the task.

Any advice on how to troubleshoot this? I'm trying to learn as I go.

EDIT: I think I need to check if the checkbox value has changed. This may involve something in the show.blade.php file?

zoltiecodes's avatar

Let me check. I removed the project from my local.. :)

zoltiecodes's avatar

You should debug the variable in these situations when you expect it to be 3 but it's 5 for some reasons.

I added this above the assertion:

dd($project->activity->pluck('description'));

So these five activites has been created.

Illuminate\Support\Collection^ {#421
  #items: array:5 [
    0 => "created_project"
    1 => "created_task"
    2 => "updated_task"
    3 => "updated_task"
    4 => "completed_task"
  ]
}

It's correct if you check your code... When you update the task in your controller - you update it twice.

    public function update(Project $project, Task $task)
    {

        $this->authorize('update', $task->project);

        $task->update(request()->validate(['body' => 'required'])); // <-- An update here

        //catch the changes to the task body and if it changes with complete or incomplete
        request('completed') ? $task->complete() : $task->incomplete(); // <-- another update here

        return redirect($project->path());
    }

If you check the complete() or incomplete() methods on your Task model you can see you record an activity for completion.

So this is why there are 5 activites.

I don't understand what you said about the extra two input fields. 🤔

This line in you test means you assert the number of activity records belongs to the project to be exactly 3.

$this->assertCount(3, $project->activity);

In this test called TriggerActivityTest you test if the correct activity records are created for the specific actions (like updating tasks). So again - what did you mean by those input fields? :)

zoltiecodes's avatar

But this is different from the issue in this post so if you need help with another issue please open another discussion and tag me there so I get notified and I can help you. :)

Next

Please or to participate in this conversation.