Beartropy Logo

Stop Debugging in Production: Testing Livewire 3 Components Like a Pro

You deployed on Friday. It broke. Users complained. You spent the weekend firefighting. Sound familiar? Manual testing is a trap — it feels fast until it costs you sleep. The solution is automated te...

Guides 06 Feb, 2026 Beartropy Team

Testing Livewire Components

You deployed on Friday. It broke. Users complained. You spent the weekend firefighting.

Sound familiar? Manual testing is a trap — it feels fast until it costs you sleep. The solution is automated tests, and with Pest + Livewire 3, writing them has never been easier.

Why Test Livewire Components?

Livewire components are deceptively complex. They handle:

  • User interactions (clicks, form submissions)
  • Real-time validation
  • State management across requests
  • Authorization and visibility logic

A single untested component can break in dozens of ways. Pest gives you confidence that your component works before production traffic hits it.

Setting Up Pest for Livewire

If you're not already using Pest, install it alongside the Livewire plugin:

1composer require pestphp/pest --dev
2composer require pestphp/pest-plugin-livewire --dev
3./vendor/bin/pest --init

Pest's Livewire plugin gives you a fluent, expressive API that feels natural to write and read.

Your First Livewire Test

Let's say you have a CreatePost component with a form. Here's how to test it:

1use App\Livewire\CreatePost;
2use Livewire\Livewire;
3 
4it('can create a post', function () {
5 Livewire::test(CreatePost::class)
6 ->set('title', 'My First Post')
7 ->set('body', 'This is the body content')
8 ->call('save')
9 ->assertHasNoErrors();
10 
11 expect(Post::count())->toBe(1);
12});

Clean, readable, and catches bugs before users do.

Testing Validation Rules

Validation is where Livewire shines — and where tests matter most. Here's how to verify your rules work:

1it('requires a title', function () {
2 Livewire::test(CreatePost::class)
3 ->set('title', '')
4 ->set('body', 'Valid body')
5 ->call('save')
6 ->assertHasErrors(['title' => 'required']);
7});
8 
9it('validates title length', function () {
10 Livewire::test(CreatePost::class)
11 ->set('title', str_repeat('x', 256))
12 ->call('save')
13 ->assertHasErrors(['title' => 'max']);
14});

Test every validation rule. Users will find edge cases you didn't think of.

Testing Component State

Livewire components maintain state across wire requests. Test that state updates correctly:

1it('updates preview when title changes', function () {
2 Livewire::test(CreatePost::class)
3 ->set('title', 'My New Title')
4 ->assertSet('preview', 'my-new-title');
5});
6 
7it('resets form after save', function () {
8 Livewire::test(CreatePost::class)
9 ->set('title', 'Post Title')
10 ->set('body', 'Post Body')
11 ->call('save')
12 ->assertSet('title', '')
13 ->assertSet('body', '')
14 ->assertDispatched('post-created');
15});

Testing Authorization

Never trust the frontend. Test that your authorization logic actually works:

1it('prevents guests from creating posts', function () {
2 Livewire::test(CreatePost::class)
3 ->call('save')
4 ->assertForbidden();
5});
6 
7it('allows authenticated users to create posts', function () {
8 $user = User::factory()->create();
9 
10 Livewire::actingAs($user)
11 ->test(CreatePost::class)
12 ->set('title', 'My Post')
13 ->set('body', 'My Body')
14 ->call('save')
15 ->assertHasNoErrors();
16});

The actingAs() method makes auth testing seamless.

Testing Events and Navigation

Livewire 3 uses events for component communication. Test them:

1it('dispatches event when post is created', function () {
2 Livewire::actingAs(User::factory()->create())
3 ->test(CreatePost::class)
4 ->set('title', 'Test')
5 ->set('body', 'Body')
6 ->call('save')
7 ->assertDispatched('post-created');
8});
9 
10it('redirects to post after creation', function () {
11 Livewire::actingAs(User::factory()->create())
12 ->test(CreatePost::class)
13 ->set('title', 'Test')
14 ->set('body', 'Body')
15 ->call('save')
16 ->assertRedirect('/posts/1');
17});

Testing Wire:Model Updates

Livewire 3 defers updates by default. Test real-time validation with live models:

1it('shows validation errors in real-time', function () {
2 Livewire::test(CreatePost::class)
3 ->set('title', 'ab') // Too short
4 ->assertHasErrors(['title' => 'min']);
5});

Advanced: Testing File Uploads

Livewire handles file uploads gracefully. Test them with UploadedFile:

1use Illuminate\Http\UploadedFile;
2use Illuminate\Support\Facades\Storage;
3 
4it('can upload a featured image', function () {
5 Storage::fake('public');
6 
7 $file = UploadedFile::fake()->image('photo.jpg');
8 
9 Livewire::actingAs(User::factory()->create())
10 ->test(CreatePost::class)
11 ->set('title', 'Post with Image')
12 ->set('body', 'Body')
13 ->set('image', $file)
14 ->call('save')
15 ->assertHasNoErrors();
16 
17 Storage::disk('public')
18 ->assertExists('posts/' . $file->hashName());
19});

The Test Coverage Sweet Spot

You don't need 100% coverage. Focus on:

  1. Happy paths — The main user flows that must work
  2. Validation — Every rule, every edge case
  3. Authorization — Who can do what
  4. State changes — Data that updates other data
  5. Events — Cross-component communication

Skip testing Livewire internals (it's already tested). Focus on your logic.

Running Your Tests

1./vendor/bin/pest --filter=Livewire

Or run everything:

1./vendor/bin/pest

Add it to your CI pipeline and never deploy broken code again.

Key Takeaways

  • Pest + Livewire makes testing delightful, not painful
  • Test validation, authorization, and state — the things that break
  • Use actingAs() for auth, assertDispatched() for events
  • Deploy on Friday with confidence

Your users (and your weekends) will thank you.


A practical guide from the Beartropy team

Comments

Leave a comment

0

No comments yet. Be the first to share your thoughts!

Share this post