When to Release a New Major Package Version
Laravel package maintainers should release a new major version when a change breaks something they promised users would keep working. Those promises…
When Laravel code sends an email, a test should verify the intended message without contacting a mail provider or sending mail to a real address. Laravel’s Mail::fake() replaces the mail service during a test and records the mailables the code tries to send or queue. A mailable is the Laravel object that holds an email’s content and related data.
Use assertSent() to check mail Laravel was told to send, and assertQueued() to check mail Laravel was told to place in a background queue. These checks verify the code’s request to Laravel; they do not prove that a queue worker processed the message or that a provider delivered it. Laravel documents these mail fakes and assertions.
Call Mail::fake() before running the code you want to test. Then trigger the action and check that Laravel captured the expected mailable. The callback you pass to assertSent() checks the recipient and message data.
use App\Mail\OrderShipped;
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
public function test_order_shipment_sends_a_notice(): void
{
Mail::fake();
$user = User::factory()->create();
$order = Order::factory()->for($user)->create();
$this->post(route('orders.ship', $order));
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user, $order) {
return $mail->hasTo($user->email)
&& $mail->order->id === $order->id;
});
}
This example assumes the OrderShipped mailable exposes its order as $mail->order. The callback returns true only when the captured message is addressed to the expected recipient and contains the expected order. For a recipient-only check, Laravel also accepts an email address as the second argument: Mail::assertSent(OrderShipped::class, $user->email). Use the callback when recipient selection and message data both matter.
assertSent() checks that Laravel received an instruction to send the mailable. It does not test SMTP settings, provider acceptance, or inbox delivery. For these behaviors, use a separate integration or operational check.
Test a mailable’s content separately from the code that decides when and who receives it. Create the mailable, then use its assertions to check the subject and rendered HTML or plain-text body:
public function test_order_shipped_mailable_has_expected_content(): void
{
$order = Order::factory()->create();
$mail = new OrderShipped($order);
$mail->assertHasSubject('Your order has shipped');
$mail->assertSeeInHtml((string) $order->id);
$mail->assertSeeInText((string) $order->id);
}
These assertions inspect the rendered message, so they can catch errors in the content that a property-only check would miss. A content test by itself does not check an address that the sending code supplies separately, such as with Mail::to($user). Check the address in the send assertion, as in the earlier example. Laravel’s mailable assertions also cover sender, CC, BCC, reply-to, and attachments.
When code calls queue(), use assertQueued() rather than assertSent(). Laravel stores queued work for a background worker to handle later. assertQueued() confirms that code asked Laravel to queue the message; it does not confirm that a worker delivered it.
Mail::fake();
Mail::to($user)->queue(new OrderShipped($order));
Mail::assertQueued(OrderShipped::class, function (OrderShipped $mail) use ($user, $order) {
return $mail->hasTo($user->email)
&& $mail->order->id === $order->id;
});
Mail::assertNothingSent();
A mailable that implements Laravel’s ShouldQueue contract is queued even when application code calls send(). In that case, assert queued behavior. The 11.x mail documentation is an earlier reference. When using newer helpers such as one-time or count assertions, check the documentation for the Laravel version installed in your project.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com