create(); $actor = User::factory()->create(); $target = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $actor->getKey(), 'role' => WorkspaceRole::Manager->value, ]); $targetMembership = WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $target->getKey(), 'role' => WorkspaceRole::Owner->value, ]); $manager = app(WorkspaceMembershipManager::class); expect(fn () => $manager->changeRole($workspace, $actor, $targetMembership, WorkspaceRole::Manager->value)) ->toThrow(DomainException::class, 'You cannot demote the last remaining owner.'); $targetMembership->refresh(); expect($targetMembership->role)->toBe(WorkspaceRole::Owner->value); $audit = AuditLog::query() ->where('workspace_id', $workspace->getKey()) ->where('action', 'workspace_membership.last_owner_blocked') ->where('status', 'blocked') ->latest('id') ->first(); expect($audit)->not->toBeNull(); expect($audit->metadata)->toMatchArray([ 'workspace_id' => (int) $workspace->getKey(), 'actor_user_id' => (int) $actor->getKey(), 'target_user_id' => (int) $target->getKey(), 'attempted_role' => WorkspaceRole::Manager->value, ]); }); it('blocks removing the last remaining workspace owner and audits it', function () { $workspace = Workspace::factory()->create(); $actor = User::factory()->create(); $target = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $actor->getKey(), 'role' => WorkspaceRole::Manager->value, ]); $targetMembership = WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $target->getKey(), 'role' => WorkspaceRole::Owner->value, ]); $manager = app(WorkspaceMembershipManager::class); expect(fn () => $manager->removeMember($workspace, $actor, $targetMembership)) ->toThrow(DomainException::class, 'You cannot remove the last remaining owner.'); expect(WorkspaceMembership::query()->whereKey($targetMembership->getKey())->exists())->toBeTrue(); $audit = AuditLog::query() ->where('workspace_id', $workspace->getKey()) ->where('action', 'workspace_membership.last_owner_blocked') ->where('status', 'blocked') ->latest('id') ->first(); expect($audit)->not->toBeNull(); expect($audit->metadata)->toMatchArray([ 'workspace_id' => (int) $workspace->getKey(), 'actor_user_id' => (int) $actor->getKey(), 'target_user_id' => (int) $target->getKey(), 'attempted_action' => 'remove', ]); });