actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->assertActionVisible('archive') ->assertActionDisabled('archive') ->assertActionExists('archive', function (Action $action): bool { return $action->getTooltip() === UiTooltips::INSUFFICIENT_PERMISSION; }); $contextEntries = collect(TenantResource::tenantViewContextEntries($tenant))->keyBy('key'); expect($contextEntries->get('tenant_edit')['availability'] ?? null)->toBe('authorization_denied') ->and($contextEntries->get('provider_connections')['availability'] ?? null)->toBe('available'); }); it('keeps archive enabled for owner members and exposes edit/provider navigation in contextual related content', function () { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->assertActionVisible('archive') ->assertActionEnabled('archive'); $contextEntries = collect(TenantResource::tenantViewContextEntries($tenant))->keyBy('key'); expect($contextEntries->get('tenant_edit')['availability'] ?? null)->toBe('available') ->and($contextEntries->get('provider_connections')['availability'] ?? null)->toBe('available'); }); it('does not execute the archive action for readonly members (silently blocked by Filament)', function () { [$user, $tenant] = createUserWithTenant(role: 'readonly'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->assertActionDisabled('archive') ->mountAction('archive') ->callMountedAction() ->assertSuccessful(); expect(Tenant::withTrashed()->find($tenant->getKey())?->trashed())->toBeFalse(); }); it('shows resume onboarding when the tenant has a resumable linked onboarding draft', function () { $tenant = Tenant::factory()->onboarding()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false); createOnboardingDraft([ 'workspace' => $tenant->workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, ], ]); $this->actingAs($user); Filament::setTenant(null, true); expect(collect(TenantResource::tenantViewContextEntries($tenant)) ->firstWhere('key', 'related_onboarding')['value'] ?? null) ->toBe('Resume onboarding'); }); it('shows a cancelled-onboarding label and repairs stale onboarding tenant status when the linked draft was cancelled', function () { $tenant = Tenant::factory()->onboarding()->create([ 'name' => 'Cancelled Flow Tenant', ]); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false); $draft = createOnboardingDraft([ 'workspace' => $tenant->workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'status' => 'cancelled', 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, ], ]); $this->actingAs($user); Filament::setTenant(null, true); $this->get(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])) ->assertSuccessful() ->assertSee('This onboarding draft is Cancelled.'); $tenant->refresh(); expect($tenant->status)->toBe(Tenant::STATUS_DRAFT); expect(AuditLog::query() ->where('workspace_id', (int) $tenant->workspace_id) ->where('tenant_id', (int) $tenant->getKey()) ->where('action', \App\Support\Audit\AuditActionId::TenantReturnedToDraft->value) ->exists())->toBeTrue(); expect(collect(TenantResource::tenantViewContextEntries($tenant)) ->firstWhere('key', 'related_onboarding')['value'] ?? null) ->toBe('View cancelled onboarding draft'); }); });