create(); $this->actingAs($user) ->get('/admin/t/'.$unauthorizedTenant->external_id.'/policies') ->assertNotFound(); }); test('tenant portfolio tenant view returns 404 for non-member tenant record', function () { $authorizedTenant = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-portfolio-authorized-view']); $unauthorizedTenant = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-portfolio-unauthorized-view']); [$user, $authorizedTenant] = createUserWithTenant($authorizedTenant, role: 'owner'); $this->actingAs($user); $this->get(ManagedEnvironmentLinks::viewUrl($unauthorizedTenant))->assertNotFound(); }); test('tenant portfolio tenant edit returns 404 for non-member tenant record', function () { $authorizedTenant = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-portfolio-authorized-edit']); $unauthorizedTenant = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-portfolio-unauthorized-edit']); [$user, $authorizedTenant] = createUserWithTenant($authorizedTenant, role: 'owner'); $this->actingAs($user); $this->get(ManagedEnvironmentResource::getUrl('edit', ['record' => $unauthorizedTenant], panel: 'admin'))->assertNotFound(); }); test('tenant portfolio lists only tenants the user can access', function () { $authorizedTenant = ManagedEnvironment::factory()->create([ 'managed_environment_id' => 'tenant-portfolio-authorized', 'name' => 'Authorized ManagedEnvironment', ]); $unauthorizedTenant = ManagedEnvironment::factory()->create([ 'managed_environment_id' => 'tenant-portfolio-unauthorized', 'name' => 'Unauthorized ManagedEnvironment', ]); [$user, $authorizedTenant] = createUserWithTenant($authorizedTenant, role: 'owner'); $this->actingAs($user); $this->get(ManagedEnvironmentLinks::indexUrl($authorizedTenant)) ->assertOk() ->assertSee($authorizedTenant->name) ->assertDontSee($unauthorizedTenant->name); }); test('tenant portfolio bulk sync dispatches one job per eligible tenant', function () { Bus::fake(); $tenantA = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-bulk-a']); [$user, $tenantA] = createUserWithTenant($tenantA, role: 'owner'); $this->actingAs($user); $tenantB = ManagedEnvironment::factory()->create([ 'managed_environment_id' => 'tenant-bulk-b', 'workspace_id' => (int) $tenantA->workspace_id, ]); $user->tenants()->syncWithoutDetaching([ $tenantB->getKey() => ['role' => 'operator'], ]); setAdminPanelContext($tenantA); Livewire::test(ListManagedEnvironments::class) ->assertTableBulkActionVisible('syncSelected') ->callTableBulkAction('syncSelected', collect([$tenantA, $tenantB])); Bus::assertDispatchedTimes(BulkTenantSyncJob::class, 1); $this->assertDatabaseHas('operation_runs', [ 'managed_environment_id' => $tenantA->id, 'user_id' => $user->id, 'type' => 'tenant.sync', 'status' => 'queued', ]); }); test('tenant portfolio bulk sync is disabled for readonly users', function () { Bus::fake(); $tenant = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-bulk-readonly']); [$user, $tenant] = createUserWithTenant($tenant, role: 'readonly'); $this->actingAs($user); setAdminPanelContext($tenant); $livewire = Livewire::actingAs($user) ->test(ListManagedEnvironments::class) ->selectTableRecords([$tenant]) ->assertTableBulkActionVisible('syncSelected') ->assertTableBulkActionDisabled('syncSelected'); $actions = $livewire->parseNestedTableBulkActions('syncSelected'); $livewire->assertActionExists($actions, fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission()); $livewire->callTableBulkAction('syncSelected', collect([$tenant])); Bus::assertNotDispatched(BulkTenantSyncJob::class); }); test('tenant portfolio bulk sync ignores out-of-scope tenants that cannot be selected', function () { Bus::fake(); $tenantA = ManagedEnvironment::factory()->create(['managed_environment_id' => 'tenant-bulk-mixed-a']); [$user, $tenantA] = createUserWithTenant($tenantA, role: 'operator', workspaceRole: 'operator'); $this->actingAs($user); $tenantB = ManagedEnvironment::factory()->create([ 'managed_environment_id' => 'tenant-bulk-mixed-b', 'workspace_id' => (int) $tenantA->workspace_id, ]); setAdminPanelContext($tenantA); $livewire = Livewire::actingAs($user) ->test(ListManagedEnvironments::class) ->assertCanSeeTableRecords([$tenantA]) ->assertCanNotSeeTableRecords([$tenantB]) ->selectTableRecords([$tenantA]) ->assertTableBulkActionVisible('syncSelected') ->assertTableBulkActionEnabled('syncSelected'); $livewire->callTableBulkAction('syncSelected', collect([$tenantA, $tenantB])); Bus::assertDispatched(BulkTenantSyncJob::class, fn (BulkTenantSyncJob $job): bool => $job->tenantIds === [$tenantA->getKey()]); }); test('tenant set event updates user tenant preference last used timestamp', function () { [$user, $tenant] = createUserWithTenant(); TenantSet::dispatch($tenant, $user); $this->assertDatabaseHas('user_managed_environment_preferences', [ 'user_id' => $user->id, 'managed_environment_id' => $tenant->id, ]); });