create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $connection = ProviderConnection::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), ]); $verificationRun = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'user_id' => (int) $user->getKey(), 'initiator_name' => $user->name, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); $draft = createOnboardingDraft([ 'workspace' => $tenant->workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'current_step' => 'verify', 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, 'provider_connection_id' => (int) $connection->getKey(), 'verification_operation_run_id' => (int) $verificationRun->getKey(), ], ]); app(OnboardingDraftMutationService::class)->mutate( draft: $draft, actor: $user, mutator: static function (): void {}, ); $event = ProductUsageEvent::query()->sole(); $serializedEvent = json_encode($event->toArray(), JSON_THROW_ON_ERROR); expect($event->event_name)->toBe(ProductUsageEventCatalog::ONBOARDING_CHECKPOINT_COMPLETED) ->and($event->workspace_id)->toBe((int) $tenant->workspace_id) ->and($event->tenant_id)->toBe((int) $tenant->getKey()) ->and($event->user_id)->toBe((int) $user->getKey()) ->and($event->subject_type)->toBe('tenant_onboarding_session') ->and($event->subject_id)->toBe((string) $draft->getKey()) ->and($event->metadata['checkpoint_key'] ?? null)->toBe(OnboardingCheckpoint::VerifyAccess->value) ->and($event->metadata['lifecycle_state'] ?? null)->toBe(OnboardingLifecycleState::ReadyForActivation->value) ->and($event->metadata['completed_at'] ?? null)->not->toBeNull() ->and($serializedEvent)->not->toContain('@') ->and($serializedEvent)->not->toContain((string) $tenant->name) ->and($serializedEvent)->not->toContain((string) ($draft->state['tenant_name'] ?? '')); }); it('does not record onboarding telemetry for pre-tenant drafts', function (): void { $workspace = \App\Models\Workspace::factory()->create(); $user = \App\Models\User::factory()->create(); $draft = createOnboardingDraft([ 'workspace' => $workspace, 'started_by' => $user, 'updated_by' => $user, 'current_step' => 'identify', 'state' => [ 'entra_tenant_id' => fake()->uuid(), 'tenant_name' => 'Pre Tenant Draft', ], ]); app(OnboardingDraftMutationService::class)->mutate( draft: $draft, actor: $user, mutator: static function (): void {}, ); expect(ProductUsageEvent::query()->count())->toBe(0); });