Files
City10/tests/Feature/CitizenApprovalTest.php
T
marcocosta10000 79ce2a1825 feat(world): add persistent citizen simulation with needs, jobs, and social features
- Adds Character model with survival needs (hunger, thirst, energy) and state machine
- Implements city:tick world ticker for offline progression every minute
- Adds city territory expansion and building construction system
- Introduces job economy, inventory, and transaction audit trail
- Adds social graph (friends, marriage, children) and character chat
- Implements admin approval workflow for new registrations
- Adds hospital admission system for traffic accidents
- Includes comprehensive feature tests and world seeders
2026-10-17 21:46:23 -03:00

168 lines
5.0 KiB
PHP
Executable File

<?php
namespace Tests\Feature;
use App\Models\Character;
use App\Models\City;
use App\Models\LegalDocument;
use App\Models\User;
use App\Models\UserConsent;
use Database\Seeders\CityWorldSeeder;
use Database\Seeders\LegalDocumentSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/**
* Registration approval workflow for citizen accounts.
*/
class CitizenApprovalTest extends TestCase
{
use RefreshDatabase;
/**
* Boot legal docs + world for each test.
*/
protected function setUp(): void
{
parent::setUp();
$this->seed(LegalDocumentSeeder::class);
$this->seed(CityWorldSeeder::class);
}
/**
* Create an admin that already accepted all current legal documents.
*/
private function makeAdmin(): User
{
$admin = User::factory()->admin()->create();
foreach (LegalDocument::where('is_current', true)->pluck('id') as $docId) {
UserConsent::create([
'user_id' => $admin->id,
'legal_document_id' => $docId,
'accepted_at' => now(),
'ip_address' => '127.0.0.1',
'user_agent' => 'phpunit',
'source' => 'web_form',
]);
}
return $admin;
}
/**
* New registrations must start as pending, not active.
*/
public function test_register_creates_pending_user(): void
{
$response = $this->post('/register', [
'name' => 'Nova Pessoa',
'email' => 'nova@example.com',
'password' => 'Secret123!',
'password_confirmation' => 'Secret123!',
'locale' => 'pt_BR',
'captcha' => $this->captchaForRegister(),
]);
$user = User::where('email', 'nova@example.com')->first();
$this->assertNotNull($user);
$this->assertSame(User::STATUS_PENDING, $user->status);
$this->assertFalse($user->is_active);
$response->assertRedirect(route('terms.accept'));
}
/**
* Pending users are sent to the approval wait screen from the dashboard.
*/
public function test_pending_user_sees_wait_screen(): void
{
$user = User::factory()->pending()->create();
$this->actingAs($user)
->get('/dashboard')
->assertRedirect(route('account.pending'));
$this->actingAs($user)
->get(route('account.pending'))
->assertOk()
->assertSee(__('auth.pending_title'), false);
}
/**
* Login attempt by a pending account shows the approval message.
*/
public function test_login_rejects_pending_with_message(): void
{
$user = User::factory()->pending()->create(['password' => 'Secret123!']);
$response = $this->post('/login', [
'email' => $user->email,
'password' => 'Secret123!',
'captcha' => $this->captchaForLogin(),
]);
$response->assertSessionHasErrors('email');
$this->assertSame(__('auth.pending'), session('errors')->first('email'));
}
/**
* Admin approval activates the account and creates the character.
*/
public function test_admin_approval_creates_character(): void
{
$admin = $this->makeAdmin();
$pending = User::factory()->pending()->create(['name' => 'Ana Silva']);
$this->actingAs($admin)
->post(route('admin.citizens.approve', $pending))
->assertRedirect(route('admin.citizens.index'));
$pending->refresh();
$this->assertSame(User::STATUS_ACTIVE, $pending->status);
$this->assertTrue($pending->is_active);
$character = Character::query()->where('user_id', $pending->id)->first();
$this->assertNotNull($character);
$this->assertSame('Ana', $character->name);
$this->assertNotNull(City::active());
$this->assertSame(City::active()->id, $character->city_id);
}
/**
* Banned accounts cannot authenticate.
*/
public function test_banned_user_cannot_login(): void
{
$user = User::factory()->inactive()->create(['password' => 'Secret123!']);
$response = $this->post('/login', [
'email' => $user->email,
'password' => 'Secret123!',
'captcha' => $this->captchaForLogin(),
]);
$response->assertSessionHasErrors('email');
}
/**
* Solve the session math CAPTCHA for a register request.
*/
private function captchaForRegister(): int
{
// Prime the session by loading the form first in real usage; in tests
// we set the session keys directly to avoid an extra round-trip.
$a = random_int(1, 9);
$b = random_int(1, 9);
session(['captcha_result' => $a + $b, 'captcha_expires_at' => now()->addMinutes(10)->getTimestamp()]);
return $a + $b;
}
/**
* Solve the session math CAPTCHA for a login request.
*/
private function captchaForLogin(): int
{
return $this->captchaForRegister();
}
}