Tech Notes: Laravel Livewire – testing object/model properties of components

This is a super quick note to my future self – and you? – about testing object/model properties of Laravel Livewire components.

I’m working on a really simple project and using it as an excuse to practice TDD with Laravel.

I have user-selectable template and my Templates component lets the user select a new template.

My test is pretty simple.

Set up a user and two templates, then assign the first template ID to the user. Note that templates have an owner ($template->owner_id), but the user also has a chosen template ($user->template_id):

// Arrange
$user = User::factory()->create();
$template1 = Template::factory()->create([
    'owner_id' => $user->id,
]);
$template2 = Template::factory()->create([
    'owner_id' => $user->id,
]);
$user->update(['template_id' => $template1->id]);

Then, acting as the user, test the Templates component, call the setUserTemplate method then assert that the currentTemplate property has changed.

// Act
Livewire::actingAs($user)
    ->test(\App\Http\Livewire\Templates::class)
    ->call('setUserTemplate', $template2->id)
    ->assertSet('currentTemplate', $template2);

Before we run the test, I note that the currentTemplate, in the Livewire component, is an Eloquent Model object.

If we run the test we get:

Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
 App\Models\Template Object (
     'connection' => 'sqlite'
-    'table' => null
+    'table' => 'templates'
     'primaryKey' => 'id'
     'keyType' => 'int'
     'incrementing' => true
@@ @@
     'withCount' => Array ()
     'perPage' => 15
     'exists' => true
-    'wasRecentlyCreated' => true
+    'wasRecentlyCreated' => false
     'attributes' => Array (...)
     'original' => Array (...)
     'changes' => Array ()

Showing that the table and wasRecentlyCreated properties of the Template object. The object properties are the same, but it’s a slightly different object behind the scenes.

The problem here is that $template2 is the original template we created using the factory in the test setup. But the currentTemplate in the component will have been fetched from the database.

The fix for this it to re-fetch $template2 from the database before we compare it. We can do this with $template2->fresh()

// Act
Livewire::actingAs($user)
    ->test(\App\Http\Livewire\Templates::class)
    ->call('setUserTemplate', $template2->id)
    ->assertSet('currentTemplate', $template2->fresh());

This gives us a nice green test:

PHPUnit 9.5.2 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.212, Memory: 32.50 MB

OK (1 test, 3 assertions)

Hooray!