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