4
4
5
5
namespace Codeception \Module \Symfony ;
6
6
7
+ use PHPUnit \Framework \Assert ;
7
8
use Symfony \Component \HttpKernel \DataCollector \EventDataCollector ;
9
+ use Symfony \Component \VarDumper \Cloner \Data ;
10
+
11
+ use function array_column ;
12
+ use function array_merge ;
13
+ use function in_array ;
8
14
use function is_array ;
9
15
use function is_object ;
16
+ use function is_string ;
17
+ use function str_starts_with ;
10
18
11
19
trait EventsAssertionsTrait
12
20
{
13
21
/**
14
- * Verifies that there were no events during the test.
15
- * Both regular and orphan events are checked.
22
+ * Verifies that **no** events (regular **or** orphan) were dispatched during the test.
16
23
*
17
24
* ```php
18
- * <?php
19
- * $I->dontSeeEvent();
20
- * $I->dontSeeEvent('App\MyEvent');
21
- * $I->dontSeeEvent(['App\MyEvent', 'App\MyOtherEvent']);
22
- * ```
25
+ * <?php
26
+ * $I->dontSeeEvent();
27
+ * $I->dontSeeEvent('App\ \MyEvent');
28
+ * $I->dontSeeEvent(['App\\ MyEvent', 'App\ \MyOtherEvent']);
29
+ * ```
23
30
*
24
- * @param string|string[] |null $expected
31
+ * @param class- string|list<class- string> |null $expected Fully-qualified event class(es) that must **not** appear.
25
32
*/
26
33
public function dontSeeEvent (array |string |null $ expected = null ): void
27
34
{
28
- $ actualEvents = [...array_column ($ this ->getCalledListeners (), 'event ' )];
29
- $ actual = [$ this ->getOrphanedEvents (), $ actualEvents ];
30
- $ this ->assertEventTriggered (false , $ expected , $ actual );
35
+ $ this ->handleEventAssertion (false , $ expected , false );
31
36
}
32
37
33
38
/**
34
- * Verifies that one or more event listeners were not called during the test.
39
+ * Verifies that one or more ** listeners** were ** not** called during the test.
35
40
*
36
41
* ```php
37
42
* <?php
38
43
* $I->dontSeeEventListenerIsCalled('App\MyEventListener');
39
44
* $I->dontSeeEventListenerIsCalled(['App\MyEventListener', 'App\MyOtherEventListener']);
40
- * $I->dontSeeEventListenerIsCalled('App\MyEventListener', 'my.event);
45
+ * $I->dontSeeEventListenerIsCalled('App\MyEventListener', 'my.event' );
41
46
* $I->dontSeeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']);
42
47
* ```
43
48
*
44
- * @param class-string|class-string[] $expected
45
- * @param string|string[] $events
49
+ * @param class-string|object|list< class-string|object> $expected Listener(s) (class-string or instance) that must **not** be called.
50
+ * @param string|list< string> $events Event name(s) to scope the assertion to; empty array means “any event”.
46
51
*/
47
52
public function dontSeeEventListenerIsCalled (array |object |string $ expected , array |string $ events = []): void
48
53
{
@@ -59,8 +64,8 @@ public function dontSeeEventListenerIsCalled(array|object|string $expected, arra
59
64
* $I->dontSeeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
60
65
* ```
61
66
*
62
- * @param object|string|string[] $expected
63
- * @deprecated Use ` dontSeeEventListenerIsCalled` instead.
67
+ * @param class-string| object|list<class- string|object> $expected
68
+ * @deprecated Use {@see dontSeeEventListenerIsCalled()} instead.
64
69
*/
65
70
public function dontSeeEventTriggered (array |object |string $ expected ): void
66
71
{
@@ -85,49 +90,42 @@ public function dontSeeEventTriggered(array|object|string $expected): void
85
90
* $I->dontSeeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']);
86
91
* ```
87
92
*
88
- * @param string|string[] $expected
93
+ * @param class- string|list<class- string>|null $expected Event class(es) that must NOT appear as orphan.
89
94
*/
90
95
public function dontSeeOrphanEvent (array |string |null $ expected = null ): void
91
96
{
92
- $ actual = [$ this ->getOrphanedEvents ()];
93
- $ this ->assertEventTriggered (false , $ expected , $ actual );
97
+ $ this ->handleEventAssertion (false , $ expected , true );
94
98
}
95
99
96
100
/**
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.
101
+ * Verifies that at least one of the given events **was** dispatched (regular **or** orphan).
102
102
*
103
103
* ```php
104
- * <?php
105
- * $I->seeEvent('App\MyEvent');
106
- * $I->seeEvent(['App\MyEvent', 'App\MyOtherEvent']);
107
- * ```
104
+ * <?php
105
+ * $I->seeEvent('App\MyEvent');
106
+ * $I->seeEvent(['App\MyEvent', 'App\MyOtherEvent']);
107
+ * ```
108
108
*
109
- * @param string|string[] $expected
109
+ * @param class- string|list<class- string> $expected Fully-qualified class-name(s) of the expected event(s).
110
110
*/
111
111
public function seeEvent (array |string $ expected ): void
112
112
{
113
- $ actualEvents = [...array_column ($ this ->getCalledListeners (), 'event ' )];
114
- $ actual = [$ this ->getOrphanedEvents (), $ actualEvents ];
115
- $ this ->assertEventTriggered (true , $ expected , $ actual );
113
+ $ this ->handleEventAssertion (true , $ expected , false );
116
114
}
117
115
118
116
/**
119
- * Verifies that one or more event listeners were called during the test.
117
+ * Verifies that one or more ** listeners** were called during the test.
120
118
*
121
119
* ```php
122
120
* <?php
123
121
* $I->seeEventListenerIsCalled('App\MyEventListener');
124
122
* $I->seeEventListenerIsCalled(['App\MyEventListener', 'App\MyOtherEventListener']);
125
- * $I->seeEventListenerIsCalled('App\MyEventListener', 'my.event);
123
+ * $I->seeEventListenerIsCalled('App\MyEventListener', 'my.event' );
126
124
* $I->seeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']);
127
125
* ```
128
126
*
129
- * @param class-string|class-string[] $expected
130
- * @param string|string[] $events
127
+ * @param class-string|object|list< class-string|object> $expected Listeners (class-strings or object instances).
128
+ * @param string|list< string> $events Event name(s) (empty = any).
131
129
*/
132
130
public function seeEventListenerIsCalled (array |object |string $ expected , array |string $ events = []): void
133
131
{
@@ -144,8 +142,8 @@ public function seeEventListenerIsCalled(array|object|string $expected, array|st
144
142
* $I->seeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
145
143
* ```
146
144
*
147
- * @param object|string|string[] $expected
148
- * @deprecated Use ` seeEventListenerIsCalled` instead.
145
+ * @param class-string| object|list<class- string|object> $expected
146
+ * @deprecated Use {@see seeEventListenerIsCalled()} instead.
149
147
*/
150
148
public function seeEventTriggered (array |object |string $ expected ): void
151
149
{
@@ -157,7 +155,7 @@ public function seeEventTriggered(array|object|string $expected): void
157
155
}
158
156
159
157
/**
160
- * Verifies that one or more orphan events were dispatched during the test.
158
+ * Verifies that one or more orphan events ** were** dispatched during the test.
161
159
*
162
160
* An orphan event is an event that was triggered by manually executing the
163
161
* [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method
@@ -169,84 +167,126 @@ public function seeEventTriggered(array|object|string $expected): void
169
167
* $I->seeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']);
170
168
* ```
171
169
*
172
- * @param string|string[] $expected
170
+ * @param class- string|list<class- string> $expected Event class-name(s) expected to be orphan.
173
171
*/
174
172
public function seeOrphanEvent (array |string $ expected ): void
175
173
{
176
- $ actual = [$ this ->getOrphanedEvents ()];
177
- $ this ->assertEventTriggered (true , $ expected , $ actual );
174
+ $ this ->handleEventAssertion (true , $ expected , true );
178
175
}
179
176
180
- protected function getCalledListeners (): array
177
+ /** @return list<array{event: string, pretty: string}> */
178
+ protected function getDispatchedEvents (): array
181
179
{
182
- $ eventCollector = $ this ->grabEventCollector (__FUNCTION__ );
180
+ $ eventCollector = $ this ->grabEventCollector (__FUNCTION__ );
183
181
$ calledListeners = $ eventCollector ->getCalledListeners ($ this ->getDefaultDispatcher ());
184
- return [...$ calledListeners ->getValue (true )];
182
+ $ raw = $ calledListeners instanceof Data ? $ calledListeners ->getValue (true ) : $ calledListeners ;
183
+
184
+ /** @var list<array{event:string,pretty:string}> $events */
185
+ $ events = is_array ($ raw ) ? array_values ($ raw ) : [];
186
+ return $ events ;
185
187
}
186
188
189
+ /** @return list<string> */
187
190
protected function getOrphanedEvents (): array
188
191
{
189
192
$ eventCollector = $ this ->grabEventCollector (__FUNCTION__ );
190
- $ orphanedEvents = $ eventCollector ->getOrphanedEvents ($ this ->getDefaultDispatcher ());
191
- return [...$ orphanedEvents ->getValue (true )];
193
+ $ orphaned = $ eventCollector ->getOrphanedEvents ($ this ->getDefaultDispatcher ());
194
+ $ raw = $ orphaned instanceof Data ? $ orphaned ->getValue (true ) : $ orphaned ;
195
+
196
+ /** @var list<string> $events */
197
+ $ events = is_array ($ raw ) ? array_values ($ raw ) : [];
198
+ return $ events ;
192
199
}
193
200
201
+ /** @param class-string|object|list<class-string|object>|null $expected */
202
+ private function handleEventAssertion (bool $ assertTrue , array |object |string |null $ expected , bool $ orphanOnly ): void
203
+ {
204
+ $ actual = $ orphanOnly
205
+ ? [$ this ->getOrphanedEvents ()]
206
+ : [$ this ->getOrphanedEvents (), array_column ($ this ->getDispatchedEvents (), 'event ' )];
207
+
208
+ $ this ->assertEventTriggered ($ assertTrue , $ expected , $ actual );
209
+ }
210
+
211
+ /**
212
+ * @param class-string|object|list<class-string|object>|null $expected
213
+ * @param list<list<string>> $actual
214
+ */
194
215
protected function assertEventTriggered (bool $ assertTrue , array |object |string |null $ expected , array $ actual ): void
195
216
{
196
217
$ actualEvents = array_merge (...$ actual );
197
218
198
- if ($ assertTrue ) $ this ->assertNotEmpty ($ actualEvents , 'No event was triggered ' );
219
+ if ($ assertTrue ) {
220
+ $ this ->assertNotEmpty ($ actualEvents , 'No event was triggered. ' );
221
+ }
199
222
if ($ expected === null ) {
200
223
$ this ->assertEmpty ($ actualEvents );
201
224
return ;
202
225
}
203
226
204
- $ 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 );
227
+ $ expectedEvents = is_object ($ expected ) ? [ $ expected] : ( array ) $ expected ;
228
+ foreach ($ expectedEvents as $ expectedEvent ) {
229
+ $ eventName = is_object ($ expectedEvent ) ? $ expectedEvent ::class : ( string ) $ expectedEvent ;
230
+ $ wasTriggered = in_array ($ eventName , $ actualEvents, true );
208
231
209
- $ message = $ assertTrue
210
- ? "The ' {$ expectedEvent }' event did not trigger "
211
- : "The ' {$ expectedEvent }' event triggered " ;
212
- $ this ->assertSame ($ assertTrue , $ eventTriggered , $ message );
232
+ $ this ->assertSame (
233
+ $ assertTrue ,
234
+ $ wasTriggered ,
235
+ sprintf ("The '%s' event %s triggered " , $ eventName , $ assertTrue ? 'did not ' : 'was ' )
236
+ );
213
237
}
214
238
}
215
239
216
- protected function assertListenerCalled (bool $ assertTrue , array |object |string $ expectedListeners , array |object |string $ expectedEvents ): void
217
- {
240
+ /**
241
+ * @param class-string|object|list<class-string|object> $expectedListeners
242
+ * @param string|list<string> $expectedEvents
243
+ */
244
+ protected function assertListenerCalled (
245
+ bool $ assertTrue ,
246
+ array |object |string $ expectedListeners ,
247
+ array |object |string $ expectedEvents
248
+ ): void {
218
249
$ expectedListeners = is_array ($ expectedListeners ) ? $ expectedListeners : [$ expectedListeners ];
219
- $ expectedEvents = is_array ($ expectedEvents ) ? $ expectedEvents : [$ expectedEvents ];
250
+ $ expectedEvents = is_array ($ expectedEvents ) ? $ expectedEvents : [$ expectedEvents ];
220
251
221
- if (empty ( $ expectedEvents) ) {
252
+ if ($ expectedEvents === [] ) {
222
253
$ expectedEvents = [null ];
223
254
} elseif (count ($ expectedListeners ) > 1 ) {
224
- $ this -> fail ('You cannot check for events when using multiple listeners. Make multiple assertions instead. ' );
255
+ Assert:: fail ('Cannot check for events when using multiple listeners. Make multiple assertions instead. ' );
225
256
}
226
257
227
- $ actualEvents = $ this ->getCalledListeners ();
228
- if ($ assertTrue && empty ($ actualEvents )) {
229
- $ this ->fail ('No event listener was called ' );
258
+ $ actualEvents = $ this ->getDispatchedEvents ();
259
+
260
+ if ($ assertTrue && $ actualEvents === []) {
261
+ Assert::fail ('No event listener was called. ' );
230
262
}
231
263
232
264
foreach ($ expectedListeners as $ expectedListener ) {
233
- $ expectedListener = is_object ($ expectedListener ) ? $ expectedListener::class : $ expectedListener ;
265
+ $ expectedListener = is_string ($ expectedListener ) ? $ expectedListener : $ expectedListener::class ;
234
266
235
267
foreach ($ expectedEvents as $ expectedEvent ) {
236
- $ listenerCalled = $ this ->listenerWasCalled ($ expectedListener , $ expectedEvent , $ actualEvents );
237
- $ message = "The ' {$ expectedListener }' listener was called "
238
- . ($ expectedEvent ? " for the ' {$ expectedEvent }' event " : '' );
239
- $ this ->assertSame ($ assertTrue , $ listenerCalled , $ message );
268
+ $ eventName = is_object ($ expectedEvent ) ? $ expectedEvent ::class : ($ expectedEvent ?: null );
269
+ $ wasCalled = $ this ->listenerWasCalled ($ expectedListener , $ eventName , $ actualEvents );
270
+
271
+ $ this ->assertSame (
272
+ $ assertTrue ,
273
+ $ wasCalled ,
274
+ sprintf (
275
+ "The '%s' listener was %scalled%s " ,
276
+ $ expectedListener ,
277
+ $ assertTrue ? 'not ' : '' ,
278
+ $ eventName ? " for the ' {$ eventName }' event " : ''
279
+ )
280
+ );
240
281
}
241
282
}
242
283
}
243
284
285
+ /** @param list<array{event: string, pretty: string}> $actualEvents */
244
286
private function listenerWasCalled (string $ expectedListener , ?string $ expectedEvent , array $ actualEvents ): bool
245
287
{
246
288
foreach ($ actualEvents as $ actualEvent ) {
247
- if (
248
- isset ($ actualEvent ['pretty ' ], $ actualEvent ['event ' ])
249
- && str_starts_with ($ actualEvent ['pretty ' ], $ expectedListener )
289
+ if (str_starts_with ($ actualEvent ['pretty ' ], $ expectedListener )
250
290
&& ($ expectedEvent === null || $ actualEvent ['event ' ] === $ expectedEvent )
251
291
) {
252
292
return true ;
@@ -262,6 +302,8 @@ protected function getDefaultDispatcher(): string
262
302
263
303
protected function grabEventCollector (string $ function ): EventDataCollector
264
304
{
265
- return $ this ->grabCollector ('events ' , $ function );
305
+ /** @var EventDataCollector $collector */
306
+ $ collector = $ this ->grabCollector ('events ' , $ function );
307
+ return $ collector ;
266
308
}
267
309
}
0 commit comments