createTenant(); $this->createEmailIntegration(); TenantIntegration::create([ 'tenant_code' => $tenant->codigo, 'integration_code' => 'email', 'integration_data' => $this->emailData(), ]); $mailer = Mockery::mock(Mailer::class); $mailer->shouldReceive('alwaysFrom') ->once() ->with('store@example.com', 'Acme Mail'); $manager = Mockery::mock(MailManager::class); $manager->shouldReceive('build') ->once() ->with(Mockery::on(fn (array $config): bool => $config === [ 'name' => 'tenant-smtp-acme', 'transport' => 'smtp', 'scheme' => 'smtp', 'host' => 'smtp.example.com', 'port' => 587, 'username' => 'mailer@example.com', 'password' => 'secret', 'timeout' => null, 'local_domain' => null, ])) ->andReturn($mailer); $service = (new MailService($manager))->forTenant($tenant->codigo); $this->assertSame('tenant-smtp', $service->mailerName()); } public function test_it_uses_the_default_mailer_when_tenant_configuration_is_not_required(): void { Mail::fake(); config(['mail.default' => 'array']); $tenant = $this->createTenant(); Integration::create([ 'integration_code' => 'email', 'name' => 'Email', 'requires_tenant_configuration' => false, ]); $service = (new MailService)->forTenant($tenant->codigo); $service->send('customer@example.com', 'Default mailer', '

Fallback

'); $this->assertSame('array', $service->mailerName()); Mail::assertSent(Mailable::class, function (Mailable $mail): bool { return $mail->hasTo('customer@example.com') && $mail->subject === 'Default mailer' && str_contains($mail->render(), 'Fallback'); }); } public function test_on_setup_sends_a_branded_test_email_to_the_configured_sender(): void { Mail::fake(); $tenant = $this->createTenant(); $this->createEmailIntegration(); TenantIntegration::create([ 'tenant_code' => $tenant->codigo, 'integration_code' => 'email', 'integration_data' => $this->emailData(), ]); (new MailService)->forTenant($tenant->codigo)->onSetup(); Mail::assertSent(Mailable::class, function (Mailable $mail) use ($tenant): bool { $html = $mail->render(); return $mail->hasTo('store@example.com') && $mail->subject === 'Configuración de correo validada' && str_contains($html, $tenant->nombre) && str_contains($html, 'background-color: #112233') && str_contains($html, 'background-color: #445566'); }); } public function test_configuring_the_email_integration_runs_its_setup_hook(): void { Mail::fake(); $tenant = $this->createTenant(); $integration = $this->createEmailIntegration(); app(TenantIntegrationService::class)->updateOrCreateIntegration( $tenant->codigo, $integration, $this->emailData(), ); Mail::assertSent(Mailable::class, 1); } private function createTenant(): Tenant { $logo = Attachment::create([ 'path' => 'tenants/logo.png', 'filename' => 'logo.png', 'type' => AttachmentType::Image, 'mime_type' => 'image/png', 'extension' => 'png', ]); return Tenant::create([ 'codigo' => 'acme', 'nombre' => 'Acme Store', 'dominio' => 'acme.example.com', 'primary_color' => '#778899', 'secondary_color' => '#64748b', 'danger_color' => '#dc2626', 'success_color' => '#16a34a', 'header_bg_color' => '#112233', 'footer_bg_color' => '#445566', 'header_logo_id' => $logo->id, 'footer_logo_id' => $logo->id, ]); } private function createEmailIntegration(): Integration { return Integration::create([ 'integration_code' => 'email', 'name' => 'Email', ]); } /** * @return array */ private function emailData(): array { return [ 'MAIL_SCHEME' => 'smtp', 'MAIL_HOST' => 'smtp.example.com', 'MAIL_PORT' => 587, 'MAIL_USERNAME' => 'mailer@example.com', 'MAIL_PASSWORD' => 'secret', 'MAIL_FROM_ADDRESS' => 'store@example.com', 'MAIL_FROM_NAME' => 'Acme Mail', ]; } }