array_merge([ 'enabled' => true, 'name' => 'Spec 256 Desk', 'create_url' => 'https://desk.example.test/api/tickets', 'api_token' => null, 'ticket_url_template' => 'https://desk.example.test/tickets/{reference}', 'timeout_seconds' => 5, ], $overrides), ]); } function spec256RunHandoffComponent(User $user, OperationRun $run): \Livewire\Features\SupportTesting\Testable { test()->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 spec256OperationRun(Tenant $tenant): OperationRun { return OperationRun::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'type' => OperationRunType::BaselineCompare->value, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'summary_counts' => [ 'total' => 0, 'processed' => 0, ], 'completed_at' => now(), ]); } it('creates an external ticket from the operation-run support action', function (): void { spec256ConfigureRunSupportDesk(); $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'operator'); $run = spec256OperationRun($tenant); Http::fake([ 'desk.example.test/*' => Http::response([ 'ticket_reference' => 'PSA-RUN-256', ], 201), ]); spec256RunHandoffComponent($user, $run) ->mountAction('requestSupport') ->setActionData([ 'severity' => SupportRequest::SEVERITY_HIGH, 'summary' => 'Run create external ticket handoff.', 'external_handoff_mode' => SupportRequest::EXTERNAL_HANDOFF_MODE_CREATE_EXTERNAL_TICKET, ]) ->callMountedAction() ->assertHasNoActionErrors() ->assertNotified('Support request submitted'); $supportRequest = SupportRequest::query()->sole(); expect($supportRequest->primary_context_type)->toBe(SupportRequest::PRIMARY_CONTEXT_OPERATION_RUN) ->and($supportRequest->operation_run_id)->toBe((int) $run->getKey()) ->and($supportRequest->external_handoff_mode)->toBe(SupportRequest::EXTERNAL_HANDOFF_MODE_CREATE_EXTERNAL_TICKET) ->and($supportRequest->external_ticket_reference)->toBe('PSA-RUN-256') ->and($supportRequest->external_ticket_url)->toBe('https://desk.example.test/tickets/PSA-RUN-256'); }); it('links an existing external ticket from the operation-run support action without outbound create', function (): void { spec256ConfigureRunSupportDesk(); $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'manager'); $run = spec256OperationRun($tenant); Http::fake(); spec256RunHandoffComponent($user, $run) ->mountAction('requestSupport') ->setActionData([ 'summary' => 'Run link existing external ticket.', 'external_handoff_mode' => SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET, 'external_ticket_reference' => 'PSA-RUN-LINK', ]) ->callMountedAction() ->assertHasNoActionErrors(); $supportRequest = SupportRequest::query()->sole(); expect($supportRequest->external_handoff_mode)->toBe(SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET) ->and($supportRequest->external_ticket_reference)->toBe('PSA-RUN-LINK') ->and($supportRequest->external_ticket_url)->toBe('https://desk.example.test/tickets/PSA-RUN-LINK'); Http::assertNothingSent(); }); it('keeps the internal run support request when external create fails', function (): void { spec256ConfigureRunSupportDesk(); $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $run = spec256OperationRun($tenant); Http::fake([ 'desk.example.test/*' => Http::failedConnection(), ]); spec256RunHandoffComponent($user, $run) ->mountAction('requestSupport') ->setActionData([ 'summary' => 'Run external handoff failure should keep internal support request.', 'external_handoff_mode' => SupportRequest::EXTERNAL_HANDOFF_MODE_CREATE_EXTERNAL_TICKET, ]) ->callMountedAction() ->assertHasNoActionErrors() ->assertNotified('Support request submitted'); $supportRequest = SupportRequest::query()->sole(); expect($supportRequest->primary_context_type)->toBe(SupportRequest::PRIMARY_CONTEXT_OPERATION_RUN) ->and($supportRequest->operation_run_id)->toBe((int) $run->getKey()) ->and($supportRequest->external_ticket_reference)->toBeNull() ->and($supportRequest->external_handoff_failure_summary)->toContain('configured timeout') ->and(OperationRun::query()->count())->toBe(1); });