$tenant->workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, ], ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(ListTenants::class) ->assertTableActionVisible('view', $tenant) ->assertTableActionVisible('related_onboarding', $tenant) ->assertTableActionExists('related_onboarding', fn (Action $action): bool => $action->getLabel() === 'Resume onboarding', $tenant) ->assertTableActionHidden('archive', $tenant) ->assertTableActionHidden('restore', $tenant); Filament::setTenant(null, true); Livewire::actingAs($user) ->test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->assertActionVisible('related_onboarding') ->assertActionExists('related_onboarding', fn (Action $action): bool => $action->getLabel() === 'Resume onboarding') ->assertActionHidden('archive') ->assertActionHidden('restore'); })->with([ 'draft' => [fn (): Tenant => Tenant::factory()->draft()->create()], 'onboarding' => [fn (): Tenant => Tenant::factory()->onboarding()->create()], ]); it('shows archive only for active tenants on list and detail surfaces', function (): void { $tenant = Tenant::factory()->active()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(ListTenants::class) ->assertTableActionVisible('archive', $tenant) ->assertTableActionHidden('restore', $tenant) ->assertTableActionHidden('related_onboarding', $tenant); Filament::setTenant(null, true); Livewire::actingAs($user) ->test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->assertActionVisible('archive') ->assertActionHidden('restore'); }); it('shows restore only for archived tenants on list and detail surfaces', function (): void { $tenant = Tenant::factory()->archived()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(ListTenants::class) ->assertTableActionVisible('restore', $tenant) ->assertTableActionHidden('archive', $tenant) ->assertTableActionHidden('related_onboarding', $tenant); Filament::setTenant(null, true); Livewire::actingAs($user) ->test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->assertActionVisible('restore') ->assertActionHidden('archive') ->assertActionHidden('related_onboarding'); }); it('keeps lifecycle actions visible but disabled for in-scope members without mutation capability', function (): void { $tenant = Tenant::factory()->active()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'manager'); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(ListTenants::class) ->assertTableActionVisible('archive', $tenant) ->assertTableActionDisabled('archive', $tenant); }); it('returns 404 on tenant detail routes for non-members regardless of lifecycle state', function (\Closure $tenantFactory): void { $tenant = $tenantFactory(); [$user] = createUserWithTenant(role: 'owner', ensureDefaultMicrosoftProviderConnection: false); $this->actingAs($user) ->get(TenantResource::getUrl('view', ['record' => $tenant])) ->assertNotFound(); })->with([ 'draft' => [fn (): Tenant => Tenant::factory()->draft()->create()], 'onboarding' => [fn (): Tenant => Tenant::factory()->onboarding()->create()], 'active' => [fn (): Tenant => Tenant::factory()->active()->create()], 'archived' => [fn (): Tenant => Tenant::factory()->archived()->create()], ]); it('keeps tenant detail lifecycle actions bound to the viewed record instead of the selected header tenant', function (): void { $selectedTenant = Tenant::factory()->active()->create(); [$user, $selectedTenant] = createUserWithTenant(tenant: $selectedTenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false); $archivedTenant = Tenant::factory()->archived()->create([ 'workspace_id' => (int) $selectedTenant->workspace_id, ]); createUserWithTenant( tenant: $archivedTenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false, ); Filament::setTenant($selectedTenant, true); Livewire::actingAs($user) ->test(ViewTenant::class, ['record' => $archivedTenant->getRouteKey()]) ->assertActionVisible('restore') ->assertActionHidden('archive') ->assertActionHidden('related_onboarding'); }); it('refuses lifecycle-invalid archive and restore mutations without changing tenant state', function (): void { $activeTenant = Tenant::factory()->active()->create(); [$user, $activeTenant] = createUserWithTenant(tenant: $activeTenant, role: 'owner'); $onboardingTenant = Tenant::factory()->onboarding()->create([ 'workspace_id' => (int) $activeTenant->workspace_id, ]); createUserWithTenant( tenant: $onboardingTenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false, ); $this->actingAs($user); $auditLogger = app(WorkspaceAuditLogger::class); TenantResource::restoreTenant($activeTenant, $auditLogger); TenantResource::archiveTenant($onboardingTenant, $auditLogger); $activeTenant->refresh(); $onboardingTenant->refresh(); expect($activeTenant->trashed())->toBeFalse() ->and($onboardingTenant->trashed())->toBeFalse() ->and($onboardingTenant->status)->toBe(Tenant::STATUS_ONBOARDING) ->and(AuditLog::query() ->whereIn('action', [ AuditActionId::TenantArchived->value, AuditActionId::TenantRestored->value, ]) ->whereIn('resource_id', [ (string) $activeTenant->getKey(), (string) $onboardingTenant->getKey(), ]) ->exists())->toBeFalse(); });