Create a gist now

Instantly share code, notes, and snippets.

@JeffreyWay /MailTracking.php Secret
Last active Mar 8, 2017

What would you like to do?
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use MailTracking;
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$this->visit('/route-that-sends-an-email')
->seeEmailWasSent()
->seeEmailSubject('Hello World')
->seeEmailTo('foo@bar.com')
->seeEmailEquals('Click here to buy this jewelry.')
->seeEmailContains('Click here');
}
}
<?php
trait MailTracking
{
/**
* Delivered emails.
*/
protected $emails = [];
/**
* Register a listener for new emails.
*
* @before
*/
public function setUpMailTracking()
{
Mail::getSwiftMailer()
->registerPlugin(new TestingMailEventListener($this));
}
/**
* Assert that at least one email was sent.
*/
protected function seeEmailWasSent()
{
$this->assertNotEmpty(
$this->emails, 'No emails have been sent.'
);
return $this;
}
/**
* Assert that no emails were sent.
*/
protected function seeEmailWasNotSent()
{
$this->assertEmpty(
$this->emails, 'Did not expect any emails to have been sent.'
);
return $this;
}
/**
* Assert that the given number of emails were sent.
*
* @param integer $count
*/
protected function seeEmailsSent($count)
{
$emailsSent = count($this->emails);
$this->assertCount(
$count, $this->emails,
"Expected $count emails to have been sent, but $emailsSent were."
);
return $this;
}
/**
* Assert that the last email's body equals the given text.
*
* @param string $body
* @param Swift_Message $message
*/
protected function seeEmailEquals($body, Swift_Message $message = null)
{
$this->assertEquals(
$body, $this->getEmail($message)->getBody(),
"No email with the provided body was sent."
);
return $this;
}
/**
* Assert that the last email's body contains the given text.
*
* @param string $excerpt
* @param Swift_Message $message
*/
protected function seeEmailContains($excerpt, Swift_Message $message = null)
{
$this->assertContains(
$excerpt, $this->getEmail($message)->getBody(),
"No email containing the provided body was found."
);
return $this;
}
/**
* Assert that the last email's subject matches the given string.
*
* @param string $subject
* @param Swift_Message $message
*/
protected function seeEmailSubject($subject, Swift_Message $message = null)
{
$this->assertEquals(
$subject, $this->getEmail($message)->getSubject(),
"No email with a subject of $subject was found."
);
return $this;
}
/**
* Assert that the last email was sent to the given recipient.
*
* @param string $recipient
* @param Swift_Message $message
*/
protected function seeEmailTo($recipient, Swift_Message $message = null)
{
$this->assertArrayHasKey(
$recipient, (array) $this->getEmail($message)->getTo(),
"No email was sent to $recipient."
);
return $this;
}
/**
* Assert that the last email was delivered by the given address.
*
* @param string $sender
* @param Swift_Message $message
*/
protected function seeEmailFrom($sender, Swift_Message $message = null)
{
$this->assertArrayHasKey(
$sender, (array) $this->getEmail($message)->getFrom(),
"No email was sent from $sender."
);
return $this;
}
/**
* Store a new swift message.
*
* @param Swift_Message $email
*/
public function addEmail(Swift_Message $email)
{
$this->emails[] = $email;
}
/**
* Retrieve the appropriate swift message.
*
* @param Swift_Message $message
*/
protected function getEmail(Swift_Message $message = null)
{
$this->seeEmailWasSent();
return $message ?: $this->lastEmail();
}
/**
* Retrieve the mostly recently sent swift message.
*/
protected function lastEmail()
{
return end($this->emails);
}
}
class TestingMailEventListener implements Swift_Events_EventListener
{
protected $test;
public function __construct($test)
{
$this->test = $test;
}
public function beforeSendPerformed($event)
{
$this->test->addEmail($event->getMessage());
}
}
@danijeel
    /**
     * Retrieve the appropriate swift message.
     *
     * @param Swift_Message $email
     */
    protected function getEmail(Swift_Message $email = null)
    {
        $this->seeEmailWasSent();
        // should be $email instead of $message
        return $email ?: $this->lastEmail();
    }
@JeffreyWay
Owner

Updated. Thanks!

@sebdesign

tests/phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit ...>
    ...
    <php>
        ...
        <env name="MAIL_DRIVER" value="log"/>
    </php>
</phpunit>
@mattkoch614

@sebdesign Awwww yeah, I was just wondering how to do that.

@suth
suth commented Feb 12, 2016

The getBody() method used on Swift_Message didn't seem to be working (always returned null) when using Mail::raw() and plain text, so the seeEmailEquals and seeEmailContains assertions were always failing. Tried making an HTML view and using Mail::send() and everything worked beautifully.

@sebdesign

I added a method that asserts the message was BCC'd to the given recipients array.

/**
 * Assert that the last email was sent to the given recipients.
 *
 * @param array        $recipients
 * @param Swift_Message $message
 */
protected function seeEmailBcc(array $recipients, Swift_Message $message = null)
{
    $bcc = array_keys((array) $this->getEmail($message)->getBcc());

    sort($recipients);
    sort($bcc);

    $this->assertArraySubset(
        $recipients, $bcc,
        '',
        'No email was BCC\'d to: '.implode(', ', $recipients)
    );

    return $this;
}
@Tjoosten

But how does the Mail:: are defined. I'm stuck on that part.

@helmut
helmut commented Jul 21, 2016

Jeffrey can you see this being added to the core? It's pretty dang useful...

@Oldenborg

This breaks down after I switched to 5.3, does any one have a patched version that works with 5.3 Mailables

@duartealexf

@olde86 It worked for me, using the 5.3 Mailables. Only thing I did was separate the event listener to its own file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment