How do you test sending emails? In Laravel, the process of sending emails can be "faked."
We continue the same topic from the previous lessons. You send mail or notifications to the admin user within a Job, dispatched from the Controller or anywhere else.
use App\Models\User;use App\Models\Product;use App\Mail\NewProductCreatedMail;use Illuminate\Support\Facades\Mail;use Illuminate\Support\Facades\Notification;use App\Notifications\NewProductCreatedNotification; class NewProductNotifyJob implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct(private readonly Product $product) {} public function handle(): void { $admin = User::where('is_admin', true)->first(); Mail::to($admin->email)->send(new NewProductCreatedMail($this->product)); Notification::send($admin, new NewProductCreatedNotification($this->product)); }}
Both mail and notifications are only created using an Artisan command, and nothing changes inside them.
Again, we start the test by making a request to create a product.
use App\Models\User;use App\Jobs\NewProductNotifyJob;use function Pest\Laravel\actingAs; beforeEach(function () { $this->user = User::factory()->create();}); test('product test create job mail send successfully', function () { $admin = User::factory()->create(['is_admin' => true]); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, ]); // assert});
Next, as with any fake, we must use the Mail
facade and fake()
method.
use App\Models\User;use App\Jobs\NewProductNotifyJob;use function Pest\Laravel\actingAs;use Illuminate\Support\Facades\Mail;use App\Mail\NewProductCreatedMail; beforeEach(function () { $this->user = User::factory()->create();}); test('product test create job mail send successfully', function () { Mail::fake(); $admin = User::factory()->create(['is_admin' => true]); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, ]); Mail::assertSent(NewProductCreatedMail::class); });
If you are using notifications, it's the same: use the Notification
facade with the fake()
method.
The only difference is that when asserting a notification, you must provide the user who should receive it.
use App\Models\User;use App\Jobs\NewProductNotifyJob;use function Pest\Laravel\actingAs;use Illuminate\Support\Facades\Notification;use App\Notifications\NewProductCreatedNotification; beforeEach(function () { $this->user = User::factory()->create();}); test('product test create job mail send successfully', function () { Mail::fake(); Notification::fake(); $admin = User::factory()->create(['is_admin' => true]); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, ]); Mail::assertSent(NewProductCreatedMail::class); Notification::assertSentTo($admin, NewProductCreatedNotification::class); });