Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ jobs:
php vendor/bin/codecept run Functional -c framework-tests
if [ "${{ matrix.symfony }}" = "7.4" ]; then
composer remove symfony/messenger --dev --no-interaction
composer require codeception/module-rest --dev
git -C framework-tests checkout -- composer.json
git -C framework-tests apply resetFormatsAfterRequest_issue_test.patch
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"symfony/http-foundation": "^5.4 | ^6.4 | ^7.4 | ^8.0",
"symfony/http-kernel": "^5.4 | ^6.4 | ^7.4 | ^8.0",
"symfony/mailer": "^5.4 | ^6.4 | ^7.4 | ^8.0",
"symfony/messenger": "^5.4 | ^6.4 | ^7.4 | ^8.0",
"symfony/mime": "^5.4 | ^6.4 | ^7.4 | ^8.0",
"symfony/notifier": "^5.4 | ^6.4 | ^7.4 | ^8.0",
"symfony/options-resolver": "^5.4 | ^6.4 | ^7.4 | ^8.0",
Expand Down
2 changes: 2 additions & 0 deletions src/Codeception/Module/Symfony.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Codeception\Module\Symfony\HttpKernelAssertionsTrait;
use Codeception\Module\Symfony\LoggerAssertionsTrait;
use Codeception\Module\Symfony\MailerAssertionsTrait;
use Codeception\Module\Symfony\MessengerAssertionsTrait;
use Codeception\Module\Symfony\MimeAssertionsTrait;
use Codeception\Module\Symfony\NotifierAssertionsTrait;
use Codeception\Module\Symfony\ParameterAssertionsTrait;
Expand Down Expand Up @@ -148,6 +149,7 @@ class Symfony extends Framework implements DoctrineProvider, PartedModule
use HttpKernelAssertionsTrait;
use LoggerAssertionsTrait;
use MailerAssertionsTrait;
use MessengerAssertionsTrait;
use MimeAssertionsTrait;
use NotifierAssertionsTrait;
use ParameterAssertionsTrait;
Expand Down
1 change: 1 addition & 0 deletions src/Codeception/Module/Symfony/DataCollectorName.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ enum DataCollectorName: string
case TWIG = 'twig';
case SECURITY = 'security';
case MAILER = 'mailer';
case MESSENGER = 'messenger';
case NOTIFIER = 'notifier';
}
4 changes: 3 additions & 1 deletion src/Codeception/Module/Symfony/HttpKernelAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\Mailer\DataCollector\MessageDataCollector;
use Symfony\Component\Messenger\DataCollector\MessengerDataCollector;
use Symfony\Component\Notifier\DataCollector\NotificationDataCollector;
use Symfony\Component\Translation\DataCollector\TranslationDataCollector;

Expand All @@ -40,9 +41,10 @@ abstract protected function getProfile(): ?Profile;
* ($name is DataCollectorName::TWIG ? TwigDataCollector :
* ($name is DataCollectorName::SECURITY ? SecurityDataCollector :
* ($name is DataCollectorName::MAILER ? MessageDataCollector :
* ($name is DataCollectorName::MESSENGER ? MessengerDataCollector :
* ($name is DataCollectorName::NOTIFIER ? NotificationDataCollector :
* DataCollectorInterface
* )))))))))
* ))))))))))
* )
*/
protected function grabCollector(DataCollectorName $name, string $callingFunction = '', ?string $message = null): DataCollectorInterface
Expand Down
134 changes: 134 additions & 0 deletions src/Codeception/Module/Symfony/MessengerAssertionsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\Symfony;

use Symfony\Component\Messenger\DataCollector\MessengerDataCollector;
use Symfony\Component\VarDumper\Cloner\Data;

use function class_exists;
use function count;
use function is_string;
use function sprintf;

