You have built the architecture, optimized the performance, and locked down the security. But are you afraid to deploy on a Friday?
If the answer is "yes", it is because you lack Automated Tests.
For a long time, testing UI components was a nightmare of Selenium drivers and flaky browser tests. Livewire changes everything. It allows you to test user interactions (clicks, inputs, form submissions) directly in PHP, running in milliseconds.
In this guide, we will use Pest PHP—the elegant testing framework—to write robust tests for a Beartropy-powered CreateUser component.
🧪 Phase 1: The Setup
If you haven't installed Pest yet, run:
1composer require pestphp/pest --dev
2php artisan pest:install
Now, let's create a test file for our component:
1php artisan pest:test Livewire/CreateUserTest
🔍 Phase 2: Does it exist?
The first test is a sanity check. Does the page load? Is the component present? Does it show our Beartropy card title?
1use App\Livewire\CreateUser;
2use function Pest\Livewire\livewire;
3
4it('renders the create user page successfully', function () {
5 $this->get('/users/create')
6 ->assertOk()
7 ->assertSeeLivewire(CreateUser::class);
8});
9
10it('displays the form title correctly', function () {
11 livewire(CreateUser::class)
12 ->assertSee('Create New User'); // Checks for the x-bt-card title
13});
🛑 Phase 3: Testing Validation (The Sad Path)
We need to ensure that our UserForm object actually blocks invalid data. This is crucial for data integrity.
1it('requires a name and email', function () {
2 livewire(CreateUser::class)
3 ->set('form.name', '')
4 ->set('form.email', '')
5 ->call('save')
6 ->assertHasErrors(['form.name' => 'required', 'form.email' => 'required']);
7});
8
9it('validates email uniqueness', function () {
10 User::factory()->create(['email' => 'john@beartropy.com']);
11
12 livewire(CreateUser::class)
13 ->set('form.email', 'john@beartropy.com')
14 ->call('save')
15 ->assertHasErrors(['form.email' => 'unique']);
16});
✅ Phase 4: Testing The Logic (The Happy Path)
Now for the most important test: Does it actually create the user in the database when everything is correct?
1it('creates a user and redirects', function () {
2 livewire(CreateUser::class)
3 ->set('form.name', 'Alice Dev')
4 ->set('form.email', 'alice@example.com')
5 ->set('form.role', 'admin')
6 ->set('form.password', 'secret123')
7 ->call('save')
8 ->assertHasNoErrors()
9 ->assertDispatched('user-created'); // Checks for the Livewire event
10
11 // Database Assertion
12 $this->assertDatabaseHas('users', [
13 'email' => 'alice@example.com',
14 'role' => 'admin',
15 ]);
16});
🎨 Phase 5: Testing UI State (Wireable & Computed)
Sometimes logic depends on UI state. Imagine our send_welcome_email toggle only appears for new users.
1it('toggles the welcome email option', function () {
2 livewire(CreateUser::class)
3 ->set('form.send_welcome_email', true)
4 ->call('save');
5
6 // Assert a job was pushed to the queue
7 Queue::assertPushed(SendWelcomeEmail::class);
8});
9
10it('does not send email if toggled off', function () {
11 livewire(CreateUser::class)
12 ->set('form.send_welcome_email', false)
13 ->call('save');
14
15 Queue::assertNotPushed(SendWelcomeEmail::class);
16});
🚀 Summary
Writing tests for Livewire with Pest is incredibly intuitive. You are essentially scripting a user's journey:
- Set data (
->set()).
- Call an action (
->call()).
- Assert the result (
->assertHasNoErrors()).
There is no excuse for shipping buggy code. Add these tests to your CI/CD pipeline today and deploy on Fridays with confidence.