Test emails sent by the Symfony Mailer with Behat or Cypress.
This testing library provides the same PHPUnit assertions for Email Messages from Symfony, but for Behat or Cypress:
assertEmailCount
assertQueuedEmailCount
assertEmailIsQueued
assertEmailIsNotQueued
assertEmailAttachmentCount
assertEmailTextBodyContains
assertEmailTextBodyNotContains
assertEmailHtmlBodyContains
assertEmailHtmlBodyNotContains
assertEmailHasHeader
assertEmailNotHasHeader
assertEmailHeaderSame
assertEmailHeaderNotSame
assertEmailAddressContains
$ composer require --dev kocal/symfony-mailer-testing
This testing library try to be the more framework-agnostic possible. You don't have to use the Symfony Framework to use this library, as long as a bridge is available, it should works for you.
However, it requires manual installation depending on your needs.
Import the bundle:
<?php
// bundles.php
return [
// ...
Kocal\SymfonyMailerTesting\Bridge\Symfony\SymfonyMailerTestingBundle::class => ['test' => true],
];
If you use Behat with Symfony, you have to make sure FriendsOfBehat/SymfonyExtension is installed and configured.
Your Behat configuration file should look like this:
# behat.yml.dist
default:
extensions:
FriendsOfBehat\SymfonyExtension: ~
suites:
default:
contexts:
# Import the context
- Kocal\SymfonyMailerTesting\Bridge\Behat\MailerContext
If you want to add more assertions but can't extend from MailerContext
, you can use the trait MailerContextTrait
.
First, you need to install a PSR-7 implementation, e.g. nyholm/psr7 :
$ composer require nyholm/psr7
Then you need to install the Sensio FrameworkExtraBundle and Symfony PSR-7 Bridge:
$ composer require sensio/framework-extra-bundle
$ composer require --dev symfony/psr-http-message-bridge
Those dependencies will make sure that the PSR-7 compatible MailerController.php
will be compatible with Symfony.
Then you have to import the routes:
# config/routes/test/symfony_mailer_testing.yaml
symfony_mailer_testing:
resource: '@SymfonyMailerTestingBundle/Resources/config/routing.yaml'
And finally, you should add this module in your support file:
// cypress/support/index.js
import '/path/to/vendor/kocal/symfony-mailer-testing/src/Bridge/Cypress/support';
Available steps:
@Then I select email #:index
@Then I select email #:index from transport :transport
@Then :count email(s) should have been sent
@Then :count email(s) should have been sent in transport :transport
@Then :count email(s) should have been queued
@Then :count email(s) should have been queued in transport :transport
@Then this email is queued
@Then this email is not queued
@Then this email has :count attachment(s)
@Then this email text body contains :text
@Then this email text body not contains :text
@Then this email HTML body contains :text
@Then this email HTML body not contains :text
@Then this email has header :headerName
@Then this email has no header :headerName
@Then this email header :headerName has value :value
@Then this email header :headerName has not value :value
@Then this email contains address :headerName :address
@Then this email subject has value :text
@Then this email subject contains :text
@Then this email subject matches :regex
this email [...]
requires you to call I select email #...
before.
Example:
Feature: Testing my feature
Scenario: An email should be sent
When <use one of your step that send an email>
Then 1 email should have been sent
And I select email #0
And this email text body contains "Hello world!"
And this email contains address "From" "from@example.com"
And this email contains address "To" "to@example.com"
Since you have imported the support file, you can use the following commands:
cy.resetMessageEvents()
: reset the Symfony Mailer loggercy.getMessageEvents()
: fetch emails sent by the Symfony Mailer
But if you prefer, you can import the methods directly:
import { resetMessageEvents, getMessageEvents } from '/path/to/vendor/kocal/symfony-mailer-testing/src/Bridge/Cypress';
// cypress/integration/your.spec.js
describe('Your feature', function () {
beforeEach(function () {
// this is important to reset message events before each specsn your tests should be isolated.
// see https://docs.cypress.io/guides/references/best-practices.html
cy.resetMessageEvents();
});
specify('An email should be sent [...]', function () {
// do some actions that send an email ...
// then use `cy.getMessageEvents()`
cy.getMessageEvents().then((messageEvents) => {
expect(messageEvents).to.have.sentEmails.lengthOf(1);
expect(messageEvents).to.have.queuedEmails.lengthOf(0);
expect(messageEvents.events[0]).to.have.subject.contains('Hello world!');
expect(messageEvents.events[0]).to.have.body('html').contains('<a href="...">My link</a>');
expect(messageEvents.events[0]).to.have.attachments.lengthOf(1);
// ...
});
});
});
Assert how many emails has been sent or queued. Can be scoped by transport (if using multiple Symfony Mailer).
expect(messageEvents).to.have.sentEmails.lengthOf(1);
expect(messageEvents).to.have.queuedEmails.lengthOf(0);
// Scope to given transport
expect(messageEvents).transport('null://').to.have.sentEmails.lengthOf(1);
expect(messageEvents).transport('null://').to.have.queuedEmails.lengthOf(0);
Assert if email has been sent or queued.
expect(messageEvents.events[0]).to.be.sent;
expect(messageEvents.events[0]).to.not.be.queued;
Assert email's attachments.
expect(messageEvents.events[0]).to.have.attachments.lengthOf(2);
// Get attachment by name
expect(messageEvents.events[0]).to.have.attachments('attachment.txt').lengthOf(1);
expect(messageEvents.events[0]).to.have.attachments('foobar.txt').lengthOf(0);
Assert email's subject.
expect(messageEvents.events[0]).to.have.subject.equal('Hello world!');
expect(messageEvents.events[0]).to.have.subject.not.equals('Foo');
expect(messageEvents.events[0]).to.have.subject.contains('Hello world!');
expect(messageEvents.events[0]).to.have.subject.not.contains('Foo');
Assert email's text or HTML body.
expect(messageEvents.events[0]).to.have.body('text').equal('Hello world!');
expect(messageEvents.events[0]).to.have.body('text').contains('Hello');
expect(messageEvents.events[0]).to.have.body('text').not.equal('Foo');
expect(messageEvents.events[0]).to.have.body('text').not.contains('Foo');
expect(messageEvents.events[0]).to.have.body('html').equal('<h1>Hello world!</h1>');
expect(messageEvents.events[0]).to.have.body('html').contains('Hello world!');
expect(messageEvents.events[0]).to.have.body('html').not.equal('Foo');
expect(messageEvents.events[0]).to.have.body('html').not.contains('Foo');
Assert email's headers.
expect(messageEvents.events[0]).to.have.header('From');
expect(messageEvents.events[0]).to.have.header('From').eq('symfony-mailer-testing@example.com');
expect(messageEvents.events[0]).to.not.have.header('Foobar');
Assert email's address.
expect(messageEvents.events[0]).to.have.address('From');
expect(messageEvents.events[0]).to.have.address('From').eq('symfony-mailer-testing@example.com');
expect(messageEvents.events[0]).to.not.have.address('Foobar');