vincent15000's avatar

How to test if an event is triggered ?

Hello,

I have an observer in which I send the InfrastructureUpdated event (event dispatched to all users via a websocket --- I listen to this event in the VueJS frontend ---).

public function updated(Infrastructure $infrastructure): void
{
    $users = User::all();

    foreach ($users as $user) {
        InfrastructureUpdated::dispatch($infrastructure, $user);
    }
}

I have written this test but it fails.

/** @test */
public function infrastructure_updated_event_is_triggered(): void
{
    Event::fake();
    
	User::factory()->count(5)->create();

    $infrastructure = Infrastructure::factory()->create();
	$infrastructure->update(['name' => 'another name']);

    Event::assertDispatched(InfrastructureUpdated::class);
}

I specify that the observer is registered directly inside the model.

#[ObservedBy([InfrastructureObserver::class])]
class Infrastructure extends Model

Have you any idea why it fails ?

Thanks for your help.

V

0 likes
6 replies
tisuchi's avatar

@vincent15000 Can you log something inside the updated observer to confirm that it's been triggered?

For example:

public function updated(Infrastructure $infrastructure): void
{
    \Log::info('Observer triggered');
    $users = User::all();

    foreach ($users as $user) {
        \Log::info('Dispatching event for user: ' . $user->id);
        InfrastructureUpdated::dispatch($infrastructure, $user);
    }
}
3 likes
vincent15000's avatar

@tisuchi The event is dispatched.

I have read the documentation once again and I have tried to mention the event inside the fake() method.

/** @test */
public function infrastructure_updated_event_is_triggered(): void
{
    Event::fake([
        InfrastructureUpdated::class,
    ]);
    
    User::factory()->count(5)->create();

    Infrastructure::factory()->create();

    Event::assertDispatched(InfrastructureUpdated::class);
}

And now it works.

Do you have any idea why it works now and why it didn't work before ?

2 likes
tisuchi's avatar
tisuchi
Best Answer
Level 70

@vincent15000 It seems somehow your event depends on some other event/job in your application.

In the monument you mentioned that you want to fake this particular class InfrastructureUpdated::class,, which means your test is only faking this class, other events will be handled normally (without faking).

That's my understanding of this behaviour.

BTW, here are the differences:

  • Event::fake(): This fakes all events, meaning none of them will be processed normally during the test. It's useful to prevent any real event handling or jobs from running.

  • Event::fake([...]): This fakes only the specified events. Other events will still be handled normally. By faking only the InfrastructureUpdated event, you make it easier to test that specific event without affecting others.

3 likes
vincent15000's avatar

@tisuchi You're right, my event is an event dispatched from inside another event handled by a observer.

2 likes
vincent15000's avatar

@tisuchi In fact I'm listening to the base CRUD events via an observer and I dispatch events to the frontend via a websocket for real time updates in the frontend.

3 likes

Please or to participate in this conversation.