Search code examples
laravelevent-handlingtddlistener

Laravel event/listener test intermittently failing


I have a pretty simple test to check my event increases the count of a video play

$video = Video::factory()->create([
            'uuid' => 'xxx',
            'slug' => 'xxx'
        ]);

        $event = new VideoPlayWasStarted($video->vimeo_id);
        $listener = new IncreaseVideoStartedCount;
        $listener->handle($event);

        $this->assertEquals(++$video->started_plays, $video->fresh()->started_plays);

in VideoPlaysWasStarted class, I pass in the video

public $videoId;
    
    public function __construct($videoId)
    {
        $this->videoId = $videoId;
    }

and then in the listener handle method

public function handle(VideoPlayWasStarted $event)
    {
        $video = Video::where('vimeo_id', $event->videoId)->first();
        $video->increaseStartedPlays();
    }

however, intermittently in running my tests, $video is returning as null resulting in Error : Call to a member function increaseStartedPlays() on null

What am I missing?


Solution

  • My issue here was that I'd forgotten about the scope I had applied to the model to check the published status of the video.

    My video factory was setup to randomly assign the is_published flag to true/false. So of course, some times if the Video was not published, then the event listener was getting that null result on lookup.

    The resolution was to override the factory creation and also improve my test

    /** @test */
        public function when_a_user_starts_a_published_video_it_increments_the_start_count_by_one()
        {
            $video = Video::factory()->create([
                'is_published' => 1,
                'created_at' => Carbon::now(),
            ]);
    
            $event = new VideoPlayWasStarted($video->vimeo_id);
            $listener = new IncreaseVideoStartedCount;
            $listener->handle($event);
    
            $this->assertEquals($video->started_plays + 1, $video->fresh()->started_plays);
        }