create(); config(['portal.managers' => [$manager->email], 'portal.opportunity_dashboard_access_enabled' => true]); $this->actingAs($manager)->get('/dashboard')->assertOk()->assertInertia(fn (Assert $page) => $page ->component('dashboard')->where('auth.canManagePortal', true) ->where('opportunityManagement.installed', true) ->where('opportunityManagement.manage.label', 'Gestão de Oportunidades') ->where('opportunityManagement.create.label', 'Nova oportunidade')); // Discover destinations from the dashboard response, rather than assuming // a successful direct request proves dashboard navigation. $dashboard = $this->get('/dashboard')->viewData('page')['props']['opportunityManagement']; $this->get($dashboard['manage']['href'])->assertInertia(fn (Assert $page) => $page->component('management/opportunities')); $this->get($dashboard['create']['href'])->assertInertia(fn (Assert $page) => $page->component('management/opportunity-draft')->where('record', null)); $draft = $this->postJson('/management/opportunities/drafts', ['creation_key' => (string) Str::uuid(), 'title' => 'QA dashboard draft', 'reason' => 'Criação de rascunho pelo painel de gestão QA'])->assertCreated()->json(); $id = $draft['id']; $this->get('/management/opportunities/'.$id.'/edit')->assertInertia(fn (Assert $page) => $page->where('values.title', 'QA dashboard draft')); $update = $this->putJson('/management/opportunities/'.$id.'/draft', ['etag' => $draft['etag'], 'title' => 'QA dashboard edited', 'reason' => 'Edição e recuperação autorizadas no ensaio QA'])->assertOk()->json(); $request = ['etag' => $update['etag'], 'action' => 'archive', 'reason' => 'Arquivo explícito sem eliminar o rascunho QA', 'confirm' => true]; $this->postJson('/management/opportunities/'.$id.'/lifecycle', [...$request, 'confirm' => false])->assertUnprocessable(); $this->postJson('/management/opportunities/'.$id.'/lifecycle', $request)->assertOk(); $this->assertDatabaseHas('opportunities', ['id' => $id, 'status' => 'archived', 'title' => 'QA dashboard edited', 'deleted_at' => null, 'first_submitted_at' => null, 'management_closed_once' => false]); $this->get($dashboard['manage']['href'].'?status=archived')->assertInertia(fn (Assert $page) => $page->where('records.data.0.id', $id)); $this->putJson('/management/opportunities/'.$id.'/draft', ['etag' => $update['etag'], 'reason' => $request['reason']])->assertConflict(); $this->postJson('/management/opportunities/'.$id.'/lifecycle', [...$request, 'action' => 'restore', 'etag' => app(OpportunityManagement::class)->etag(Opportunity::findOrFail($id))])->assertOk(); $this->get('/management/opportunities/'.$id.'/edit')->assertInertia(fn (Assert $page) => $page->where('record.status', 'draft')->where('values.title', 'QA dashboard edited')); $this->assertSame(0, Opportunity::published()->count()); $this->assertSame(4, DB::table('audit_events')->where('source_system', 'opportunity-management')->where('after_data->record_id', $id)->count()); } public function test_investor_unverified_manager_and_guest_do_not_gain_management_access(): void { $manager = User::factory()->unverified()->create(); $investor = User::factory()->create(); config(['portal.managers' => [$manager->email], 'portal.opportunity_dashboard_access_enabled' => true]); $this->actingAs($investor)->get('/dashboard')->assertInertia(fn (Assert $page) => $page->where('summary', null)->where('opportunityManagement', null)->where('auth.canManagePortal', false)); $this->get('/management/opportunities')->assertForbidden(); $this->postJson('/management/opportunities/drafts', ['creation_key' => (string) Str::uuid()])->assertForbidden(); $this->actingAs($manager)->get('/dashboard')->assertRedirect('/email/verify'); $this->getJson('/management/opportunities')->assertForbidden(); $this->assertSame(0, Opportunity::count()); auth()->forgetGuards(); $this->flushSession(); $this->get('/dashboard')->assertRedirect('/login'); } public function test_missing_installation_is_explicit_and_disabled_increment_preserves_compatibility(): void { $manager = User::factory()->create(); config(['portal.managers' => [$manager->email], 'portal.opportunity_dashboard_access_enabled' => false]); $this->actingAs($manager)->get('/dashboard')->assertInertia(fn (Assert $page) => $page->where('opportunityManagement', null)); $this->postJson('/management/opportunities/1/lifecycle', ['etag' => str_repeat('a', 64), 'action' => 'archive', 'reason' => 'Incremento ainda não disponibilizado nesta configuração', 'confirm' => true])->assertUnprocessable(); config(['portal.opportunity_dashboard_access_enabled' => true]); $migration = require database_path('migrations/2026_10_09_020000_extend_opportunity_management.php'); $migration->down(); $this->get('/dashboard')->assertInertia(fn (Assert $page) => $page->where('opportunityManagement.installed', false)->where('opportunityManagement.installationHref', '/management/opportunity-management-install')); $this->postJson('/management/opportunities/drafts', ['creation_key' => (string) Str::uuid()])->assertServiceUnavailable(); } }