trait MessengerAssertionsTrait
{
/**
* Asserts no message of the given class was dispatched (optionally on a single bus).
*
* ```php
* <?php
* $I->dontSeeMessageDispatched(SendWelcomeEmail::class);
* $I->dontSeeMessageDispatched(SendWelcomeEmail::class, 'messenger.bus.default');
* ```
*
* @param class-string $messageClass
*/
public function dontSeeMessageDispatched(string $messageClass, ?string $bus = null): void
{
$this->assertNotContains(
$messageClass,
$this->getDispatchedMessageClasses(__FUNCTION__, $bus),
sprintf("The '%s' message was dispatched%s.", $messageClass, $this->busSuffix($bus)),
);
}

/**
* Returns the dispatched message class names, in dispatch order (optionally for a single bus).
*
* The profiler stores cloned snapshots, so this yields class names, not the message objects.
*
* ```php
* <?php
* $classes = $I->grabDispatchedMessageClasses();
* $classes = $I->grabDispatchedMessageClasses('messenger.bus.default');
* ```
*
* @return list<class-string>
*/
public function grabDispatchedMessageClasses(?string $bus = null): array
{
return $this->getDispatchedMessageClasses(__FUNCTION__, $bus);
}

/**
* Asserts how many messages were dispatched (optionally on a single bus).
*
* ```php
* <?php
* $I->seeDispatchedMessageCount(1);
* $I->seeDispatchedMessageCount(2, 'messenger.bus.default');
* ```
*/
public function seeDispatchedMessageCount(int $expectedCount, ?string $bus = null): void
{
$messages = $this->grabMessengerCollector(__FUNCTION__)->getMessages($bus);

$this->assertCount(
$expectedCount,
$messages,
sprintf(
'Expected %d message(s) to be dispatched%s, but %d were.',
$expectedCount,
$this->busSuffix($bus),
count($messages),
),
);
}

/**
* Asserts at least one message of the given class was dispatched (optionally on a single bus).
*
* ```php
* <?php
* $I->seeMessageDispatched(SendWelcomeEmail::class);
* $I->seeMessageDispatched(SendWelcomeEmail::class, 'messenger.bus.default');
* ```
*
* @param class-string $messageClass
*/
public function seeMessageDispatched(string $messageClass, ?string $bus = null): void
{
$this->assertContains(
$messageClass,
$this->getDispatchedMessageClasses(__FUNCTION__, $bus),
sprintf("The '%s' message was not dispatched%s.", $messageClass, $this->busSuffix($bus)),
);
}

/**
* @return list<class-string>
*/
private function getDispatchedMessageClasses(string $callingFunction, ?string $bus): array
{
$classes = [];
foreach ($this->grabMessengerCollector($callingFunction)->getMessages($bus) as $entry) {
if (!$entry instanceof Data) {
continue;
}

$message = $entry['message'];
$type = $message instanceof Data ? ($message['type'] ?? null) : null;
if ($type instanceof Data) {
$type = $type->getValue();
}

if (is_string($type) && class_exists($type)) {
$classes[] = $type;
}
}

return $classes;
}

private function busSuffix(?string $bus): string
{
return $bus !== null ? sprintf(" on bus '%s'", $bus) : '';
}

protected function grabMessengerCollector(string $callingFunction): MessengerDataCollector
{
return $this->grabCollector(DataCollectorName::MESSENGER, $callingFunction);
}
}
59 changes: 59 additions & 0 deletions tests/MessengerAssertionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Tests;

use Codeception\Module\Symfony\MessengerAssertionsTrait;
use stdClass;
use Tests\App\Message\TestMessage;
use Tests\Support\CodeceptTestCase;

final class MessengerAssertionsTest extends CodeceptTestCase
{
use MessengerAssertionsTrait;

public function testSeeDispatchedMessageCount(): void
{
$this->client->request('GET', '/dispatch-message');

$this->seeDispatchedMessageCount(1);
$this->seeDispatchedMessageCount(1, 'messenger.bus.default');
$this->seeDispatchedMessageCount(0, 'non.existent.bus');
}

public function testSeeMessageDispatched(): void
{
$this->client->request('GET', '/dispatch-message');

$this->seeMessageDispatched(TestMessage::class);
$this->seeMessageDispatched(TestMessage::class, 'messenger.bus.default');
}

public function testDontSeeMessageDispatched(): void
{
$this->client->request('GET', '/dispatch-message');

$this->dontSeeMessageDispatched(stdClass::class);
$this->dontSeeMessageDispatched(TestMessage::class, 'non.existent.bus');
}

public function testGrabDispatchedMessageClasses(): void
{
$this->client->request('GET', '/dispatch-message');

$messages = $this->grabDispatchedMessageClasses();

$this->assertSame([TestMessage::class], $messages);
$this->assertSame([TestMessage::class], $this->grabDispatchedMessageClasses('messenger.bus.default'));
$this->assertSame([], $this->grabDispatchedMessageClasses('non.existent.bus'));
}

public function testNoMessagesDispatched(): void
{
$this->client->request('GET', '/');

$this->seeDispatchedMessageCount(0);
$this->assertSame([], $this->grabDispatchedMessageClasses());
}
}
9 changes: 9 additions & 0 deletions tests/_app/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Validator\Constraints\Email as EmailConstraint;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Tests\App\Event\TestEvent;
use Tests\App\Mailer\MessageMailer;
use Tests\App\Mailer\RegistrationMailer;
use Tests\App\Message\TestMessage;
use Twig\Environment;

