dispatcher = $dispatcher; $this->eventsToFake = Arr::wrap($eventsToFake); } /** * Specify the events that should be dispatched instead of faked. * * @param array|string $eventsToDispatch * @return $this */ public function except($eventsToDispatch) { $this->eventsToDispatch = array_merge( $this->eventsToDispatch, Arr::wrap($eventsToDispatch) ); return $this; } /** * Assert if an event has a listener attached to it. * * @param string $expectedEvent * @param string|array $expectedListener * @return void */ public function assertListening($expectedEvent, $expectedListener) { foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) { $actualListener = (new ReflectionFunction($listenerClosure)) ->getStaticVariables()['listener']; if (is_string($actualListener) && Str::contains($actualListener, '@')) { $actualListener = Str::parseCallback($actualListener); if (is_string($expectedListener)) { if (Str::contains($expectedListener, '@')) { $expectedListener = Str::parseCallback($expectedListener); } else { $expectedListener = [$expectedListener, 'handle']; } } } if ($actualListener === $expectedListener || ($actualListener instanceof Closure && $expectedListener === Closure::class)) { PHPUnit::assertTrue(true); return; } } PHPUnit::assertTrue( false, sprintf( 'Event [%s] does not have the [%s] listener attached to it', $expectedEvent, print_r($expectedListener, true) ) ); } /** * Assert if an event was dispatched based on a truth-test callback. * * @param string|\Closure $event * @param callable|int|null $callback * @return void */ public function assertDispatched($event, $callback = null) { if ($event instanceof Closure) { [$event, $callback] = [$this->firstClosureParameterType($event), $event]; } if (is_int($callback)) { return $this->assertDispatchedTimes($event, $callback); } PHPUnit::assertTrue( $this->dispatched($event, $callback)->count() > 0, "The expected [{$event}] event was not dispatched." ); } /** * Assert if an event was dispatched a number of times. * * @param string $event * @param int $times * @return void */ public function assertDispatchedTimes($event, $times = 1) { $count = $this->dispatched($event)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$event}] event was dispatched {$count} times instead of {$times} times." ); } /** * Determine if an event was dispatched based on a truth-test callback. * * @param string|\Closure $event * @param callable|null $callback * @return void */ public function assertNotDispatched($event, $callback = null) { if ($event instanceof Closure) { [$event, $callback] = [$this->firstClosureParameterType($event), $event]; } PHPUnit::assertCount( 0, $this->dispatched($event, $callback), "The unexpected [{$event}] event was dispatched." ); } /** * Assert that no events were dispatched. * * @return void */ public function assertNothingDispatched() { $count = count(Arr::flatten($this->events)); PHPUnit::assertSame( 0, $count, "{$count} unexpected events were dispatched." ); } /** * Get all of the events matching a truth-test callback. * * @param string $event * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function dispatched($event, $callback = null) { if (! $this->hasDispatched($event)) { return collect(); } $callback = $callback ?: fn () => true; return collect($this->events[$event])->filter( fn ($arguments) => $callback(...$arguments) ); } /** * Determine if the given event has been dispatched. * * @param string $event * @return bool */ public function hasDispatched($event) { return isset($this->events[$event]) && ! empty($this->events[$event]); } /** * Register an event listener with the dispatcher. * * @param \Closure|string|array $events * @param mixed $listener * @return void */ public function listen($events, $listener = null) { $this->dispatcher->listen($events, $listener); } /** * Determine if a given event has listeners. * * @param string $eventName * @return bool */ public function hasListeners($eventName) { return $this->dispatcher->hasListeners($eventName); } /** * Register an event and payload to be dispatched later. * * @param string $event * @param array $payload * @return void */ public function push($event, $payload = []) { // } /** * Register an event subscriber with the dispatcher. * * @param object|string $subscriber * @return void */ public function subscribe($subscriber) { $this->dispatcher->subscribe($subscriber); } /** * Flush a set of pushed events. * * @param string $event * @return void */ public function flush($event) { // } /** * Fire an event and call the listeners. * * @param string|object $event * @param mixed $payload * @param bool $halt * @return array|null */ public function dispatch($event, $payload = [], $halt = false) { $name = is_object($event) ? get_class($event) : (string) $event; if ($this->shouldFakeEvent($name, $payload)) { $this->events[$name][] = func_get_args(); } else { return $this->dispatcher->dispatch($event, $payload, $halt); } } /** * Determine if an event should be faked or actually dispatched. * * @param string $eventName * @param mixed $payload * @return bool */ protected function shouldFakeEvent($eventName, $payload) { if ($this->shouldDispatchEvent($eventName, $payload)) { return false; } if (empty($this->eventsToFake)) { return true; } return collect($this->eventsToFake) ->filter(function ($event) use ($eventName, $payload) { return $event instanceof Closure ? $event($eventName, $payload) : $event === $eventName; }) ->isNotEmpty(); } /** * Determine whether an event should be dispatched or not. * * @param string $eventName * @param mixed $payload * @return bool */ protected function shouldDispatchEvent($eventName, $payload) { if (empty($this->eventsToDispatch)) { return false; } return collect($this->eventsToDispatch) ->filter(function ($event) use ($eventName, $payload) { return $event instanceof Closure ? $event($eventName, $payload) : $event === $eventName; }) ->isNotEmpty(); } /** * Remove a set of listeners from the dispatcher. * * @param string $event * @return void */ public function forget($event) { // } /** * Forget all of the queued listeners. * * @return void */ public function forgetPushed() { // } /** * Dispatch an event and call the listeners. * * @param string|object $event * @param mixed $payload * @return array|null */ public function until($event, $payload = []) { return $this->dispatch($event, $payload, true); } }