Cannot test laravel livewire model hidden attribute with assertSet

1.1k Views Asked by At

I have a simple LIvewire component consisting of a form to create a new User, and it work, i can tell since i've been asked to write tests after the project already reached staging.

The Livewire component use a new User instance (non presisted, i.e. user->exists is false) to store inserted data before persisting it, and the user model hides the password attribute trough the protected $hidden array.

Now, i can sucesfully create new users trough the form page in my local environment, but when it comes to testing, it gives me error.

The test

Livewire::test(
        FormComponent::class,
    )
    ->set('user.name', 'user name')
    ->set('user.email', '[email protected]')
    ->set('user.password', 'password')
    ->assertSet('user.name', 'user name')
    ->assertSet('user.email', '[email protected]')
    ->assertSet('user.password', 'password');

The error

Failed asserting that null matches expected 'password'.

What i find out

Setting my compoment user instance trough the form page goes fine because livewire recognize it as a model, so do something like user->password = 'password', while when setting it from the test with set() it access its property with the access operator as it is an array, i.e.: user['password] = 'password'.
Commenting out the password entry in the $hidden array made the test pass. This will explain the difference in the property setting.

Conclusion

Since the $hidden array is meant to hide model properties in its array/json representation it should not interfere with automated tests, moreover when using Livewire own methods, so to me this looks like a LIvewire Bug.

Help

Does anyone have aver encountered this bug?

Update#1

I've opened an issue on Livewire github page for this.

1

There are 1 best solutions below

0
On

You have diagnosed this pretty well. When Livewire serializes the User model, password is not included because it is in the $hidden array. Even though the User model has not been persisted yet, serialization is the same.

I would guess that your input fields all use the defer modifier, which is why your fields are working in the browser; however, when you call set() in the test, it simulates a Livewire request, so the $hidden attributes are being wiped.

An alternate assertion for testing the password is my recommendation here. Try asserting that the created user can login with the selected password.

$this->assertTrue(
    auth()->attempt(['email' => '[email protected]', 'password' => 'password'])
);