final class AppController extends AbstractController
Expand Down Expand Up @@ -66,6 +68,13 @@ public function dispatchOrphanEvent(EventDispatcherInterface $dispatcher): Respo
return new Response('Orphan event dispatched');
}

public function dispatchTestMessage(MessageBusInterface $bus): Response
{
$bus->dispatch(new TestMessage('Hello from Messenger'));

return new Response('Message dispatched');
}

public function form(Request $request, FormFactoryInterface $formFactory, Environment $twig): Response
{
$builder = $formFactory->createNamedBuilder('registration_form', options: ['csrf_protection' => false]);
Expand Down
18 changes: 18 additions & 0 deletions tests/_app/Message/TestMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Tests\App\Message;

final class TestMessage
{
public function __construct(
private readonly string $content = '',
) {
}

public function getContent(): string
{
return $this->content;
}
}
20 changes: 20 additions & 0 deletions tests/_app/MessageHandler/TestMessageHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Tests\App\MessageHandler;

use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Tests\App\Message\TestMessage;

#[AsMessageHandler]
final class TestMessageHandler
{
/** @var list<string> */
public array $handled = [];

public function __invoke(TestMessage $message): void
{
$this->handled[] = $message->getContent();
}
}
3 changes: 2 additions & 1 deletion tests/_app/TestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ private function configureExtensions(ContainerConfigurator $container): void
'profiler' => $profilerConfig,
'property_info' => ['enabled' => true],
'session' => ['handler_id' => null, 'storage_factory_id' => 'session.storage.factory.mock_file'],
'mailer' => ['dsn' => 'null://null'],
'mailer' => ['dsn' => 'null://null', 'message_bus' => false],
'default_locale' => 'en',
'translator' => ['default_path' => __DIR__ . '/translations', 'fallbacks' => ['es'], 'logging' => true],
'validation' => ['enabled' => true],
'form' => ['enabled' => true],
'notifier' => ['chatter_transports' => ['async' => 'null://null'], 'texter_transports' => ['sms' => 'null://null']],
'messenger' => ['default_bus' => 'messenger.bus.default', 'buses' => ['messenger.bus.default' => []]],
]);

$container->extension('twig', ['default_path' => __DIR__ . '/templates', 'debug' => true]);
Expand Down
1 change: 1 addition & 0 deletions tests/_app/config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
$routes->add('dashboard', '/dashboard')->controller(AppController::class . '::dashboard');
$routes->add('deprecated', '/deprecated')->controller(AppController::class . '::deprecated');
$routes->add('dispatch_event', '/dispatch-event')->controller(AppController::class . '::dispatchEvent');
$routes->add('dispatch_message', '/dispatch-message')->controller(AppController::class . '::dispatchTestMessage');
$routes->add('dispatch_named_event', '/dispatch-named-event')->controller(AppController::class . '::dispatchNamedEvent');
$routes->add('dispatch_orphan_event', '/dispatch-orphan-event')->controller(AppController::class . '::dispatchOrphanEvent');
$routes->add('form_handler', '/form')->controller(AppController::class . '::form');
Expand Down
3 changes: 3 additions & 0 deletions tests/_app/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Tests\App\Logger\ArrayLogger;
use Tests\App\Mailer\MessageMailer;
use Tests\App\Mailer\RegistrationMailer;
use Tests\App\MessageHandler\TestMessageHandler;
use Tests\App\Notifier\NotifierFixture;
use Tests\App\Repository\UserRepository;
use Tests\App\Repository\UserRepositoryInterface;
Expand Down Expand Up @@ -67,6 +68,8 @@
$services->set('notifier.notification_logger_listener', NotificationLoggerListener::class)->tag('kernel.event_subscriber');
$services->alias('notifier.logger_notification_listener', 'notifier.notification_logger_listener')->public();

$services->set(TestMessageHandler::class);

$services->set(RegistrationMailer::class)->arg('$mailer', service('mailer'));
$services->set(MessageMailer::class)->arg('$mailer', service('mailer'));
$services->set(NotifierFixture::class)->arg('$dispatcher', service('event_dispatcher'));
Expand Down