I am writing a Behat Scenario that checks that an email generated by the Drupal system under test is sent to the correct recipient but I [could not] capture the mail messages from test_mail_collector
. How do I do this?
[Update]
The code below is essentially my current working version and should work for you ... at least as long as you don't have an anti-spam module interceding ... in which case see the extra code in my answer.
In FeatureContext.php
I switch over to the mail system sender test_mail_collector
in the @BeforeScenario
tagged with @email
and revert to the site's original mail system sender in the @AfterScenario
tagged with @email
.
However, [before I discovered my answer, there were] never any messages in the array returned by \Drupal::state()->get('system.test_mail_collector')
when a scenario should generate them,
Here's a typical scenario:
...
@email
Scenario: Send an email when a user resets her password
Given users:
| name | mail | status |
| Jo User | [email protected] | 1 |
When I visit "user/password"
And I fill in "name" with "[email protected]"
When I press the "Submit" button
Then an email should be sent to "[email protected]"
And here are the FeatureContext.php
snippets:
...
/**
* @Then an email should be sent to :recipient
*/
public function anEmailShouldBeSentTo($recipient)
{
// Reset state cache.
\Drupal::state()->resetCache();
$mails = \Drupal::state()->get('system.test_mail_collector') ?: array();
$last_mail = end($mails);
if(!$last_mail) {
throw new Exception('No mail was sent.');
}
if ($last_mail['to'] != $recipient) {
throw new \Exception("Unexpected recpient: " . $last_mail['to']);
}
$this->lastMail = $last_mail;
}
/**
* @BeforeScenario @email
*/
public function beforeEmailScenario(BeforeScenarioScope $scope)
{
$this->m_config = \Drupal::configFactory()->getEditable('mailsystem.settings');
$this->saved_mailsystem_defaults = $this->m_config->get('defaults');
$this->m_config->set('defaults.sender', 'test_mail_collector')->save();
\Drupal::state()->set('system.test_mail_collector', array());
}
/**
* @AfterScenario @email
*/
public function afterEmailScenario(AfterScenarioScope $scope)
{
// revert mail system after scenarios agged with @email
$this->m_config->set('defaults.sender', $this->saved_mailsystem_defaults['sender'])->save();
}
The website is normally set up to run with swiftmailer
enabled but I have tried all the other available mail system formatters and senders - like Default PHP Mailer
- without success.
As a kind of "proof of setup" within FeatureContext.php
, I can send test messages to the test_mail_collector
:
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
\Drupal::service('plugin.manager.mail')
->mail('test', 'test', '[email protected]', $language_interface->getId());
This shows me that the test_mail_collector
is working - but messages generated from the website [were] not being collected.