Skip to content

Commit

Permalink
feat(Testing): Add ability to assert event listeners with assert class
Browse files Browse the repository at this point in the history
  • Loading branch information
pionl committed Jan 16, 2023
1 parent 390e769 commit 4d0e39e
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/Testing/Concerns/AssertEventListeners.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace LaraStrict\Testing\Concerns;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Events\Dispatcher;
use PHPUnit\Framework\Assert;

trait AssertEventListeners
{
/**
* @param bool $disableWildcard You can receive un-wanted listener responses (like laravel-ray). By default, we will remove any wildcard event.
*/
public function assertEventListeners(
Application $app,
object $event,
string $contract,
object $assert,
array $expectedListenerResults = [null],
bool $disableWildcard = true
): void {
$app->bind(abstract: $contract, concrete: static fn () => $assert);

/** @var Dispatcher $events */
$events = $app->make(Dispatcher::class);

if ($disableWildcard) {
$events->forget('*');
}

$results = $events->dispatch($event);

Assert::assertEquals($expectedListenerResults, $results);
}
}
34 changes: 34 additions & 0 deletions tests/Feature/Testing/Concerns/AssertEventListenersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Testing\Concerns;

use Illuminate\Events\Dispatcher;
use LaraStrict\Testing\Concerns\AssertEventListeners;
use Tests\LaraStrict\Feature\TestCase;

class AssertEventListenersTest extends TestCase
{
use AssertEventListeners;

public function testAssertEventListeners(): void
{
// Set the event as provided would
/** @var Dispatcher $events */
$events = $this->app()
->get(Dispatcher::class);
$this->app()
->bind(TestListenerContract::class, TestListener::class);

$events->listen(TestEvent::class, TestListenerContract::class);

$event = new TestEvent();
$this->assertEventListeners(
app: $this->app(),
event: $event,
contract: TestListenerContract::class,
assert: new TestListenerContractAssert([new TestListenerContractExpectation(event: $event)])
);
}
}
9 changes: 9 additions & 0 deletions tests/Feature/Testing/Concerns/TestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Testing\Concerns;

class TestEvent
{
}
15 changes: 15 additions & 0 deletions tests/Feature/Testing/Concerns/TestListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Testing\Concerns;

use PHPUnit\Framework\Assert;

class TestListener implements TestListenerContract
{
public function handle(TestEvent $event): void
{
Assert::fail('Listener should not be called');
}
}
10 changes: 10 additions & 0 deletions tests/Feature/Testing/Concerns/TestListenerContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Testing\Concerns;

interface TestListenerContract
{
public function handle(TestEvent $event): void;
}
26 changes: 26 additions & 0 deletions tests/Feature/Testing/Concerns/TestListenerContractAssert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Testing\Concerns;

use LaraStrict\Testing\AbstractExpectationCallMap;
use PHPUnit\Framework\Assert;

/**
* @extends AbstractExpectationCallMap<TestListenerContractExpectation>
*/
class TestListenerContractAssert extends AbstractExpectationCallMap implements TestListenerContract
{
public function handle(TestEvent $event): void
{
$expectation = $this->getExpectation();
$message = $this->getDebugMessage();

Assert::assertEquals($expectation->event, $event, $message);

if (is_callable($expectation->hook)) {
call_user_func($expectation->hook, $event, $expectation);
}
}
}
19 changes: 19 additions & 0 deletions tests/Feature/Testing/Concerns/TestListenerContractExpectation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Testing\Concerns;

use Closure;

final class TestListenerContractExpectation
{
/**
* @param Closure(TestEvent,self):void|null $hook
*/
public function __construct(
public readonly TestEvent $event,
public readonly ?Closure $hook = null,
) {
}
}

0 comments on commit 4d0e39e

Please sign in to comment.