actingAs($user); Filament::setTenant(null, true); session()->put(WorkspaceContext::SESSION_KEY, (int) $run->workspace_id); return Livewire::actingAs($user)->test(TenantlessOperationRunViewer::class, ['run' => $run]); } function operationSupportRequestHeaderActions(\Livewire\Features\SupportTesting\Testable $component): array { $instance = $component->instance(); if ($instance->getCachedHeaderActions() === []) { $instance->cacheInteractsWithHeaderActions(); } return $instance->getCachedHeaderActions(); } function operationSupportRequestHeaderPrimaryNames(\Livewire\Features\SupportTesting\Testable $component): array { return collect(operationSupportRequestHeaderActions($component)) ->reject(static fn ($action): bool => $action instanceof ActionGroup) ->map(static fn ($action): ?string => $action instanceof Action ? $action->getName() : null) ->filter() ->values() ->all(); } function operationSupportRequestHeaderMoreActionNames(\Livewire\Features\SupportTesting\Testable $component): array { $moreGroup = collect(operationSupportRequestHeaderActions($component)) ->first(static fn ($action): bool => $action instanceof ActionGroup && $action->getLabel() === 'More'); return collect($moreGroup?->getActions() ?? []) ->map(static fn ($action): ?string => $action instanceof Action ? $action->getName() : null) ->filter() ->values() ->all(); } function operationSupportRequestHeaderMoreAction(\Livewire\Features\SupportTesting\Testable $component, string $name): ?Action { $moreGroup = collect(operationSupportRequestHeaderActions($component)) ->first(static fn ($action): bool => $action instanceof ActionGroup && $action->getLabel() === 'More'); $action = collect($moreGroup?->getActions() ?? []) ->first(static fn ($action): bool => $action instanceof Action && $action->getName() === $name); return $action instanceof Action ? $action : null; } it('creates a run-scoped support request from the tenantless operation viewer', function (): void { $tenant = Tenant::factory()->create(['name' => 'Contoso Support Tenant']); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'operator'); $run = OperationRun::factory() ->forTenant($tenant) ->create([ 'type' => OperationRunType::BaselineCompare->value, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'summary_counts' => [ 'total' => 0, 'processed' => 0, ], 'failure_summary' => [[ 'message' => 'Run failed after provider validation.', ]], 'completed_at' => now()->subMinutes(10), ]); $component = operationSupportRequestComponent($user, $run); expect(operationSupportRequestHeaderPrimaryNames($component)) ->not->toContain('openSupportDiagnostics') ->not->toContain('requestSupport') ->and(operationSupportRequestHeaderMoreActionNames($component)) ->toEqualCanonicalizing(['openSupportDiagnostics', 'requestSupport']) ->and(operationSupportRequestHeaderMoreAction($component, 'openSupportDiagnostics')?->isIconButton()) ->toBeFalse(); $component ->assertActionVisible('openSupportDiagnostics') ->assertActionEnabled('openSupportDiagnostics') ->assertActionVisible('requestSupport') ->assertActionEnabled('requestSupport') ->assertActionExists('requestSupport', fn (Action $action): bool => $action->getLabel() === 'Request support') ->mountAction('requestSupport') ->setActionData([ 'severity' => SupportRequest::SEVERITY_BLOCKING, 'summary' => 'This failed operation needs support escalation.', 'reproduction_notes' => 'Open the canonical run detail and submit the request from the grouped secondary action.', ]) ->callMountedAction() ->assertHasNoActionErrors() ->assertNotified('Support request submitted'); $supportRequest = SupportRequest::query()->sole(); expect($supportRequest->internal_reference)->toMatch('/^SR-[0-9A-HJKMNP-TV-Z]{26}$/') ->and($supportRequest->workspace_id)->toBe((int) $tenant->workspace_id) ->and($supportRequest->tenant_id)->toBe((int) $tenant->getKey()) ->and($supportRequest->initiated_by_user_id)->toBe((int) $user->getKey()) ->and($supportRequest->primary_context_type)->toBe(SupportRequest::PRIMARY_CONTEXT_OPERATION_RUN) ->and($supportRequest->operation_run_id)->toBe((int) $run->getKey()) ->and($supportRequest->attachment_mode)->toBe(SupportRequest::ATTACHMENT_MODE_DIAGNOSTIC_SNAPSHOT_ATTACHED) ->and($supportRequest->severity)->toBe(SupportRequest::SEVERITY_BLOCKING) ->and($supportRequest->summary)->toBe('This failed operation needs support escalation.') ->and(data_get($supportRequest->context_envelope, 'primary_context.type'))->toBe('operation_run') ->and(data_get($supportRequest->context_envelope, 'primary_context.operation_run_id'))->toBe((int) $run->getKey()) ->and(data_get($supportRequest->context_envelope, 'diagnostic_snapshot'))->toBeArray(); }); it('keeps tenantless operation detail deny-as-not-found for workspace members without tenant entitlement', function (): void { $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), ]); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $workspace->getKey(), 'type' => OperationRunType::BaselineCompare->value, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'completed_at' => now(), ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]) ->get(route('admin.operations.view', ['run' => (int) $run->getKey()])) ->assertNotFound(); });