Skip to content

Commit a524da2

Browse files
committed
Events PHPStan fix
1 parent e59a94e commit a524da2

File tree

1 file changed

+101
-60
lines changed

1 file changed

+101
-60
lines changed

src/Codeception/Module/Symfony/EventsAssertionsTrait.php

Lines changed: 101 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,39 @@
55
namespace Codeception\Module\Symfony;
66

77
use Symfony\Component\HttpKernel\DataCollector\EventDataCollector;
8+
use Symfony\Component\VarDumper\Cloner\Data;
9+
10+
use function array_column;
11+
use function array_merge;
12+
use function in_array;
813
use function is_array;
914
use function is_object;
15+
use function is_string;
16+
use function str_starts_with;
1017

1118
trait EventsAssertionsTrait
1219
{
1320
/**
14-
* Verifies that there were no events during the test.
15-
* Both regular and orphan events are checked.
21+
* Verifies that **no** events (regular **or** orphan) were dispatched during the test.
1622
*
1723
* ```php
18-
* <?php
19-
* $I->dontSeeEvent();
20-
* $I->dontSeeEvent('App\MyEvent');
21-
* $I->dontSeeEvent(['App\MyEvent', 'App\MyOtherEvent']);
22-
* ```
24+
* <?php
25+
* $I->dontSeeEvent();
26+
* $I->dontSeeEvent('App\\MyEvent');
27+
* $I->dontSeeEvent(['App\\MyEvent', 'App\\MyOtherEvent']);
28+
* ```
2329
*
24-
* @param string|string[]|null $expected
30+
* @param string|list<string>|null $expected Fully-qualified event class(es) that must **not** appear.
2531
*/
2632
public function dontSeeEvent(array|string|null $expected = null): void
2733
{
28-
$actualEvents = [...array_column($this->getCalledListeners(), 'event')];
29-
$actual = [$this->getOrphanedEvents(), $actualEvents];
34+
$actualEvents = $this->getDispatchedEventNames();
35+
$actual = [$this->getOrphanedEvents(), $actualEvents];
3036
$this->assertEventTriggered(false, $expected, $actual);
3137
}
3238

3339
/**
34-
* Verifies that one or more event listeners were not called during the test.
40+
* Verifies that one or more **listeners** were **not** called during the test.
3541
*
3642
* ```php
3743
* <?php
@@ -41,8 +47,8 @@ public function dontSeeEvent(array|string|null $expected = null): void
4147
* $I->dontSeeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']);
4248
* ```
4349
*
44-
* @param class-string|class-string[] $expected
45-
* @param string|string[] $events
50+
* @param string|object|list<string|object> $expected Listener(s) (class-string or instance) that must **not** be called.
51+
* @param string|list<string> $events Event name(s) to scope the assertion to; empty array means “any event”.
4652
*/
4753
public function dontSeeEventListenerIsCalled(array|object|string $expected, array|string $events = []): void
4854
{
@@ -59,8 +65,8 @@ public function dontSeeEventListenerIsCalled(array|object|string $expected, arra
5965
* $I->dontSeeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
6066
* ```
6167
*
62-
* @param object|string|string[] $expected
63-
* @deprecated Use `dontSeeEventListenerIsCalled` instead.
68+
* @param string|object|list<string|object> $expected
69+
* @deprecated Use {@see dontSeeEventListenerIsCalled()} instead.
6470
*/
6571
public function dontSeeEventTriggered(array|object|string $expected): void
6672
{
@@ -85,7 +91,7 @@ public function dontSeeEventTriggered(array|object|string $expected): void
8591
* $I->dontSeeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']);
8692
* ```
8793
*
88-
* @param string|string[] $expected
94+
* @param string|list<string>|null $expected Event class(es) that must NOT appear as orphan.
8995
*/
9096
public function dontSeeOrphanEvent(array|string|null $expected = null): void
9197
{
@@ -94,29 +100,24 @@ public function dontSeeOrphanEvent(array|string|null $expected = null): void
94100
}
95101

96102
/**
97-
* Verifies that one or more events were dispatched during the test.
98-
* Both regular and orphan events are checked.
99-
*
100-
* If you need to verify that expected event is not orphan,
101-
* add `dontSeeOrphanEvent` call.
102-
*
103+
* Verifies that at least one of the given events **was** dispatched (regular **or** orphan).
103104
* ```php
104-
* <?php
105-
* $I->seeEvent('App\MyEvent');
106-
* $I->seeEvent(['App\MyEvent', 'App\MyOtherEvent']);
107-
* ```
105+
* <?php
106+
* $I->seeEvent('App\MyEvent');
107+
* $I->seeEvent(['App\MyEvent', 'App\MyOtherEvent']);
108+
* ```
108109
*
109-
* @param string|string[] $expected
110+
* @param string|list<string> $expected Fully-qualified class-name(s) of the expected event(s).
110111
*/
111112
public function seeEvent(array|string $expected): void
112113
{
113-
$actualEvents = [...array_column($this->getCalledListeners(), 'event')];
114-
$actual = [$this->getOrphanedEvents(), $actualEvents];
114+
$actualEvents = $this->getDispatchedEventNames();
115+
$actual = [$this->getOrphanedEvents(), $actualEvents];
115116
$this->assertEventTriggered(true, $expected, $actual);
116117
}
117118

118119
/**
119-
* Verifies that one or more event listeners were called during the test.
120+
* Verifies that one or more **listeners** were called during the test.
120121
*
121122
* ```php
122123
* <?php
@@ -126,8 +127,8 @@ public function seeEvent(array|string $expected): void
126127
* $I->seeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']);
127128
* ```
128129
*
129-
* @param class-string|class-string[] $expected
130-
* @param string|string[] $events
130+
* @param string|object|list<string|object> $expected Listeners (class-strings or object instances).
131+
* @param string|list<string> $events Event name(s) (empty = any).
131132
*/
132133
public function seeEventListenerIsCalled(array|object|string $expected, array|string $events = []): void
133134
{
@@ -144,8 +145,8 @@ public function seeEventListenerIsCalled(array|object|string $expected, array|st
144145
* $I->seeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
145146
* ```
146147
*
147-
* @param object|string|string[] $expected
148-
* @deprecated Use `seeEventListenerIsCalled` instead.
148+
* @param string|object|list<string|object> $expected
149+
* @deprecated Use {@see seeEventListenerIsCalled()} instead.
149150
*/
150151
public function seeEventTriggered(array|object|string $expected): void
151152
{
@@ -157,7 +158,7 @@ public function seeEventTriggered(array|object|string $expected): void
157158
}
158159

159160
/**
160-
* Verifies that one or more orphan events were dispatched during the test.
161+
* Verifies that one or more orphan events **were** dispatched during the test.
161162
*
162163
* An orphan event is an event that was triggered by manually executing the
163164
* [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method
@@ -169,84 +170,122 @@ public function seeEventTriggered(array|object|string $expected): void
169170
* $I->seeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']);
170171
* ```
171172
*
172-
* @param string|string[] $expected
173+
* @param string|list<string> $expected Event class-name(s) expected to be orphan.
173174
*/
174175
public function seeOrphanEvent(array|string $expected): void
175176
{
176177
$actual = [$this->getOrphanedEvents()];
177178
$this->assertEventTriggered(true, $expected, $actual);
178179
}
179180

180-
protected function getCalledListeners(): array
181+
/** @return list<array{event: string, pretty: string}> */
182+
protected function getDispatchedEvents(): array
181183
{
182-
$eventCollector = $this->grabEventCollector(__FUNCTION__);
184+
$eventCollector = $this->grabEventCollector(__FUNCTION__);
183185
$calledListeners = $eventCollector->getCalledListeners($this->getDefaultDispatcher());
184-
return [...$calledListeners->getValue(true)];
186+
$raw = $calledListeners instanceof Data ? $calledListeners->getValue(true) : $calledListeners;
187+
188+
/** @var list<array{event:string,pretty:string}> $events */
189+
$events = is_array($raw) ? array_values($raw) : [];
190+
return $events;
185191
}
186192

193+
/** @return list<string> */
194+
private function getDispatchedEventNames(): array
195+
{
196+
$names = [];
197+
foreach ($this->getDispatchedEvents() as $listener) {
198+
$names[] = $listener['event'];
199+
}
200+
return $names;
201+
}
202+
203+
/** @return list<string> */
187204
protected function getOrphanedEvents(): array
188205
{
189206
$eventCollector = $this->grabEventCollector(__FUNCTION__);
190-
$orphanedEvents = $eventCollector->getOrphanedEvents($this->getDefaultDispatcher());
191-
return [...$orphanedEvents->getValue(true)];
207+
$orphaned = $eventCollector->getOrphanedEvents($this->getDefaultDispatcher());
208+
$raw = $orphaned instanceof Data ? $orphaned->getValue(true) : $orphaned;
209+
210+
/** @var list<string> $events */
211+
$events = is_array($raw) ? array_values($raw) : [];
212+
return $events;
192213
}
193214

215+
/**
216+
* @param string|object|list<string|object>|null $expected
217+
* @param list<list<string>> $actual
218+
*/
194219
protected function assertEventTriggered(bool $assertTrue, array|object|string|null $expected, array $actual): void
195220
{
196221
$actualEvents = array_merge(...$actual);
197222

198-
if ($assertTrue) $this->assertNotEmpty($actualEvents, 'No event was triggered');
223+
if ($assertTrue) {
224+
$this->assertNotEmpty($actualEvents, 'No event was triggered.');
225+
}
199226
if ($expected === null) {
200227
$this->assertEmpty($actualEvents);
201228
return;
202229
}
203230

204231
$expected = is_object($expected) ? $expected::class : $expected;
205-
foreach ((array)$expected as $expectedEvent) {
206-
$expectedEvent = is_object($expectedEvent) ? $expectedEvent::class : $expectedEvent;
207-
$eventTriggered = in_array($expectedEvent, $actualEvents);
232+
foreach ((array) $expected as $expectedEvent) {
233+
$expectedEvent = is_object($expectedEvent) ? $expectedEvent::class : (string) $expectedEvent;
234+
$eventTriggered = in_array($expectedEvent, $actualEvents, true);
208235

209236
$message = $assertTrue
210-
? "The '{$expectedEvent}' event did not trigger"
211-
: "The '{$expectedEvent}' event triggered";
237+
? sprintf("The '%s' event did not trigger", $expectedEvent)
238+
: sprintf("The '%s' event triggered", $expectedEvent);
239+
212240
$this->assertSame($assertTrue, $eventTriggered, $message);
213241
}
214242
}
215243

244+
/**
245+
* @param string|object|list<string|object> $expectedListeners
246+
* @param string|object|list<string|object>|string[] $expectedEvents
247+
*/
216248
protected function assertListenerCalled(bool $assertTrue, array|object|string $expectedListeners, array|object|string $expectedEvents): void
217249
{
218250
$expectedListeners = is_array($expectedListeners) ? $expectedListeners : [$expectedListeners];
219-
$expectedEvents = is_array($expectedEvents) ? $expectedEvents : [$expectedEvents];
251+
$expectedEvents = is_array($expectedEvents) ? $expectedEvents : [$expectedEvents];
220252

221-
if (empty($expectedEvents)) {
253+
if ($expectedEvents === []) {
222254
$expectedEvents = [null];
223255
} elseif (count($expectedListeners) > 1) {
224256
$this->fail('You cannot check for events when using multiple listeners. Make multiple assertions instead.');
225257
}
226258

227-
$actualEvents = $this->getCalledListeners();
228-
if ($assertTrue && empty($actualEvents)) {
229-
$this->fail('No event listener was called');
259+
$actualEvents = $this->getDispatchedEvents();
260+
261+
if ($assertTrue && $actualEvents === []) {
262+
$this->fail('No event listener was called.');
230263
}
231264

232265
foreach ($expectedListeners as $expectedListener) {
233-
$expectedListener = is_object($expectedListener) ? $expectedListener::class : $expectedListener;
266+
$expectedListener = is_string($expectedListener) ? $expectedListener : $expectedListener::class;
234267

235268
foreach ($expectedEvents as $expectedEvent) {
236-
$listenerCalled = $this->listenerWasCalled($expectedListener, $expectedEvent, $actualEvents);
237-
$message = "The '{$expectedListener}' listener was called"
238-
. ($expectedEvent ? " for the '{$expectedEvent}' event" : '');
269+
$eventName = is_object($expectedEvent) ? $expectedEvent::class : ($expectedEvent ?: null);
270+
$listenerCalled = $this->listenerWasCalled($expectedListener, $eventName, $actualEvents);
271+
272+
$message = sprintf(
273+
"The '%s' listener was %scalled%s",
274+
$expectedListener,
275+
$assertTrue ? 'not ' : '',
276+
$eventName ? " for the '{$eventName}' event" : ''
277+
);
278+
239279
$this->assertSame($assertTrue, $listenerCalled, $message);
240280
}
241281
}
242282
}
243283

284+
/** @param list<array{event: string, pretty: string}> $actualEvents */
244285
private function listenerWasCalled(string $expectedListener, ?string $expectedEvent, array $actualEvents): bool
245286
{
246287
foreach ($actualEvents as $actualEvent) {
247-
if (
248-
isset($actualEvent['pretty'], $actualEvent['event'])
249-
&& str_starts_with($actualEvent['pretty'], $expectedListener)
288+
if (str_starts_with($actualEvent['pretty'], $expectedListener)
250289
&& ($expectedEvent === null || $actualEvent['event'] === $expectedEvent)
251290
) {
252291
return true;
@@ -262,6 +301,8 @@ protected function getDefaultDispatcher(): string
262301

263302
protected function grabEventCollector(string $function): EventDataCollector
264303
{
265-
return $this->grabCollector('events', $function);
304+
/** @var EventDataCollector $collector */
305+
$collector = $this->grabCollector('events', $function);
306+
return $collector;
266307
}
267308
}

0 commit comments

Comments
 (0)