diff --git a/ui/src/components/chat/AgentCallDisplay.tsx b/ui/src/components/chat/AgentCallDisplay.tsx
index 6ce80d14c..3d0e75e52 100644
--- a/ui/src/components/chat/AgentCallDisplay.tsx
+++ b/ui/src/components/chat/AgentCallDisplay.tsx
@@ -1,12 +1,28 @@
import { useMemo, useState } from "react";
import { FunctionCall } from "@/types";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { convertToUserFriendlyName } from "@/lib/utils";
+import { convertToUserFriendlyName, isAgentToolName } from "@/lib/utils";
import { ChevronDown, ChevronUp, MessageSquare, Loader2, AlertCircle, CheckCircle } from "lucide-react";
import KagentLogo from "../kagent-logo";
+import ToolDisplay, { ToolCallStatus } from "@/components/ToolDisplay";
export type AgentCallStatus = "requested" | "executing" | "completed";
+// Constants
+const MAX_NESTING_DEPTH = 10;
+const NESTING_INDENT_REM = 1.5;
+
+interface NestedToolCall {
+ id: string;
+ call: FunctionCall;
+ result?: {
+ content: string;
+ is_error?: boolean;
+ };
+ status: ToolCallStatus;
+ nestedCalls?: NestedToolCall[];
+}
+
interface AgentCallDisplayProps {
call: FunctionCall;
result?: {
@@ -15,14 +31,31 @@ interface AgentCallDisplayProps {
};
status?: AgentCallStatus;
isError?: boolean;
+ nestedCalls?: NestedToolCall[]; // Support for nested agent/tool calls
+ depth?: number; // Track nesting depth for visual indentation
}
-const AgentCallDisplay = ({ call, result, status = "requested", isError = false }: AgentCallDisplayProps) => {
+const AgentCallDisplay = ({ call, result, status = "requested", isError = false, nestedCalls = [], depth = 0 }: AgentCallDisplayProps) => {
const [areInputsExpanded, setAreInputsExpanded] = useState(false);
const [areResultsExpanded, setAreResultsExpanded] = useState(false);
+ const [areNestedCallsExpanded, setAreNestedCallsExpanded] = useState(true); // Expanded by default for better visibility
const agentDisplay = useMemo(() => convertToUserFriendlyName(call.name), [call.name]);
const hasResult = result !== undefined;
+ const hasNestedCalls = nestedCalls && nestedCalls.length > 0;
+
+ // Protection against infinite recursion
+ if (depth > MAX_NESTING_DEPTH) {
+ console.warn(`Maximum nesting depth (${MAX_NESTING_DEPTH}) reached for agent call:`, call.name);
+ return (
+
+ ⚠️ Maximum nesting depth reached
+
+ );
+ }
+
+ // Calculate left margin based on nesting depth
+ const marginLeft = depth > 0 ? `${depth * NESTING_INDENT_REM}rem` : '0';
const getStatusDisplay = () => {
if (isError && status === "executing") {
@@ -69,59 +102,100 @@ const AgentCallDisplay = ({ call, result, status = "requested", isError = false
};
return (
-
-
-
-
-
- {agentDisplay}
-
- {call.id}
-
-
- {getStatusDisplay()}
-
-
-
-
-
- {areInputsExpanded && (
-
-
{JSON.stringify(call.args, null, 2)}
+
+
0 ? 'border-l-4 border-l-blue-400' : ''}`}>
+
+
+
+
+ {agentDisplay}
+ {depth > 0 && (nested level {depth})}
- )}
-
+
{call.id}
+
+
+ {getStatusDisplay()}
+
+
+
+
+
+ {areInputsExpanded && (
+
+
{JSON.stringify(call.args, null, 2)}
+
+ )}
+
-
- {status === "executing" && !hasResult && (
-
-
- {agentDisplay} is responding...
-
- )}
- {hasResult && result?.content && (
-
-
);
};
diff --git a/ui/src/components/chat/ToolCallDisplay.tsx b/ui/src/components/chat/ToolCallDisplay.tsx
index d4823e881..990cd565a 100644
--- a/ui/src/components/chat/ToolCallDisplay.tsx
+++ b/ui/src/components/chat/ToolCallDisplay.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useMemo } from "react";
import { Message, TextPart } from "@a2a-js/sdk";
import ToolDisplay, { ToolCallStatus } from "@/components/ToolDisplay";
import AgentCallDisplay from "@/components/chat/AgentCallDisplay";
@@ -19,6 +19,7 @@ interface ToolCallState {
is_error?: boolean;
};
status: ToolCallStatus;
+ nestedCalls?: ToolCallState[]; // Track nested agent calls
}
// Create a global cache to track tool calls across components
@@ -163,28 +164,34 @@ const ToolCallDisplay = ({ currentMessage, allMessages }: ToolCallDisplayProps)
};
}, [currentMessage]);
- useEffect(() => {
+ // Memoize the expensive nested call building operation
+ const processedToolCalls = useMemo(() => {
if (ownedCallIds.size === 0) {
- // If the component doesn't own any call IDs, ensure toolCalls is empty and return.
- if (toolCalls.size > 0) {
- setToolCalls(new Map());
- }
- return;
+ return new Map
();
}
- const newToolCalls = new Map();
+ try {
+ const newToolCalls = new Map();
+ const allToolCallsMap = new Map(); // Track ALL tool calls for nesting
- // First pass: collect all tool call requests that this component owns
+ // First pass: collect all tool call requests (both owned and nested)
for (const message of allMessages) {
if (isToolCallRequestMessage(message)) {
const requests = extractToolCallRequests(message);
for (const request of requests) {
- if (request.id && ownedCallIds.has(request.id)) {
- newToolCalls.set(request.id, {
+ if (request.id) {
+ const toolCallState: ToolCallState = {
id: request.id,
call: request,
- status: "requested"
- });
+ status: "requested",
+ nestedCalls: []
+ };
+
+ allToolCallsMap.set(request.id, toolCallState);
+
+ if (ownedCallIds.has(request.id)) {
+ newToolCalls.set(request.id, toolCallState);
+ }
}
}
}
@@ -195,8 +202,8 @@ const ToolCallDisplay = ({ currentMessage, allMessages }: ToolCallDisplayProps)
if (isToolCallExecutionMessage(message)) {
const results = extractToolCallResults(message);
for (const result of results) {
- if (result.call_id && newToolCalls.has(result.call_id)) {
- const existingCall = newToolCalls.get(result.call_id)!;
+ if (result.call_id && allToolCallsMap.has(result.call_id)) {
+ const existingCall = allToolCallsMap.get(result.call_id)!;
existingCall.result = {
content: result.content,
is_error: result.is_error
@@ -217,26 +224,94 @@ const ToolCallDisplay = ({ currentMessage, allMessages }: ToolCallDisplayProps)
}
if (summaryMessageEncountered) {
- newToolCalls.forEach((call, id) => {
- // Only update owned calls that are in 'executing' state and have a result
- if (call.status === "executing" && call.result && ownedCallIds.has(id)) {
+ allToolCallsMap.forEach((call) => {
+ // Only update calls that are in 'executing' state and have a result
+ if (call.status === "executing" && call.result) {
call.status = "completed";
}
});
} else {
// For stored tasks without summary messages, auto-complete tool calls that have results
- newToolCalls.forEach((call, id) => {
- if (call.status === "executing" && call.result && ownedCallIds.has(id)) {
+ allToolCallsMap.forEach((call) => {
+ if (call.status === "executing" && call.result) {
call.status = "completed";
}
});
}
-
+
+ // Fourth pass: Build nested call hierarchy
+ // Map to track which message created which call (callId -> message that created it)
+ const callIdToMessage = new Map();
+
+ for (const message of allMessages) {
+ if (isToolCallRequestMessage(message)) {
+ const requests = extractToolCallRequests(message);
+ for (const request of requests) {
+ if (request.id) {
+ callIdToMessage.set(request.id, message);
+ }
+ }
+ }
+ }
+
+ // Build parent-child relationships
+ // A call B is nested under call A if:
+ // - Both A and B are agent calls
+ // - B's message appeared after A's message but before A completed
+ // - B is not in ownedCallIds (not a top-level call)
+ allToolCallsMap.forEach((parentCall) => {
+ if (!isAgentToolName(parentCall.call.name)) return;
+
+ const nestedCallsList: ToolCallState[] = [];
+ const parentMessage = callIdToMessage.get(parentCall.id);
+ if (!parentMessage) return;
+
+ const parentIndex = allMessages.indexOf(parentMessage);
+
+ // Find where parent completed (if it did)
+ let parentCompletionIndex = allMessages.length;
+ for (let i = parentIndex + 1; i < allMessages.length; i++) {
+ if (isToolCallExecutionMessage(allMessages[i])) {
+ const results = extractToolCallResults(allMessages[i]);
+ if (results.some(r => r.call_id === parentCall.id)) {
+ parentCompletionIndex = i;
+ break;
+ }
+ }
+ }
+
+ // Look for child calls between parent start and completion
+ allToolCallsMap.forEach((potentialChild, childId) => {
+ // Skip if it's the parent itself or if it's a top-level owned call
+ if (childId === parentCall.id || ownedCallIds.has(childId)) return;
+
+ const childMessage = callIdToMessage.get(childId);
+ if (!childMessage) return;
+
+ const childIndex = allMessages.indexOf(childMessage);
+
+ // Child must appear after parent but before parent completes
+ if (childIndex > parentIndex && childIndex < parentCompletionIndex) {
+ nestedCallsList.push(potentialChild);
+ }
+ });
+
+ parentCall.nestedCalls = nestedCallsList;
+ });
+
+ return newToolCalls;
+ } catch (error) {
+ console.error("Error building nested call hierarchy:", error);
+ return new Map(); // Return empty map on error
+ }
+ }, [allMessages, ownedCallIds]);
+
+ // Update state when processed calls change
+ useEffect(() => {
// Only update state if there's a change, to prevent unnecessary re-renders.
- // This is a shallow comparison, but sufficient for this case.
- let changed = newToolCalls.size !== toolCalls.size;
+ let changed = processedToolCalls.size !== toolCalls.size;
if (!changed) {
- for (const [key, value] of newToolCalls) {
+ for (const [key, value] of processedToolCalls) {
const oldVal = toolCalls.get(key);
if (!oldVal || oldVal.status !== value.status || oldVal.result?.content !== value.result?.content) {
changed = true;
@@ -246,10 +321,9 @@ const ToolCallDisplay = ({ currentMessage, allMessages }: ToolCallDisplayProps)
}
if (changed) {
- setToolCalls(newToolCalls);
+ setToolCalls(processedToolCalls);
}
-
- }, [allMessages, ownedCallIds, toolCalls]);
+ }, [processedToolCalls, toolCalls]);
// If no tool calls to display for this message, return null
const currentDisplayableCalls = Array.from(toolCalls.values()).filter(call => ownedCallIds.has(call.id));
@@ -265,6 +339,7 @@ const ToolCallDisplay = ({ currentMessage, allMessages }: ToolCallDisplayProps)
result={toolCall.result}
status={toolCall.status}
isError={toolCall.result?.is_error}
+ nestedCalls={toolCall.nestedCalls}
/>
) : (
({
+ __esModule: true,
+ default: ({ call }: any) => Tool: {call.name}
,
+}));
+
+describe('AgentCallDisplay - Nested Rendering', () => {
+ const basicCall: FunctionCall = {
+ id: 'test-1',
+ name: 'kagent__NS__test-agent',
+ args: { query: 'test' },
+ };
+
+ test('renders agent call without nesting at depth 0', () => {
+ render();
+
+ expect(screen.getByText(/kagent\/test-agent/)).toBeInTheDocument();
+ expect(screen.queryByText(/nested level/)).not.toBeInTheDocument();
+ });
+
+ test('renders agent call with nested level indicator at depth 1', () => {
+ render();
+
+ expect(screen.getByText(/nested level 1/)).toBeInTheDocument();
+ });
+
+ test('renders agent call with nested level indicator at depth 2', () => {
+ render();
+
+ expect(screen.getByText(/nested level 2/)).toBeInTheDocument();
+ });
+
+ test('displays "Delegated Calls" section when nestedCalls provided', () => {
+ const nestedCalls = [
+ {
+ id: 'nested-1',
+ call: {
+ id: 'nested-1',
+ name: 'kagent__NS__sub-agent',
+ args: {},
+ },
+ status: 'completed' as const,
+ },
+ ];
+
+ render();
+
+ expect(screen.getByText(/Delegated Calls \(1\)/)).toBeInTheDocument();
+ });
+
+ test('displays correct count for multiple nested calls', () => {
+ const nestedCalls = [
+ {
+ id: 'nested-1',
+ call: {
+ id: 'nested-1',
+ name: 'kagent__NS__sub-agent-1',
+ args: {},
+ },
+ status: 'completed' as const,
+ },
+ {
+ id: 'nested-2',
+ call: {
+ id: 'nested-2',
+ name: 'kagent__NS__sub-agent-2',
+ args: {},
+ },
+ status: 'completed' as const,
+ },
+ {
+ id: 'nested-3',
+ call: {
+ id: 'nested-3',
+ name: 'read_file', // Tool call
+ args: {},
+ },
+ status: 'completed' as const,
+ },
+ ];
+
+ render();
+
+ expect(screen.getByText(/Delegated Calls \(3\)/)).toBeInTheDocument();
+ });
+
+ test('does not display "Delegated Calls" section when no nested calls', () => {
+ render();
+
+ expect(screen.queryByText(/Delegated Calls/)).not.toBeInTheDocument();
+ });
+
+ test('renders nested tool calls within delegated section', () => {
+ const nestedCalls = [
+ {
+ id: 'tool-1',
+ call: {
+ id: 'tool-1',
+ name: 'read_file',
+ args: { path: '/test' },
+ },
+ status: 'completed' as const,
+ },
+ ];
+
+ render();
+
+ // Should render ToolDisplay component for non-agent calls
+ expect(screen.getByTestId('tool-tool-1')).toBeInTheDocument();
+ });
+
+ test('displays different status indicators correctly', () => {
+ const { rerender } = render();
+ expect(screen.getByText(/Delegating/)).toBeInTheDocument();
+
+ rerender();
+ expect(screen.getByText(/Awaiting response/)).toBeInTheDocument();
+
+ rerender();
+ expect(screen.getByText(/Completed/)).toBeInTheDocument();
+ });
+
+ test('displays error status correctly', () => {
+ const result = {
+ content: 'Error occurred',
+ is_error: true,
+ };
+
+ render();
+
+ expect(screen.getByText(/Failed/)).toBeInTheDocument();
+ });
+
+ test('applies correct styling for nested depth', () => {
+ const { container } = render(
+
+ );
+
+ // Check for border styling on nested calls
+ const card = container.querySelector('.border-l-4');
+ expect(card).toBeInTheDocument();
+ });
+
+ test('recursive nesting - nested call can have its own nested calls', () => {
+ const deeplyNestedCalls = [
+ {
+ id: 'level2',
+ call: {
+ id: 'level2',
+ name: 'kagent__NS__level2-agent',
+ args: {},
+ },
+ status: 'completed' as const,
+ nestedCalls: [
+ {
+ id: 'level3',
+ call: {
+ id: 'level3',
+ name: 'kagent__NS__level3-agent',
+ args: {},
+ },
+ status: 'completed' as const,
+ },
+ ],
+ },
+ ];
+
+ render(
+
+ );
+
+ // Should have delegated calls sections (multiple due to recursion)
+ const delegatedSections = screen.getAllByText(/Delegated Calls \(1\)/);
+ expect(delegatedSections.length).toBeGreaterThan(0);
+ });
+
+ test('displays input/output sections', () => {
+ const callWithArgs: FunctionCall = {
+ id: 'test-1',
+ name: 'kagent__NS__test-agent',
+ args: { query: 'search term', limit: 10 },
+ };
+
+ const result = {
+ content: 'Search completed successfully',
+ is_error: false,
+ };
+
+ render();
+
+ // Input and Output sections should be present
+ expect(screen.getByText(/Input/)).toBeInTheDocument();
+ expect(screen.getByText(/Output/)).toBeInTheDocument();
+ });
+
+ test('enforces maximum nesting depth limit', () => {
+ const MAX_DEPTH = 10;
+
+ render();
+
+ // Should display warning instead of rendering normally
+ expect(screen.getByText(/Maximum nesting depth reached/)).toBeInTheDocument();
+ expect(screen.queryByText(/kagent\/test-agent/)).not.toBeInTheDocument();
+ });
+
+ test('renders normally at maximum allowed depth', () => {
+ const MAX_DEPTH = 10;
+
+ render();
+
+ // Should render normally at exactly max depth
+ expect(screen.getByText(/kagent\/test-agent/)).toBeInTheDocument();
+ expect(screen.queryByText(/Maximum nesting depth reached/)).not.toBeInTheDocument();
+ });
+});
diff --git a/ui/src/components/chat/__tests__/ToolCallDisplay.test.tsx b/ui/src/components/chat/__tests__/ToolCallDisplay.test.tsx
new file mode 100644
index 000000000..2cfe33b9b
--- /dev/null
+++ b/ui/src/components/chat/__tests__/ToolCallDisplay.test.tsx
@@ -0,0 +1,330 @@
+import { describe, test, expect } from '@jest/globals';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { Message } from '@a2a-js/sdk';
+import ToolCallDisplay from '../ToolCallDisplay';
+
+// Mock the child components
+jest.mock('../AgentCallDisplay', () => ({
+ __esModule: true,
+ default: ({ call, nestedCalls, depth }: any) => (
+
+ Agent: {call.name}
+ {nestedCalls && nestedCalls.length > 0 && (
+
+ Nested: {nestedCalls.length}
+
+ )}
+
+ ),
+}));
+
+jest.mock('@/components/ToolDisplay', () => ({
+ __esModule: true,
+ default: ({ call }: any) => Tool: {call.name}
,
+}));
+
+describe('ToolCallDisplay - Nested Agent Calls', () => {
+ test('displays simple agent call without nesting', () => {
+ const currentMessage: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'call-1',
+ name: 'kagent__NS__test-agent',
+ args: { query: 'test' },
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const allMessages = [currentMessage];
+
+ render();
+
+ expect(screen.getByTestId('agent-call-call-1')).toBeInTheDocument();
+ expect(screen.getByText(/Agent: kagent__NS__test-agent/)).toBeInTheDocument();
+ });
+
+ test('builds nested call hierarchy for agent->subagent calls', () => {
+ const parentCall: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'parent-1',
+ name: 'kagent__NS__main-agent',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const nestedCall: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'nested-1',
+ name: 'kagent__NS__sub-agent',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const parentResult: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'parent-1',
+ name: 'kagent__NS__main-agent',
+ response: { result: 'done' },
+ },
+ metadata: {
+ kagent_type: 'function_response',
+ },
+ },
+ ],
+ };
+
+ const allMessages = [parentCall, nestedCall, parentResult];
+
+ render();
+
+ // Parent call should be displayed
+ expect(screen.getByTestId('agent-call-parent-1')).toBeInTheDocument();
+
+ // Should have nested calls indicator
+ expect(screen.getByTestId('nested-calls-parent-1')).toBeInTheDocument();
+ expect(screen.getByText(/Nested: 1/)).toBeInTheDocument();
+ });
+
+ test('handles multi-level nesting (agent->subagent->subagent)', () => {
+ const level1Call: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'level1',
+ name: 'kagent__NS__main',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const level2Call: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'level2',
+ name: 'kagent__NS__research',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const level3Call: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'level3',
+ name: 'kagent__NS__data',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const level1Result: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'level1',
+ name: 'kagent__NS__main',
+ response: { result: 'complete' },
+ },
+ metadata: {
+ kagent_type: 'function_response',
+ },
+ },
+ ],
+ };
+
+ const allMessages = [level1Call, level2Call, level3Call, level1Result];
+
+ render();
+
+ // Level 1 should be displayed with nested calls
+ expect(screen.getByTestId('agent-call-level1')).toBeInTheDocument();
+ expect(screen.getByTestId('nested-calls-level1')).toBeInTheDocument();
+ });
+
+ test('handles regular tool calls within agent calls', () => {
+ const agentCall: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'agent-1',
+ name: 'kagent__NS__agent',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const toolCall: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'tool-1',
+ name: 'read_file', // No __NS__ = regular tool
+ args: { path: '/test' },
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const agentResult: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'agent-1',
+ name: 'kagent__NS__agent',
+ response: { result: 'done' },
+ },
+ metadata: {
+ kagent_type: 'function_response',
+ },
+ },
+ ],
+ };
+
+ const allMessages = [agentCall, toolCall, agentResult];
+
+ render();
+
+ // Should display agent call with nested tool
+ expect(screen.getByTestId('agent-call-agent-1')).toBeInTheDocument();
+ });
+
+ test('does not nest calls that appear after parent completion', () => {
+ const parentCall: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'parent',
+ name: 'kagent__NS__parent',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const parentResult: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'parent',
+ name: 'kagent__NS__parent',
+ response: { result: 'done' },
+ },
+ metadata: {
+ kagent_type: 'function_response',
+ },
+ },
+ ],
+ };
+
+ const afterCall: Message = {
+ kind: 'message',
+ role: 'assistant',
+ parts: [
+ {
+ kind: 'data',
+ data: {
+ id: 'after',
+ name: 'kagent__NS__after',
+ args: {},
+ },
+ metadata: {
+ kagent_type: 'function_call',
+ },
+ },
+ ],
+ };
+
+ const allMessages = [parentCall, parentResult, afterCall];
+
+ render();
+
+ // Parent should not have nested calls (call came after completion)
+ expect(screen.getByTestId('agent-call-parent')).toBeInTheDocument();
+ expect(screen.queryByTestId('nested-calls-parent')).not.toBeInTheDocument();
+ });
+});