Files
Investidor-V2/tests/Feature/PortalOperationsTest.php
nala 250ac35fd1
tests / ci (push) Canceled after 0s
first commit
2026-09-28 10:01:09 +02:00

98 lines
4.7 KiB
PHP

<?php
namespace Tests\Feature;
use App\Jobs\NotifyInterestReceived;
use App\Models\InterestRequest;
use App\Models\Sector;
use App\Models\User;
use App\Services\PortalAudit;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Mail\MailManager;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class PortalOperationsTest extends TestCase
{
use RefreshDatabase;
public function test_audit_records_actor_and_changes_without_free_text(): void
{
$user = User::factory()->create();
$sector = new Sector;
PortalAudit::save($sector, ['name' => 'Nome privado', 'slug' => 'test', 'description' => 'Texto confidencial', 'is_active' => true], $user->id);
PortalAudit::save($sector, ['is_active' => false], $user->id);
$events = DB::table('audit_events')->where('source_system', 'portal-management')->get();
$this->assertCount(2, $events);
$this->assertSame($user->id, $events[0]->actor_user_id);
$this->assertStringNotContainsString('Texto confidencial', json_encode($events));
$this->assertStringNotContainsString('Nome privado', json_encode($events));
$updated = $events->firstWhere('action', 'updated');
$this->assertFalse(json_decode($updated->after_data, true)['values']['is_active']);
$this->actingAs($user)->get('/management/history')->assertForbidden();
config(['portal.managers' => [$user->email]]);
$this->get('/management/history')->assertOk();
}
public function test_audit_failure_rolls_back_the_business_change(): void
{
$sector = Sector::create(['name' => 'Energia', 'slug' => 'energia', 'is_active' => true]);
try {
PortalAudit::save($sector, ['is_active' => false], 9999999);
$this->fail('Expected invalid actor foreign key to reject event.');
} catch (QueryException) {
$this->assertTrue($sector->fresh()->is_active);
}
}
public function test_public_notifications_are_disabled_by_default_and_enqueued_when_enabled(): void
{
$payload = ['fullName' => 'Pessoa de teste', 'email' => 'portal-integration-test@gmail.com',
'investorType' => 'empresa', 'country' => 'Moçambique', 'sectorInterest' => 'Energia',
'message' => 'Pedido de teste na base isolada.', 'privacyConsent' => true];
config(['portal.notifications_enabled' => false]);
$this->postJson('/api/v1/interest-requests', $payload)->assertCreated();
$this->assertDatabaseCount('jobs', 0);
config(['portal.notifications_enabled' => true, 'portal.notification_recipients' => ['team@example.invalid']]);
$this->postJson('/api/v1/interest-requests', $payload)->assertCreated();
$this->assertDatabaseCount('jobs', 1);
$this->assertDatabaseCount('interest_requests', 2);
config(['queue.connections.database.after_commit' => true]);
$this->postJson('/api/v1/interest-requests', $payload)->assertStatus(500);
$this->assertDatabaseCount('jobs', 1);
$this->assertDatabaseCount('interest_requests', 2);
}
public function test_job_checks_current_configuration_and_excludes_personal_data(): void
{
$interest = InterestRequest::create(['reference' => 'IR-TEST', 'full_name' => 'Pessoa confidencial',
'email' => 'personal@example.invalid', 'investor_type' => 'empresa', 'country' => 'Moçambique',
'sector_interest' => 'Energia', 'message' => 'Mensagem confidencial', 'privacy_consent' => true]);
$job = new NotifyInterestReceived($interest->id, 'team@example.invalid');
config(['portal.notifications_enabled' => false]);
Mail::shouldReceive('raw')->never();
$job->handle();
Mail::clearResolvedInstance('mail.manager');
Mail::swap(\Mockery::mock(MailManager::class));
config(['portal.notifications_enabled' => true, 'portal.notification_recipients' => ['team@example.invalid']]);
Mail::shouldReceive('raw')->once()->withArgs(function ($body, $callback) {
$this->assertStringContainsString('IR-TEST', $body);
$this->assertStringContainsString('/management/interests/', $body);
$this->assertStringNotContainsString('confidencial', $body);
$this->assertStringNotContainsString('personal@example.invalid', $body);
return is_callable($callback);
});
$job->handle();
}
public function test_readiness_reports_non_production_without_mutating_data(): void
{
$this->artisan('portal:readiness')->expectsOutput('[PENDENTE] Ambiente production')->assertExitCode(1);
$this->assertDatabaseCount('users', 0);
$this->assertDatabaseCount('jobs', 0);
}
}