shopit-back/tests/Unit/Notification/NotificationMailServiceLogg...

133 lines
4.2 KiB
PHP

<?php
namespace Tests\Unit\Notification;
use App\Domains\Integration\Services\MailService;
use App\Domains\Notification\Services\NotificationMailService;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Ticket\Services\TicketPdfService;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Mockery;
use ReflectionMethod;
use RuntimeException;
use Tests\TestCase;
class NotificationMailServiceLoggingTest extends TestCase
{
private NotificationMailService $service;
private MailService $mailService;
protected function setUp(): void
{
parent::setUp();
$this->mailService = Mockery::mock(MailService::class);
$this->service = new NotificationMailService(
$this->mailService,
Mockery::mock(TicketPdfService::class),
);
}
public function test_it_logs_and_swallows_a_missing_purchase(): void
{
$this->createEmptyPurchasesTable();
Log::shouldReceive('channel')->once()->with('emails')->andReturnSelf();
Log::shouldReceive('warning')->once()->with(
'Notification email skipped.',
[
'purchase_id' => 123,
'reason' => 'purchase_not_found',
'missing_model' => Purchase::class,
'email_type' => 'purchase_paid',
],
);
$this->service->sendPurchasePaid(123);
}
public function test_missing_purchase_log_includes_the_requested_ticket_ids(): void
{
$this->createEmptyPurchasesTable();
Log::shouldReceive('channel')->once()->with('emails')->andReturnSelf();
Log::shouldReceive('warning')->once()->with(
'Notification email skipped.',
[
'purchase_id' => 123,
'requested_ticket_count' => 2,
'requested_ticket_ids' => [10, 11],
'reason' => 'purchase_not_found',
'missing_model' => Purchase::class,
'email_type' => 'tickets_available',
],
);
$this->service->sendTicketsAvailable(123, [10, 11]);
}
public function test_it_logs_successful_delivery_with_the_mailer(): void
{
$this->mailService->shouldReceive('mailerName')->once()->andReturn('smtp');
Log::shouldReceive('channel')->once()->with('emails')->andReturnSelf();
Log::shouldReceive('info')->once()->with(
'Notification email sent.',
[
'user_id' => 10,
'tenant_code' => 'tenant-test',
'email_type' => 'welcome',
'mailer' => 'smtp',
],
);
$this->sendLogged(
'welcome',
['user_id' => 10],
fn (): array => ['tenant_code' => 'tenant-test'],
);
}
public function test_it_logs_and_rethrows_delivery_failures(): void
{
$exception = new RuntimeException('SMTP unavailable.');
Log::shouldReceive('channel')->once()->with('emails')->andReturnSelf();
Log::shouldReceive('error')->once()->with(
'Notification email delivery failed.',
Mockery::on(fn (array $context): bool => $context['purchase_id'] === 123
&& $context['email_type'] === 'purchase_paid'
&& $context['exception'] === $exception),
);
$this->expectExceptionObject($exception);
$this->sendLogged('purchase_paid', ['purchase_id' => 123], function () use ($exception): array {
throw $exception;
});
}
/** @param array<string, mixed> $context */
private function sendLogged(string $emailType, array $context, callable $send): void
{
(new ReflectionMethod($this->service, 'sendLogged'))->invoke(
$this->service,
$emailType,
$context,
$send,
);
}
private function createEmptyPurchasesTable(): void
{
config([
'database.default' => 'sqlite',
'database.connections.sqlite.database' => ':memory:',
]);
Schema::connection('sqlite')->create('compras', function (Blueprint $table): void {
$table->id();
});
}
}