Skip to content

Update event assertions #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 89 additions & 10 deletions src/Codeception/Module/Symfony/EventsAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Symfony\Component\HttpKernel\DataCollector\EventDataCollector;
use Symfony\Component\VarDumper\Cloner\Data;

use function is_array;
use function is_object;

Expand Down Expand Up @@ -53,11 +54,14 @@ public function dontSeeOrphanEvent(array|object|string $expected = null): void
* ```
*
* @param object|string|string[] $expected
* @deprecated Use `dontSeeEventListenerIsCalled()` instead.
* @deprecated Use `dontSeeEventListenerIsCalled` instead.
*/
public function dontSeeEventTriggered(array|object|string $expected): void
{
trigger_error('dontSeeEventTriggered is deprecated, please use dontSeeEventListenerIsCalled instead', E_USER_DEPRECATED);
trigger_error(
'dontSeeEventTriggered is deprecated, please use dontSeeEventListenerIsCalled instead',
E_USER_DEPRECATED
);
$this->dontSeeEventListenerIsCalled($expected);
}

Expand All @@ -69,18 +73,28 @@ public function dontSeeEventTriggered(array|object|string $expected): void
* $I->dontSeeEventListenerIsCalled('App\MyEventListener');
* $I->dontSeeEventListenerIsCalled(new App\Events\MyEventListener());
* $I->dontSeeEventListenerIsCalled(['App\MyEventListener', 'App\MyOtherEventListener']);
* $I->dontSeeEventListenerIsCalled('App\MyEventListener', 'my.event);
* $I->dontSeeEventListenerIsCalled(new App\Events\MyEventListener(), new MyEvent());
* $I->dontSeeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']);
* ```
*
* @param object|string|string[] $expected
*/
public function dontSeeEventListenerIsCalled(array|object|string $expected): void
{
public function dontSeeEventListenerIsCalled(
array|object|string $expected,
array|object|string $withEvents = []
): void {
$eventCollector = $this->grabEventCollector(__FUNCTION__);

$data = $eventCollector->getCalledListeners();
$expected = is_array($expected) ? $expected : [$expected];
$withEvents = is_array($withEvents) ? $withEvents : [$withEvents];

if (!empty($withEvents) && count($expected) > 1) {
$this->fail('You cannot check for events when using multiple listeners. Make multiple assertions instead.');
}

$this->assertEventNotTriggered($data, $expected);
$this->assertListenerCalled($data, $expected, $withEvents, true);
}

/**
Expand Down Expand Up @@ -120,11 +134,14 @@ public function seeOrphanEvent(array|object|string $expected): void
* ```
*
* @param object|string|string[] $expected
* @deprecated Use `seeEventListenerIsCalled()` instead.
* @deprecated Use `seeEventListenerIsCalled` instead.
*/
public function seeEventTriggered(array|object|string $expected): void
{
trigger_error('seeEventTriggered is deprecated, please use seeEventListenerIsCalled instead', E_USER_DEPRECATED);
trigger_error(
'seeEventTriggered is deprecated, please use seeEventListenerIsCalled instead',
E_USER_DEPRECATED
);
$this->seeEventListenerIsCalled($expected);
}

Expand All @@ -136,18 +153,28 @@ public function seeEventTriggered(array|object|string $expected): void
* $I->seeEventListenerIsCalled('App\MyEventListener');
* $I->seeEventListenerIsCalled(new App\Events\MyEventListener());
* $I->seeEventListenerIsCalled(['App\MyEventListener', 'App\MyOtherEventListener']);
* $I->seeEventListenerIsCalled('App\MyEventListener', 'my.event);
* $I->seeEventListenerIsCalled(new App\Events\MyEventListener(), new MyEvent());
* $I->seeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']);
* ```
*
* @param object|string|string[] $expected
*/
public function seeEventListenerIsCalled(array|object|string $expected): void
{
public function seeEventListenerIsCalled(
array|object|string $expected,
array|object|string $withEvents = []
): void {
$eventCollector = $this->grabEventCollector(__FUNCTION__);

$data = $eventCollector->getCalledListeners();
$expected = is_array($expected) ? $expected : [$expected];
$withEvents = is_array($withEvents) ? $withEvents : [$withEvents];

$this->assertEventTriggered($data, $expected);
if (!empty($withEvents) && count($expected) > 1) {
$this->fail('You cannot check for events when using multiple listeners. Make multiple assertions instead.');
}

$this->assertListenerCalled($data, $expected, $withEvents);
}

protected function assertEventNotTriggered(Data $data, array $expected): void
Expand Down Expand Up @@ -180,6 +207,39 @@ protected function assertEventTriggered(Data $data, array $expected): void
}
}

protected function assertListenerCalled(
Data $data,
array $expectedListeners,
array $withEvents,
bool $invertAssertion = false
): void {
$assertTrue = !$invertAssertion;

if ($assertTrue && $data->count() === 0) {
$this->fail('No event listener was called');
}

$actual = $data->getValue(true);
$expectedEvents = empty($withEvents) ? [null] : $withEvents;

foreach ($expectedListeners as $expectedListener) {
$expectedListener = is_object($expectedListener) ? $expectedListener::class : $expectedListener;

foreach ($expectedEvents as $expectedEvent) {
$message = "The '{$expectedListener}' listener was called"
. ($expectedEvent ? " for the '{$expectedEvent}' event" : '');

$condition = $this->listenerWasCalled($actual, $expectedListener, $expectedEvent);

if ($assertTrue) {
$this->assertTrue($condition, $message);
} else {
$this->assertFalse($condition, $message);
}
}
}
}

protected function eventWasTriggered(array $actual, string $expectedEvent): bool
{
$triggered = false;
Expand All @@ -195,9 +255,28 @@ protected function eventWasTriggered(array $actual, string $expectedEvent): bool
}
}
}

return $triggered;
}

protected function listenerWasCalled(array $actual, string $expectedListener, string|null $expectedEvent): bool
{
$called = false;

foreach ($actual as $actualEvent) {
// Called Listeners
if (is_array($actualEvent) && str_starts_with($actualEvent['pretty'], $expectedListener)) {
if ($expectedEvent === null) {
$called = true;
} elseif ($actualEvent['event'] === $expectedEvent) {
$called = true;
}
}
}

return $called;
}

protected function grabEventCollector(string $function): EventDataCollector
{
return $this->grabCollector('events', $function);
Expand Down