Verified Commit 4b2b8604 authored by Dave Long's avatar Dave Long
Browse files

test: #3397420 Add a way to capture mails sent through the mailer transport service during tests

By: znerol
By: adamps
By: berdir
By: dcam
parent ef2e841b
Loading
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Test;

use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\RawMessage;

/**
 * Provides methods for testing emails sent during test runs.
 *
 * @see \Drupal\mailer_capture\Transport\CaptureTransport
 */
trait MailerCaptureTrait {

  /**
   * Gets an array containing all emails sent during this test case.
   *
   * @return \Symfony\Component\Mime\Email[]
   *   An array containing email messages captured during the current test.
   */
  protected function getEmails(): array {
    $messages = array_map(fn (SentMessage $m) => $m->getOriginalMessage(), $this->getCapturedMessages());
    return array_filter($messages, fn (RawMessage $m) => $m instanceof Email);
  }

  /**
   * Gets an array containing all messages sent during this test case.
   *
   * @return \Symfony\Component\Mailer\SentMessage[]
   *   An array containing messages captured during the current test.
   */
  protected function getCapturedMessages(): array {
    return \Drupal::keyValue('mailer_capture')->get('messages', []);
  }

  /**
   * Clears all messages sent during this test case.
   */
  protected function clearCapturedMessages(): void {
    \Drupal::keyValue('mailer_capture')->delete('messages');
  }

}
+5 −0
Original line number Diff line number Diff line
name: 'Mailer capture'
type: module
description: 'Activates mailer transport capturing all mail in a key value store.'
package: Testing
version: VERSION
+38 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\mailer_capture;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\mailer_capture\Transport\CaptureTransport;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Mailer\Transport\TransportInterface;

/**
 * Enforce mailer transport which captures sent messages in a key value store.
 *
 * Enforces CaptureTransport as the mailer transport service implementation,
 * sidestepping mailer transport factory. As a result, the contents of the
 * system.mail mailer_dsn is irrelevant for transport service construction.
 */
class MailerCaptureServiceProvider implements ServiceModifierInterface {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container): void {
    $definition = new Definition(CaptureTransport::class, [
      new Reference(EventDispatcherInterface::class),
    ]);
    $definition->addMethodCall('setKeyValueFactory', [
      new Reference(KeyValueFactoryInterface::class),
    ]);
    $container->setDefinition(TransportInterface::class, $definition->setPublic(TRUE));
  }

}
+50 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\mailer_capture\Transport;

use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mailer\Transport\TransportInterface;
use Symfony\Contracts\Service\Attribute\Required;

/**
 * Defines a mail transport that captures sent messages in a key value store.
 *
 * This class is for running tests or for development.
 */
class CaptureTransport extends AbstractTransport implements TransportInterface {

  /**
   * Key value factory.
   */
  protected KeyValueFactoryInterface $keyValueFactory;

  /**
   * Set key value factory.
   */
  #[Required]
  public function setKeyValueFactory(KeyValueFactoryInterface $keyValueFactory): void {
    $this->keyValueFactory = $keyValueFactory;
  }

  /**
   * {@inheritdoc}
   */
  protected function doSend(SentMessage $message): void {
    $keyValueStore = $this->keyValueFactory->get('mailer_capture');
    $capturedMails = $keyValueStore->get('messages', []);
    $capturedMails[] = $message;
    $keyValueStore->set('messages', $capturedMails);
  }

  /**
   * {@inheritdoc}
   */
  public function __toString(): string {
    return 'drupal.test-capture';
  }

}
+5 −0
Original line number Diff line number Diff line
name: 'Mailer capture test'
type: module
description: 'Support module for mailer capture testing.'
package: Testing
version: VERSION
Loading