Summer Sale! All accounts are 50% off this week.

Mwaa's avatar
Level 1

Some eloquent model events are not triggered during testing

Reference to Laravel issue https://github.com/laravel/framework/issues/1181

Am writing tests for my application and having problems with some model events not been fired. I have a model called Organization and inside have the following method for events

    static function boot()
    {
        parent::boot();

        static::saving(function ($org)
        {
            if (is_null($org->slug))
            {
                $org->slug = \Str::slug($org->name);
            }
            return $org;

        });

        static::creating(function($org)
        {
            $org->id = md5(uniqid($org->name));
            return $org;
        });

        static::created(function ($org)
        {

            \Session::flash('info','We are setting up your organization. This should take a few minutes');
            return $org;
        });

I have used dd($org) to test which methods run to completion. both created and saving don't work hence in the end the new organization to be created is not saved in database.

Any help offered is appreaciated

0 likes
10 replies
Mwaa's avatar
Level 1

Point of note my issue is not when running different tests but on a single instance of running test

Mwaa's avatar
Level 1

@JarekTkaczyk Read on the issue and implemented a BaseCase with method resetEvents called in the function Setup

    private function resetEvents()
    {
        // Define the models that have event listeners.
        $models = array('\API\V1\Models\Organization','\API\V1\Models\User');

        // Reset their event listeners.
        foreach ($models as $model) {

            // Flush any existing listeners.
            call_user_func(array($model, 'flushEventListeners'));

            // Reregister them.
            call_user_func(array($model, 'boot'));
        }
    }

This does not work still. Have i implemented it wrongly?

erunion's avatar

@Mwaa did you ever figure this out? Running in to the same issue on Laravel 5.1. Eloquent events get fired on the first test, but don't on subsequent. Flushing events in a tearDown does nothing to help the following test work.

Mwaa's avatar
Level 1

@erunion never got a solution to this. Just abandoned the issue entirely. So sad that i finished the project with incomplete tests.

eugenefvdm's avatar

I think you guys are probably dealing with what I'm dealing with right now in that you have to get a fresh model from the database.

See code below, if I don't include the ->fresh() I get 0 for totals, which is incorrect. The total is determined by my model events, so it appears they are not triggered, but in the database the totals are correct. It's just in the tests they appear to be 0.

<?php
   $invoice1 =  factory(\App\Invoice::class, 1)->create()->each(function ($invoice1) {
      for($i = 0; $i < 2; $i++ ) {
      $invoice1->invoice_items()->save(factory(\App\InvoiceItem::class)->make());
   }
})->fresh();

dd($invoice1->first()->total);
JerryBels's avatar

Well, maybe this will help someone at some point. For me it was simply because I used Event::fake() in my test, trying to check if a specific event was dispatched while not actually dispatching it... But I forgot it would also fake eloquent's events. I simply added the name of the event I wanted to check Event::fake([MyEvent::class]); and all works as intended. Felt pretty dumb.

4 likes
Taelkir's avatar

@JerryBels Oh goddamnit. Thanks for this, worked perfectly. Feeling pretty dumb myself now too. 🤣

2 likes
erikms61's avatar

Hi all, I just ran into this exact issue, and found a most unlikely workaround (Laravel 8).

My model Card uses a booted method to write a CardStatusTransition, and the booted function was not getting called.

However:

`public function test_write_transition_by_hand($stockCard)
{
    echo sprintf("%s considering card %s\n", __FUNCTION__, $stockCard->rfid);
    $numTransitions = $stockCard->StatusTransitions()->count();
    echo sprintf("pre-change transitions %d\n", $numTransitions);
    $stockCardCopy = $stockCard->toArray(); //<-- this line somehow makes the test work
    $stockCard->setEmpty();
    echo sprintf("post-change transitions %d\n", $stockCard->StatusTransitions()->count());
    $this->assertSame($numTransitions + 1, $stockCard->StatusTransitions()->count());
}`

if I comment out the marked line, the test fails.

Put it back in and it consistently succeeds.

Just my 2c

-Erik

Please or to participate in this conversation.