MailFake.php
TLDR
The MailFake
class is part of the Illuminate\Support\Testing\Fakes
namespace and is used as a fake implementation for mailing in the Laravel framework's testing environment. It implements the Factory
, Fake
, Mailer
, and MailQueue
interfaces. The class provides methods for asserting if a mailable was sent or queued, counting the number of sent or queued mailables, retrieving sent or queued mailables based on a truth-test callback, and more.
Methods
assertSent
Asserts if a mailable was sent based on a truth-test callback.
assertSentTimes
Asserts if a mailable was sent a specific number of times.
assertNotOutgoing
Determines if a mailable was not sent or queued to be sent based on a truth-test callback.
assertNotSent
Determines if a mailable was not sent based on a truth-test callback.
assertNothingOutgoing
Asserts that no mailables were sent or queued to be sent.
assertNothingSent
Asserts that no mailables were sent.
assertQueued
Asserts if a mailable was queued based on a truth-test callback.
assertQueuedTimes
Asserts if a mailable was queued a specific number of times.
assertNotQueued
Determines if a mailable was not queued based on a truth-test callback.
assertNothingQueued
Asserts that no mailables were queued.
assertSentCount
Asserts the total number of mailables that were sent.
assertQueuedCount
Asserts the total number of mailables that were queued.
assertOutgoingCount
Asserts the total number of mailables that were sent or queued.
sent
Returns all of the mailables matching a truth-test callback that were sent.
hasSent
Determines if a given mailable has been sent.
queued
Returns all of the queued mailables matching a truth-test callback.
hasQueued
Determines if a given mailable has been queued.
mailer
Gets a mailer instance by name.
to
Begins the process of mailing a mailable class instance to specific users.
cc
Begins the process of mailing a mailable class instance to users as carbon copy recipients.
bcc
Begins the process of mailing a mailable class instance to users as blind carbon copy recipients.
raw
Sends a new message with only a raw text part.
send
Sends a new message using a view.
queue
Queues a new e-mail message for sending.
later
Queues a new e-mail message for sending after a specific delay.
prepareMailableAndCallback
Infers the mailable class using reflection if a type-hinted closure is passed to the assertion.
forgetMailers
Forgets all of the resolved mailer instances.
__call
Handles dynamic method calls to the mailer.
<?php
namespace Illuminate\Support\Testing\Fakes;
use Closure;
use Illuminate\Contracts\Mail\Factory;
use Illuminate\Contracts\Mail\Mailable;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Mail\MailQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\MailManager;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Support\Traits\ReflectsClosures;
use PHPUnit\Framework\Assert as PHPUnit;
class MailFake implements Factory, Fake, Mailer, MailQueue
{
use ForwardsCalls, ReflectsClosures;
/**
* The mailer instance.
*
* @var MailManager
*/
public $manager;
/**
* The mailer currently being used to send a message.
*
* @var string
*/
protected $currentMailer;
/**
* All of the mailables that have been sent.
*
* @var array
*/
protected $mailables = [];
/**
* All of the mailables that have been queued.
*
* @var array
*/
protected $queuedMailables = [];
/**
* Create a new mail fake.
*
* @param MailManager $manager
* @return void
*/
public function __construct(MailManager $manager)
{
$this->manager = $manager;
}
/**
* Assert if a mailable was sent based on a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|int|null $callback
* @return void
*/
public function assertSent($mailable, $callback = null)
{
[$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);
if (is_numeric($callback)) {
return $this->assertSentTimes($mailable, $callback);
}
$message = "The expected [{$mailable}] mailable was not sent.";
if (count($this->queuedMailables) > 0) {
$message .= ' Did you mean to use assertQueued() instead?';
}
PHPUnit::assertTrue(
$this->sent($mailable, $callback)->count() > 0,
$message
);
}
/**
* Assert if a mailable was sent a number of times.
*
* @param string $mailable
* @param int $times
* @return void
*/
protected function assertSentTimes($mailable, $times = 1)
{
$count = $this->sent($mailable)->count();
PHPUnit::assertSame(
$times, $count,
"The expected [{$mailable}] mailable was sent {$count} times instead of {$times} times."
);
}
/**
* Determine if a mailable was not sent or queued to be sent based on a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|null $callback
* @return void
*/
public function assertNotOutgoing($mailable, $callback = null)
{
$this->assertNotSent($mailable, $callback);
$this->assertNotQueued($mailable, $callback);
}
/**
* Determine if a mailable was not sent based on a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|null $callback
* @return void
*/
public function assertNotSent($mailable, $callback = null)
{
[$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);
PHPUnit::assertCount(
0, $this->sent($mailable, $callback),
"The unexpected [{$mailable}] mailable was sent."
);
}
/**
* Assert that no mailables were sent or queued to be sent.
*
* @return void
*/
public function assertNothingOutgoing()
{
$this->assertNothingSent();
$this->assertNothingQueued();
}
/**
* Assert that no mailables were sent.
*
* @return void
*/
public function assertNothingSent()
{
$mailableNames = collect($this->mailables)->map(
fn ($mailable) => get_class($mailable)
)->join(', ');
PHPUnit::assertEmpty($this->mailables, 'The following mailables were sent unexpectedly: '.$mailableNames);
}
/**
* Assert if a mailable was queued based on a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|int|null $callback
* @return void
*/
public function assertQueued($mailable, $callback = null)
{
[$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);
if (is_numeric($callback)) {
return $this->assertQueuedTimes($mailable, $callback);
}
PHPUnit::assertTrue(
$this->queued($mailable, $callback)->count() > 0,
"The expected [{$mailable}] mailable was not queued."
);
}
/**
* Assert if a mailable was queued a number of times.
*
* @param string $mailable
* @param int $times
* @return void
*/
protected function assertQueuedTimes($mailable, $times = 1)
{
$count = $this->queued($mailable)->count();
PHPUnit::assertSame(
$times, $count,
"The expected [{$mailable}] mailable was queued {$count} times instead of {$times} times."
);
}
/**
* Determine if a mailable was not queued based on a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|null $callback
* @return void
*/
public function assertNotQueued($mailable, $callback = null)
{
[$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);
PHPUnit::assertCount(
0, $this->queued($mailable, $callback),
"The unexpected [{$mailable}] mailable was queued."
);
}
/**
* Assert that no mailables were queued.
*
* @return void
*/
public function assertNothingQueued()
{
$mailableNames = collect($this->queuedMailables)->map(
fn ($mailable) => get_class($mailable)
)->join(', ');
PHPUnit::assertEmpty($this->queuedMailables, 'The following mailables were queued unexpectedly: '.$mailableNames);
}
/**
* Assert the total number of mailables that were sent.
*
* @param int $count
* @return void
*/
public function assertSentCount($count)
{
$total = collect($this->mailables)->count();
PHPUnit::assertSame(
$count, $total,
"The total number of mailables sent was {$total} instead of {$count}."
);
}
/**
* Assert the total number of mailables that were queued.
*
* @param int $count
* @return void
*/
public function assertQueuedCount($count)
{
$total = collect($this->queuedMailables)->count();
PHPUnit::assertSame(
$count, $total,
"The total number of mailables queued was {$total} instead of {$count}."
);
}
/**
* Assert the total number of mailables that were sent or queued.
*
* @param int $count
* @return void
*/
public function assertOutgoingCount($count)
{
$total = collect($this->mailables)
->concat($this->queuedMailables)
->count();
PHPUnit::assertSame(
$count, $total,
"The total number of outgoing mailables was {$total} instead of {$count}."
);
}
/**
* Get all of the mailables matching a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|null $callback
* @return \Illuminate\Support\Collection
*/
public function sent($mailable, $callback = null)
{
[$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);
if (! $this->hasSent($mailable)) {
return collect();
}
$callback = $callback ?: fn () => true;
return $this->mailablesOf($mailable)->filter(fn ($mailable) => $callback($mailable));
}
/**
* Determine if the given mailable has been sent.
*
* @param string $mailable
* @return bool
*/
public function hasSent($mailable)
{
return $this->mailablesOf($mailable)->count() > 0;
}
/**
* Get all of the queued mailables matching a truth-test callback.
*
* @param string|\Closure $mailable
* @param callable|null $callback
* @return \Illuminate\Support\Collection
*/
public function queued($mailable, $callback = null)
{
[$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);
if (! $this->hasQueued($mailable)) {
return collect();
}
$callback = $callback ?: fn () => true;
return $this->queuedMailablesOf($mailable)->filter(fn ($mailable) => $callback($mailable));
}
/**
* Determine if the given mailable has been queued.
*
* @param string $mailable
* @return bool
*/
public function hasQueued($mailable)
{
return $this->queuedMailablesOf($mailable)->count() > 0;
}
/**
* Get all of the mailed mailables for a given type.
*
* @param string $type
* @return \Illuminate\Support\Collection
*/
protected function mailablesOf($type)
{
return collect($this->mailables)->filter(fn ($mailable) => $mailable instanceof $type);
}
/**
* Get all of the mailed mailables for a given type.
*
* @param string $type
* @return \Illuminate\Support\Collection
*/
protected function queuedMailablesOf($type)
{
return collect($this->queuedMailables)->filter(fn ($mailable) => $mailable instanceof $type);
}
/**
* Get a mailer instance by name.
*
* @param string|null $name
* @return \Illuminate\Contracts\Mail\Mailer
*/
public function mailer($name = null)
{
$this->currentMailer = $name;
return $this;
}
/**
* Begin the process of mailing a mailable class instance.
*
* @param mixed $users
* @return \Illuminate\Mail\PendingMail
*/
public function to($users)
{
return (new PendingMailFake($this))->to($users);
}
/**
* Begin the process of mailing a mailable class instance.
*
* @param mixed $users
* @return \Illuminate\Mail\PendingMail
*/
public function cc($users)
{
return (new PendingMailFake($this))->cc($users);
}
/**
* Begin the process of mailing a mailable class instance.
*
* @param mixed $users
* @return \Illuminate\Mail\PendingMail
*/
public function bcc($users)
{
return (new PendingMailFake($this))->bcc($users);
}
/**
* Send a new message with only a raw text part.
*
* @param string $text
* @param \Closure|string $callback
* @return void
*/
public function raw($text, $callback)
{
//
}
/**
* Send a new message using a view.
*
* @param \Illuminate\Contracts\Mail\Mailable|string|array $view
* @param array $data
* @param \Closure|string|null $callback
* @return void
*/
public function send($view, array $data = [], $callback = null)
{
if (! $view instanceof Mailable) {
return;
}
$view->mailer($this->currentMailer);
if ($view instanceof ShouldQueue) {
return $this->queue($view, $data);
}
$this->currentMailer = null;
$this->mailables[] = $view;
}
/**
* Queue a new e-mail message for sending.
*
* @param \Illuminate\Contracts\Mail\Mailable|string|array $view
* @param string|null $queue
* @return mixed
*/
public function queue($view, $queue = null)
{
if (! $view instanceof Mailable) {
return;
}
$view->mailer($this->currentMailer);
$this->currentMailer = null;
$this->queuedMailables[] = $view;
}
/**
* Queue a new e-mail message for sending after (n) seconds.
*
* @param \DateTimeInterface|\DateInterval|int $delay
* @param \Illuminate\Contracts\Mail\Mailable|string|array $view
* @param string|null $queue
* @return mixed
*/
public function later($delay, $view, $queue = null)
{
$this->queue($view, $queue);
}
/**
* Infer mailable class using reflection if a typehinted closure is passed to assertion.
*
* @param string|\Closure $mailable
* @param callable|null $callback
* @return array
*/
protected function prepareMailableAndCallback($mailable, $callback)
{
if ($mailable instanceof Closure) {
return [$this->firstClosureParameterType($mailable), $mailable];
}
return [$mailable, $callback];
}
/**
* Forget all of the resolved mailer instances.
*
* @return $this
*/
public function forgetMailers()
{
$this->currentMailer = null;
return $this;
}
/**
* Handle dynamic method calls to the mailer.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->forwardCallTo($this->manager, $method, $parameters);
}
}