Efficiently testing components with Laravel Livewire's testing utilities
I've been writing some tests to check my new subscription form functions as expected. I show how easy it is to write tests to make assertions against a Livewire component.
As touched on recently, testing is important! I just wanted to quickly document my experience writing Pest tests for Livewire components. Testing can be tricky with abstractions but fortunately, Livewire is a well considered framework and has all the testing utilities needed.
I've modularised my subscription elements which you'll notice in the code snippet below, but that's not important, what is, is how we test against the Livewire component.
<?php
use Livewire\Livewire;
use Modules\Subscribe\Actions\CreateSubscriber;
use Modules\Subscribe\Livewire\Subscribe;
use Tests\TestCase;
uses(TestCase::class);
it('can render the component', function () {
/// When we render the component, check we are loading the right view
/// and that we see an expected element from the form itself
Livewire::test(Subscribe::class)
->assertSee('I agree to receive occasional')
->assertViewIs('subscribe::subscribe');
});
it('can validate the form', function () {
/// When we submit the form with invalid values, we should see
/// the appropriate errors
Livewire::test(Subscribe::class)
->set('name', '')
->set('email', '')
->set('agree', false)
->call('save')
->assertHasErrors(['name', 'email', 'agree']);
});
it('can submit the form', function () {
$this->mock(CreateSubscriber::class, function ($mock) {
$mock->shouldReceive('__invoke')->once();
});
/// When we submit the form with valid values, we should see
/// a success message and no errors
Livewire::test(Subscribe::class)
->set('name', 'John Doe')
->set('email', 'john@example.com')
->set('agree', true)
->call('save')
->assertSee('Thanks for signing up!')
->assertHasNoErrors();
});
You'll notice on the highlighted lines, that I'm mocking my CreateSubscriber
class, I've pulled this out using the Action pattern. This allows me to write tests for that element separately, without having to test the full functionality in this test. So, I'm just making sure that it's called, and any testing for that particular action will be performed in another file.
So the common pattern is wrapping your component in Livewire::test()
and then chaining ->set()
to set the components values and ->call()
to call the methods against it. In the case of my subscribe form, the save
function would normally be called when the form is submitted.
We can then check for the presence of errors, or lack of, and run partial checks on the output to make sure our messaging has changed. So as you can see it's so easy to write tests for Livewire components. Thank you Livewire!
If you haven't yet seen my subscription form in action, check it out here!