create(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()]); config(['portal.managers' => [$user->email]]); return $user; } private function login(User $user, bool $mfa = true): static { return $this->actingAs($user)->withSession(['portal.mfa_actor' => $mfa ? $user->id : null, 'portal.mfa_at' => $mfa ? time() : 0]); } private function readiness(bool $ready): void { // Unit fixture only. Real activation requires the existing installer's verified backup evidence. $this->partialMock(OrganizationCountryInstallation::class, function ($mock) use ($ready) { $mock->shouldReceive('evidence')->andReturn(['ready' => $ready, 'backupDate' => null]); }); } private function input(): array { return ['hash' => $this->getJson('/management/opportunity-resources-install/organization-country')->assertOk()->json('hash'), 'confirm' => true, 'idempotency_key' => (string) Str::uuid(), 'reason' => 'Extensão sintética QA, sem contas nem preenchimento automático']; } public function test_cold_install_requires_readiness_is_atomic_and_repetition_has_no_duplicates(): void { $actor = $this->actor(); $this->login($actor); // TestCase has verified the isolated unit database before RefreshDatabase or these writes. Schema::table('organizations', fn ($table) => $table->dropColumn(['incorporation_country_code', 'incorporation_country_provenance'])); DB::table('migrations')->where('migration', OrganizationCountryInstallation::MIGRATION)->delete(); $this->readiness(false); $this->getJson('/management/opportunity-resources-install/organization-country')->assertOk()->assertJsonPath('installed', false)->assertJsonPath('consistent', true)->assertJsonPath('ready', false); $this->postJson('/management/opportunity-resources-install/organization-country', $this->input())->assertUnprocessable(); $this->readiness(true); $organizations = DB::table('organizations')->count(); $users = DB::table('users')->count(); $input = $this->input(); $this->postJson('/management/opportunity-resources-install/organization-country', $input)->assertOk()->assertJsonPath('changed', true)->assertJsonPath('new_columns', 2); $this->postJson('/management/opportunity-resources-install/organization-country', $input)->assertOk()->assertJsonPath('changed', true); $this->postJson('/management/opportunity-resources-install/organization-country', [...$input, 'reason' => 'Outro conteúdo na mesma chave de repetição'])->assertConflict(); $this->postJson('/management/opportunity-resources-install/organization-country', $this->input())->assertOk()->assertJsonPath('changed', false)->assertJsonPath('new_columns', 0); $this->assertSame($organizations, DB::table('organizations')->count()); $this->assertSame($users, DB::table('users')->count()); $this->assertSame(1, DB::table('migrations')->where('migration', OrganizationCountryInstallation::MIGRATION)->count()); $this->assertSame(2, DB::table('audit_events')->where('source_system', 'organization-country-installation')->count()); $this->assertFalse(config('organization_country.authenticated_installation')); } public function test_missing_mfa_other_user_and_partial_schema_are_denied(): void { $actor = $this->actor(); $this->readiness(true); $this->login($actor, false); $this->postJson('/management/opportunity-resources-install/organization-country', $this->input())->assertForbidden(); $this->login(User::factory()->create()); $this->getJson('/management/opportunity-resources-install/organization-country')->assertForbidden(); $this->login($actor); Schema::table('organizations', fn ($table) => $table->dropColumn('incorporation_country_provenance')); $this->getJson('/management/opportunity-resources-install/organization-country')->assertOk()->assertJsonPath('consistent', false); $this->postJson('/management/opportunity-resources-install/organization-country', $this->input())->assertConflict(); $this->assertSame(0, DB::table('audit_events')->where('source_system', 'organization-country-installation')->count()); } public function test_designated_holder_uses_existing_authority_without_legacy_manager_allowlist(): void { $holder = $this->actor(); $second = User::factory()->create(); $approver = User::factory()->create(); config(['portal.managers' => []]); DB::table('portal_superuser_pair')->insert(['id' => 1, 'first_user_id' => $holder->id, 'second_user_id' => $second->id, 'approved_by' => $approver->id, 'version' => 1]); $this->readiness(false); $this->login($holder); $this->getJson('/management/opportunity-resources-install/organization-country')->assertOk()->assertJsonPath('installed', true); $this->postJson('/management/opportunity-resources-install/organization-country', $this->input())->assertOk()->assertJsonPath('changed', false); $this->login($approver); $this->getJson('/management/opportunity-resources-install/organization-country')->assertForbidden(); } }