Skip to content

Commit

Permalink
[TesterBundle] EventDispatcherTesterTrait
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoiriert committed Aug 11, 2024
1 parent 9565a3e commit 60c7004
Show file tree
Hide file tree
Showing 6 changed files with 420 additions and 15 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"doctrine/persistence": "^2.2 || ^3.0",
"dragonmantank/cron-expression": "^3.3",
"ext-ctype": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-mongodb": "*",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace Draw\Bundle\TesterBundle\EventDispatcher;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;

trait EventDispatcherTesterTrait
{
protected static array $eventDispatcherFileCleaners = [
[EventDispatcherTesterTrait::class, 'cleanEventDispatcherFileContainerReference'],
];

protected static function cleanEventDispatcherFile(string $filePath): void
{
foreach (static::$eventDispatcherFileCleaners as $cleaner) {
\call_user_func($cleaner, $filePath);
}
}

/**
* Clean reference in file that looks like this.
*
* <callable type="function" name="onKernelControllerArguments" class="ContainerPKL8sSi\RequestPayloadValueResolverGhostB42fd45" priority="0"/>
*
* By Removing the unique string pattern in the class attribute using DomDocument.
*
* The result after cleaning will be:
*
* <callable type="function" name="onKernelControllerArguments" class="Container\RequestPayloadValueResolverGhost" priority="0"/>
*
* Clean when the class name contains Container and Ghost in its name.
*/
public static function cleanEventDispatcherFileContainerReference(string $filePath): void
{
$dom = new \DOMDocument();
$dom->load($filePath);

$xpath = new \DOMXPath($dom);

$nodes = $xpath->query('//callable[@class]');

foreach ($nodes as $node) {
\assert($node instanceof \DOMElement);
$class = $node->getAttribute('class');
if (preg_match('/Container.*Ghost/', $class)) {
// Use regex to match only the alphanumeric patterns that follow "Container" and "Ghost"
$class = preg_replace('/(?<=Container)[A-Za-z0-9]+|(?<=Ghost)[A-Za-z0-9]+/', '__cleaned__', $class);
$node->setAttribute('class', $class);
}
}

$dom->save($filePath);
}

public static function assertEventDispatcherConfiguration(string $expectedFilePath, string $dispatcherName = 'event_dispatcher'): void
{
$commandTester = new CommandTester(
static::getContainer()->get('console.command.event_dispatcher_debug')
);

$commandTester->execute([
'--dispatcher' => $dispatcherName,
'--format' => 'xml',
]);

$display = $commandTester->getDisplay();

$resultFilePath = tempnam(sys_get_temp_dir(), 'event_dispatcher_configuration');

file_put_contents($resultFilePath, $display);

static::cleanEventDispatcherFile($resultFilePath);

register_shutdown_function('unlink', $resultFilePath);

if (!file_exists($expectedFilePath)) {
copy($resultFilePath, $expectedFilePath);

TestCase::fail($dispatcherName.' configuration file created at '.$expectedFilePath.'. Please review it and commit it.');
}

TestCase::assertXmlFileEqualsXmlFile(
$expectedFilePath,
$resultFilePath,
);
}
}
47 changes: 32 additions & 15 deletions packages/tester-bundle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,46 @@ Draw Tester Bundle

This bundle integrate the Draw Tester Component.

To use the HttpTesterTrait in a KernelTestCase you must simply do this:
It also provides test helpers to make it easier to test your Symfony application.

```PHP
<?php namespace App\Tests;
## Kernel Testing

use Draw\Bundle\TesterBundle\Http\BrowserFactoryInterface;
use Draw\Bundle\TesterBundle\Http\HttpTesterTrait;
When configuring your kernel you may want to test that everything is hooked up correctly.

There is the list of service, event dispatcher, command etc.

There is some TestCase/Trait to help you do that (work in progress).

### Event Dispatcher

Relying on the `debug:event-dispatcher` command we can dump the list of event listeners and validated it against the expected list.

```php
<?php

namespace App\Tests;

use Draw\Bundle\TesterBundle\EventDispatcher\EventDispatcherTesterTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\BrowserKit\AbstractBrowser;

class TestCase extends KernelTestCase implements BrowserFactoryInterface
class AppKernelTest extends KernelTestCase
{
use HttpTesterTrait;
public function createBrowser(): AbstractBrowser
use EventDispatcherTesterTrait;

public function testEventDispatcherConfiguration(): void
{
return static::bootKernel()->getContainer()->get('test.client');
$this->assertEventDispatcherConfiguration(
__DIR__.'/fixtures/AppKernelTest/testEventDispatcherConfiguration/event_dispatcher.xml',
'event_dispatcher' // This is the default value, same as the debug:event-dispatcher command
);
}
}
```

As you can see we are using the **HttpTesterTrait** of the **Bundle** instead of the **Component**.
This is because it as the implementation of the implementation of the **createHttpTesterClient** method.
The first time you run this test it will fail and dump the current configuration in the `event_dispatcher.xml` file.

Commit this file, next time your rune this test you will be able to validate that the configuration is still valid.

If you change the listener in your code or change your dependencies you can run the test again and see the diff.

Also you can see that we are booting a new kernel every time. It's to make sure we are using a new container
on each request like the behaviour of a normal client request will do.
This will allow you to see if some external listeners changed at the same time.
1 change: 1 addition & 0 deletions packages/tester-bundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"integration test"
],
"require": {
"ext-dom": "*",
"draw/core": "^0.11",
"draw/tester": "^0.11",
"symfony/browser-kit": "^6.4.0",
Expand Down
18 changes: 18 additions & 0 deletions tests/AppKernelTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Tests;

use Draw\Bundle\TesterBundle\EventDispatcher\EventDispatcherTesterTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class AppKernelTest extends KernelTestCase
{
use EventDispatcherTesterTrait;

public function testEventDispatcherConfiguration(): void
{
$this->assertEventDispatcherConfiguration(
__DIR__.'/fixtures/AppKernelTest/testEventDispatcherConfiguration/event_dispatcher.xml'
);
}
}
Loading

0 comments on commit 60c7004

Please sign in to comment.