test(cli): refactor tests for async render utilities (#23252)

This commit is contained in:
Tommaso Sciortino
2026-03-20 20:08:29 +00:00
committed by GitHub
parent 86a3a913b5
commit 6c78eb7a39
198 changed files with 3592 additions and 4802 deletions
@@ -29,10 +29,9 @@ describe('<CompressionMessage />', () => {
describe('pending state', () => {
it('renders pending message when compression is in progress', async () => {
const props = createCompressionProps({ isPending: true });
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Compressing chat history');
@@ -48,10 +47,9 @@ describe('<CompressionMessage />', () => {
newTokenCount: 50,
compressionStatus: CompressionStatus.COMPRESSED,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('✦');
@@ -73,9 +71,9 @@ describe('<CompressionMessage />', () => {
newTokenCount: newTokens,
compressionStatus: CompressionStatus.COMPRESSED,
});
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(<CompressionMessage {...props} />);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
const output = lastFrame();
expect(output).toContain('✦');
@@ -98,10 +96,9 @@ describe('<CompressionMessage />', () => {
compressionStatus:
CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('✦');
@@ -119,10 +116,9 @@ describe('<CompressionMessage />', () => {
compressionStatus:
CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain(
@@ -158,9 +154,9 @@ describe('<CompressionMessage />', () => {
newTokenCount: newTokens,
compressionStatus: CompressionStatus.COMPRESSED,
});
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(<CompressionMessage {...props} />);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
const output = lastFrame();
expect(output).toContain(expected);
@@ -182,9 +178,9 @@ describe('<CompressionMessage />', () => {
compressionStatus:
CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
});
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(<CompressionMessage {...props} />);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
const output = lastFrame();
expect(output).toContain(
@@ -209,9 +205,9 @@ describe('<CompressionMessage />', () => {
compressionStatus:
CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
});
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(<CompressionMessage {...props} />);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
const output = lastFrame();
expect(output).toContain('compression did not reduce size');
@@ -228,10 +224,9 @@ describe('<CompressionMessage />', () => {
isPending: false,
compressionStatus: CompressionStatus.COMPRESSION_FAILED_EMPTY_SUMMARY,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('✦');
@@ -247,10 +242,9 @@ describe('<CompressionMessage />', () => {
compressionStatus:
CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<CompressionMessage {...props} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain(
@@ -10,10 +10,9 @@ import { describe, it, expect } from 'vitest';
describe('ErrorMessage', () => {
it('renders with the correct prefix and text', async () => {
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<ErrorMessage text="Something went wrong" />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -22,10 +21,9 @@ describe('ErrorMessage', () => {
it('renders multiline error messages', async () => {
const message = 'Error line 1\nError line 2';
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<ErrorMessage text={message} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -24,13 +24,12 @@ describe('<GeminiMessage /> - Raw Markdown Display Snapshots', () => {
])(
'renders with renderMarkdown=$renderMarkdown $description',
async ({ renderMarkdown }) => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<GeminiMessage {...baseProps} />,
{
uiState: { renderMarkdown, streamingState: StreamingState.Idle },
},
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
},
@@ -39,13 +38,12 @@ describe('<GeminiMessage /> - Raw Markdown Display Snapshots', () => {
it.each([{ renderMarkdown: true }, { renderMarkdown: false }])(
'renders pending state with renderMarkdown=$renderMarkdown',
async ({ renderMarkdown }) => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<GeminiMessage {...baseProps} isPending={true} />,
{
uiState: { renderMarkdown, streamingState: StreamingState.Idle },
},
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
},
@@ -55,7 +53,7 @@ describe('<GeminiMessage /> - Raw Markdown Display Snapshots', () => {
const terminalWidth = 20;
const text =
'This is a long line that should wrap correctly without truncation';
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<GeminiMessage
text={text}
isPending={false}
@@ -65,7 +63,6 @@ describe('<GeminiMessage /> - Raw Markdown Display Snapshots', () => {
uiState: { renderMarkdown: false, streamingState: StreamingState.Idle },
},
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -10,10 +10,9 @@ import { describe, it, expect } from 'vitest';
describe('InfoMessage', () => {
it('renders with the correct default prefix and text', async () => {
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<InfoMessage text="Just so you know" />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -21,10 +20,9 @@ describe('InfoMessage', () => {
});
it('renders with a custom icon', async () => {
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<InfoMessage text="Custom icon test" icon="★" />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -33,10 +31,7 @@ describe('InfoMessage', () => {
it('renders multiline info messages', async () => {
const message = 'Info line 1\nInfo line 2';
const { lastFrame, waitUntilReady, unmount } = render(
<InfoMessage text={message} />,
);
await waitUntilReady();
const { lastFrame, unmount } = await render(<InfoMessage text={message} />);
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -33,7 +33,7 @@ describe('ToolConfirmationMessage Redirection', () => {
rootCommands: ['echo'],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -43,7 +43,6 @@ describe('ToolConfirmationMessage Redirection', () => {
terminalWidth={100}
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -170,11 +170,10 @@ describe('<ShellToolMessage />', () => {
},
],
])('%s', async (_, props, options) => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ShellToolMessage {...baseProps} {...props} />,
{ uiActions, ...options },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -219,31 +218,29 @@ describe('<ShellToolMessage />', () => {
focused,
constrainHeight,
) => {
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(
<ShellToolMessage
{...baseProps}
resultDisplay={LONG_OUTPUT}
renderOutputAsMarkdown={false}
availableTerminalHeight={availableTerminalHeight}
ptyId={1}
status={CoreToolCallStatus.Executing}
/>,
{
uiActions,
config: makeFakeConfig({ useAlternateBuffer: true }),
settings: createMockSettings({
ui: { useAlternateBuffer: true },
}),
uiState: {
activePtyId: focused ? 1 : 2,
embeddedShellFocused: focused,
constrainHeight,
},
const { lastFrame, unmount } = await renderWithProviders(
<ShellToolMessage
{...baseProps}
resultDisplay={LONG_OUTPUT}
renderOutputAsMarkdown={false}
availableTerminalHeight={availableTerminalHeight}
ptyId={1}
status={CoreToolCallStatus.Executing}
/>,
{
uiActions,
config: makeFakeConfig({ useAlternateBuffer: true }),
settings: createMockSettings({
ui: { useAlternateBuffer: true },
}),
uiState: {
activePtyId: focused ? 1 : 2,
embeddedShellFocused: focused,
constrainHeight,
},
);
},
);
await waitUntilReady();
const frame = lastFrame();
expect(frame.match(/Line \d+/g)?.length).toBe(expectedMaxLines);
expect(frame).toMatchSnapshot();
@@ -276,7 +273,7 @@ describe('<ShellToolMessage />', () => {
});
it('fully expands in alternate buffer mode when constrainHeight is false and isExpandable is true', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ShellToolMessage
{...baseProps}
resultDisplay={LONG_OUTPUT}
@@ -295,7 +292,6 @@ describe('<ShellToolMessage />', () => {
},
);
await waitUntilReady();
await waitFor(() => {
const frame = lastFrame();
// Should show all 100 lines because constrainHeight is false and isExpandable is true
@@ -306,7 +302,7 @@ describe('<ShellToolMessage />', () => {
});
it('stays constrained in alternate buffer mode when isExpandable is false even if constrainHeight is false', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ShellToolMessage
{...baseProps}
resultDisplay={LONG_OUTPUT}
@@ -325,7 +321,6 @@ describe('<ShellToolMessage />', () => {
},
);
await waitUntilReady();
await waitFor(() => {
const frame = lastFrame();
// Should still be constrained to 12 (15 - 3) because isExpandable is false
@@ -83,11 +83,7 @@ describe('<SubagentGroupDisplay />', () => {
});
it('renders collapsed view by default with correct agent counts and states', async () => {
const { lastFrame, waitUntilReady } = await renderSubagentGroup(
mockToolCalls,
40,
);
await waitUntilReady();
const { lastFrame } = await renderSubagentGroup(mockToolCalls, 40);
expect(lastFrame()).toMatchSnapshot();
});
@@ -35,10 +35,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -59,10 +58,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -81,10 +79,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -103,10 +100,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -127,10 +123,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -148,10 +143,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -163,10 +157,9 @@ describe('<SubagentProgressDisplay />', () => {
state: 'cancelled',
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -184,10 +177,9 @@ describe('<SubagentProgressDisplay />', () => {
],
};
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<SubagentProgressDisplay progress={progress} terminalWidth={80} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
});
@@ -32,12 +32,11 @@ describe.each([true, false])(
'<TodoTray /> (showFullTodos: %s)',
async (showFullTodos: boolean) => {
const renderWithUiState = async (uiState: Partial<UIState>) => {
const result = render(
const result = await render(
<UIStateContext.Provider value={uiState as UIState}>
<TodoTray />
</UIStateContext.Provider>,
);
await result.waitUntilReady();
return result;
};
@@ -91,7 +90,7 @@ describe.each([true, false])(
});
it('renders a todo list with long descriptions that wrap when full view is on', async () => {
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<Box width="50">
<UIStateContext.Provider
value={
@@ -118,7 +117,6 @@ describe.each([true, false])(
</UIStateContext.Provider>
</Box>,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -50,7 +50,7 @@ describe('ToolConfirmationMessage', () => {
urls: ['https://example.com'],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -60,7 +60,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
@@ -77,7 +76,7 @@ describe('ToolConfirmationMessage', () => {
],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -87,7 +86,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
@@ -101,7 +99,7 @@ describe('ToolConfirmationMessage', () => {
urls: ['https://täst.com'],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -112,8 +110,6 @@ describe('ToolConfirmationMessage', () => {
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Deceptive URL(s) detected');
expect(output).toContain('Original: https://täst.com');
@@ -132,7 +128,7 @@ describe('ToolConfirmationMessage', () => {
rootCommands: ['curl'],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -143,8 +139,6 @@ describe('ToolConfirmationMessage', () => {
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Deceptive URL(s) detected');
expect(output).toContain('Original: https://еxample.com/');
@@ -163,7 +157,7 @@ describe('ToolConfirmationMessage', () => {
rootCommands: ['curl'],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -174,8 +168,6 @@ describe('ToolConfirmationMessage', () => {
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Deceptive URL(s) detected');
// It should extract "https://еxample.com" and NOT "https://еxample.com;ls"
@@ -193,7 +185,7 @@ describe('ToolConfirmationMessage', () => {
urls: ['https://еxample.com', 'https://täst.com'],
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -204,8 +196,6 @@ describe('ToolConfirmationMessage', () => {
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Deceptive URL(s) detected');
expect(output).toContain('Original: https://еxample.com/');
@@ -223,7 +213,7 @@ describe('ToolConfirmationMessage', () => {
commands: ['echo "hello"', 'ls -la', 'whoami'], // Multi-command list
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -233,7 +223,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('echo "hello"');
@@ -336,18 +325,16 @@ describe('ToolConfirmationMessage', () => {
getIdeMode: () => false,
getDisableAlwaysAllow: () => false,
} as unknown as Config;
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={details}
config={mockConfig}
getPreferredEditor={vi.fn()}
availableTerminalHeight={30}
terminalWidth={80}
/>,
);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={details}
config={mockConfig}
getPreferredEditor={vi.fn()}
availableTerminalHeight={30}
terminalWidth={80}
/>,
);
expect(lastFrame()).toMatchSnapshot();
unmount();
@@ -360,18 +347,16 @@ describe('ToolConfirmationMessage', () => {
getDisableAlwaysAllow: () => false,
} as unknown as Config;
const { lastFrame, waitUntilReady, unmount } =
await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={details}
config={mockConfig}
getPreferredEditor={vi.fn()}
availableTerminalHeight={30}
terminalWidth={80}
/>,
);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={details}
config={mockConfig}
getPreferredEditor={vi.fn()}
availableTerminalHeight={30}
terminalWidth={80}
/>,
);
expect(lastFrame()).toMatchSnapshot();
unmount();
@@ -396,7 +381,7 @@ describe('ToolConfirmationMessage', () => {
getIdeMode: () => false,
getDisableAlwaysAllow: () => false,
} as unknown as Config;
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={editConfirmationDetails}
@@ -411,7 +396,6 @@ describe('ToolConfirmationMessage', () => {
}),
},
);
await waitUntilReady();
expect(lastFrame()).not.toContain('Allow for all future sessions');
unmount();
@@ -423,7 +407,7 @@ describe('ToolConfirmationMessage', () => {
getIdeMode: () => false,
getDisableAlwaysAllow: () => false,
} as unknown as Config;
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={editConfirmationDetails}
@@ -438,7 +422,6 @@ describe('ToolConfirmationMessage', () => {
}),
},
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('future sessions');
@@ -471,7 +454,7 @@ describe('ToolConfirmationMessage', () => {
isDiffingEnabled: false,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={editConfirmationDetails}
@@ -481,7 +464,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
expect(lastFrame()).toContain('Modify with external editor');
unmount();
@@ -499,7 +481,7 @@ describe('ToolConfirmationMessage', () => {
isDiffingEnabled: false,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={editConfirmationDetails}
@@ -509,7 +491,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
expect(lastFrame()).toContain('Modify with external editor');
unmount();
@@ -527,7 +508,7 @@ describe('ToolConfirmationMessage', () => {
isDiffingEnabled: true,
});
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={editConfirmationDetails}
@@ -537,7 +518,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
expect(lastFrame()).not.toContain('Modify with external editor');
unmount();
@@ -554,7 +534,7 @@ describe('ToolConfirmationMessage', () => {
onConfirm: vi.fn(),
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -564,7 +544,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
const output = lastFrame();
// BiDi characters \u202E and \u202D should be stripped
@@ -600,7 +579,7 @@ describe('ToolConfirmationMessage', () => {
onConfirm: vi.fn(),
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -610,7 +589,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('MCP Tool Details:');
@@ -632,7 +610,7 @@ describe('ToolConfirmationMessage', () => {
onConfirm: vi.fn(),
};
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -642,7 +620,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('MCP Tool Details:');
@@ -677,7 +654,7 @@ describe('ToolConfirmationMessage', () => {
urls: ['https://example.com'],
};
const { stdin, waitUntilReady, unmount } = await renderWithProviders(
const { stdin, unmount } = await renderWithProviders(
<ToolConfirmationMessage
callId="test-call-id"
confirmationDetails={confirmationDetails}
@@ -687,7 +664,6 @@ describe('ToolConfirmationMessage', () => {
terminalWidth={80}
/>,
);
await waitUntilReady();
stdin.write('\x1b');
@@ -75,7 +75,7 @@ describe('<ToolGroupMessage />', () => {
it('renders single successful tool call', async () => {
const toolCalls = [createToolCall()];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -90,7 +90,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -109,13 +108,12 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
// Should now hide confirming tools (to avoid duplication with Global Queue)
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toBe('');
unmount();
});
@@ -130,12 +128,11 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot('canceled_tool');
unmount();
@@ -164,7 +161,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -180,7 +177,6 @@ describe('<ToolGroupMessage />', () => {
},
);
// pending-tool should now be visible
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('successful-tool');
expect(output).toContain('pending-tool');
@@ -205,7 +201,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -219,7 +215,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('successful-tool');
expect(output).not.toContain('error-tool');
@@ -238,7 +233,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -253,7 +248,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('client-error-tool');
unmount();
@@ -282,7 +276,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -298,7 +292,6 @@ describe('<ToolGroupMessage />', () => {
},
);
// write_file (Pending) should now be visible
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('read_file');
expect(output).toContain('run_shell_command');
@@ -324,7 +317,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -344,7 +337,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -358,7 +350,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -378,7 +370,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -386,7 +377,7 @@ describe('<ToolGroupMessage />', () => {
it('renders empty tool calls array', async () => {
const toolCalls: IndividualToolCallDisplay[] = [];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -401,7 +392,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -423,7 +413,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<Scrollable height={10} hasFocus={true} scrollToBottom={true}>
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />
</Scrollable>,
@@ -440,7 +430,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -456,7 +445,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -471,7 +460,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -496,7 +484,7 @@ describe('<ToolGroupMessage />', () => {
];
const item2 = createItem(toolCalls2);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<Scrollable height={6} hasFocus={true} scrollToBottom={true}>
<ToolGroupMessage
{...baseProps}
@@ -526,7 +514,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -541,7 +528,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -556,7 +543,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -571,7 +557,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{
config: baseMockConfig,
@@ -586,7 +572,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -609,7 +594,7 @@ describe('<ToolGroupMessage />', () => {
}),
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -629,7 +614,6 @@ describe('<ToolGroupMessage />', () => {
},
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -676,17 +660,10 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } =
await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
toolCalls={toolCalls}
/>,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
if (shouldHide) {
expect(lastFrame({ allowEmpty: true })).toBe('');
} else {
@@ -711,12 +688,11 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toMatchSnapshot();
unmount();
});
@@ -734,7 +710,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -744,7 +720,6 @@ describe('<ToolGroupMessage />', () => {
{ config: baseMockConfig, settings: fullVerbositySettings },
);
// AskUser tools in progress are rendered by AskUserDialog, so we expect nothing.
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toBe('');
unmount();
});
@@ -761,7 +736,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -775,7 +750,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toBe('');
unmount();
});
@@ -784,7 +758,7 @@ describe('<ToolGroupMessage />', () => {
const toolCalls: IndividualToolCallDisplay[] = [];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -798,7 +772,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).not.toBe('');
unmount();
});
@@ -815,7 +788,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -829,7 +802,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toBe('');
unmount();
});
@@ -848,7 +820,7 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -862,7 +834,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).toBe('');
unmount();
});
@@ -943,7 +914,7 @@ describe('<ToolGroupMessage />', () => {
const toolCalls = [visibleTool, ...hiddenTools];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
@@ -957,7 +928,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('visible-tool');
expect(output).not.toContain('hidden-error-0');
@@ -969,7 +939,7 @@ describe('<ToolGroupMessage />', () => {
const toolCalls: IndividualToolCallDisplay[] = [];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage
item={item}
toolCalls={toolCalls}
@@ -983,7 +953,6 @@ describe('<ToolGroupMessage />', () => {
},
);
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })).not.toBe('');
unmount();
});
@@ -1016,17 +985,10 @@ describe('<ToolGroupMessage />', () => {
];
const item = createItem(toolCalls);
const { lastFrame, unmount, waitUntilReady } =
await renderWithProviders(
<ToolGroupMessage
{...baseProps}
item={item}
toolCalls={toolCalls}
/>,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
await waitUntilReady();
const { lastFrame, unmount } = await renderWithProviders(
<ToolGroupMessage {...baseProps} item={item} toolCalls={toolCalls} />,
{ config: baseMockConfig, settings: fullVerbositySettings },
);
if (visible) {
expect(lastFrame()).toContain(name);
@@ -78,11 +78,10 @@ describe('<ToolMessage />', () => {
});
it('renders basic tool information', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} />,
StreamingState.Idle,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
unmount();
@@ -91,7 +90,7 @@ describe('<ToolMessage />', () => {
describe('JSON rendering', () => {
it('pretty prints valid JSON', async () => {
const testJSONstring = '{"a": 1, "b": [2, 3]}';
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
resultDisplay={testJSONstring}
@@ -99,7 +98,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Idle,
);
await waitUntilReady();
const output = lastFrame();
@@ -113,11 +111,10 @@ describe('<ToolMessage />', () => {
});
it('renders pretty JSON in ink frame', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} resultDisplay='{"a":1,"b":2}' />,
StreamingState.Idle,
);
await waitUntilReady();
const frame = lastFrame();
@@ -127,7 +124,7 @@ describe('<ToolMessage />', () => {
it('uses JSON renderer even when renderOutputAsMarkdown=true is true', async () => {
const testJSONstring = '{"a": 1, "b": [2, 3]}';
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
resultDisplay={testJSONstring}
@@ -135,7 +132,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Idle,
);
await waitUntilReady();
const output = lastFrame();
@@ -149,7 +145,7 @@ describe('<ToolMessage />', () => {
});
it('falls back to plain text for malformed JSON', async () => {
const testJSONstring = 'a": 1, "b": [2, 3]}';
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
resultDisplay={testJSONstring}
@@ -157,7 +153,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Idle,
);
await waitUntilReady();
const output = lastFrame();
@@ -168,7 +163,7 @@ describe('<ToolMessage />', () => {
it('rejects mixed text + JSON renders as plain text', async () => {
const testJSONstring = `{"result": "count": 42,"items": ["apple", "banana"]},"meta": {"timestamp": "2025-09-28T12:34:56Z"}}End.`;
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
resultDisplay={testJSONstring}
@@ -176,7 +171,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Idle,
);
await waitUntilReady();
const output = lastFrame();
@@ -188,7 +182,7 @@ describe('<ToolMessage />', () => {
it('rejects ANSI-tained JSON renders as plain text', async () => {
const testJSONstring =
'\u001b[32mOK\u001b[0m {"status": "success", "data": {"id": 123, "values": [10, 20, 30]}}';
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
resultDisplay={testJSONstring}
@@ -196,7 +190,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Idle,
);
await waitUntilReady();
const output = lastFrame();
@@ -207,7 +200,7 @@ describe('<ToolMessage />', () => {
it('pretty printing 10kb JSON completes in <50ms', async () => {
const large = '{"key": "' + 'x'.repeat(10000) + '"}';
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
resultDisplay={large}
@@ -215,7 +208,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Idle,
);
await waitUntilReady();
const start = performance.now();
lastFrame();
@@ -226,84 +218,76 @@ describe('<ToolMessage />', () => {
describe('ToolStatusIndicator rendering', () => {
it('shows ✓ for Success status', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Success} />,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows o for Pending status', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Scheduled} />,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows ? for Confirming status', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
status={CoreToolCallStatus.AwaitingApproval}
/>,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows - for Canceled status', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Cancelled} />,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows x for Error status', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Error} />,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows paused spinner for Executing status when streamingState is Idle', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Executing} />,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows paused spinner for Executing status when streamingState is WaitingForConfirmation', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Executing} />,
StreamingState.WaitingForConfirmation,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows MockRespondingSpinner for Executing status when streamingState is Responding', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} status={CoreToolCallStatus.Executing} />,
StreamingState.Responding, // Simulate app still responding
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -317,11 +301,10 @@ describe('<ToolMessage />', () => {
newContent: 'new',
filePath: 'file.txt',
};
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} resultDisplay={diffResult} />,
StreamingState.Idle,
);
await waitUntilReady();
// Check that the output contains the MockDiff content as part of the whole message
expect(lastFrame()).toMatchSnapshot();
unmount();
@@ -372,17 +355,16 @@ describe('<ToolMessage />', () => {
},
],
];
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage {...baseProps} resultDisplay={ansiResult} />,
StreamingState.Idle,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('renders McpProgressIndicator with percentage and message for executing tools', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
status={CoreToolCallStatus.Executing}
@@ -392,7 +374,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Responding,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('42%');
expect(output).toContain('Working on it...');
@@ -404,7 +385,7 @@ describe('<ToolMessage />', () => {
});
it('renders only percentage when progressMessage is missing', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
status={CoreToolCallStatus.Executing}
@@ -413,7 +394,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Responding,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('75%');
expect(output).toContain('\u2588');
@@ -424,7 +404,7 @@ describe('<ToolMessage />', () => {
});
it('renders indeterminate progress when total is missing', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithContext(
const { lastFrame, unmount } = await renderWithContext(
<ToolMessage
{...baseProps}
status={CoreToolCallStatus.Executing}
@@ -432,7 +412,6 @@ describe('<ToolMessage />', () => {
/>,
StreamingState.Responding,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('7');
expect(output).toContain('\u2588');
@@ -449,7 +428,7 @@ describe('<ToolMessage />', () => {
(_, i) => `Line ${i + 1}`,
).join('\n');
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolMessage
{...baseProps}
kind={Kind.Agent}
@@ -468,7 +447,6 @@ describe('<ToolMessage />', () => {
settings: createMockSettings({ ui: { useAlternateBuffer: false } }),
},
);
await waitUntilReady();
const output = lastFrame();
// Since kind=Kind.Agent and availableTerminalHeight is provided, it should truncate to SUBAGENT_MAX_LINES (15)
@@ -486,7 +464,7 @@ describe('<ToolMessage />', () => {
(_, i) => `Line ${i + 1}`,
).join('\n');
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolMessage
{...baseProps}
kind={Kind.Agent}
@@ -502,7 +480,6 @@ describe('<ToolMessage />', () => {
settings: createMockSettings({ ui: { useAlternateBuffer: false } }),
},
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Line 1');
@@ -516,7 +493,7 @@ describe('<ToolMessage />', () => {
(_, i) => `Line ${i + 1}`,
).join('\n');
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<ToolMessage
{...baseProps}
kind={Kind.Read}
@@ -531,7 +508,6 @@ describe('<ToolMessage />', () => {
settings: createMockSettings({ ui: { useAlternateBuffer: false } }),
},
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Line 1');
@@ -70,7 +70,6 @@ describe('Focus Hint', () => {
<Component {...baseProps} resultDisplay={undefined} />,
{ uiState: { streamingState: StreamingState.Idle } },
);
await waitUntilReady();
// Initially, no focus hint
expect(lastFrame()).toMatchSnapshot('initial-no-output');
@@ -92,7 +91,6 @@ describe('Focus Hint', () => {
<Component {...baseProps} resultDisplay="Some output" />,
{ uiState: { streamingState: StreamingState.Idle } },
);
await waitUntilReady();
// Initially, no focus hint
expect(lastFrame()).toMatchSnapshot('initial-with-output');
@@ -119,7 +117,6 @@ describe('Focus Hint', () => {
/>,
{ uiState: { streamingState: StreamingState.Idle } },
);
await waitUntilReady();
await act(async () => {
vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100);
@@ -64,7 +64,7 @@ describe('<ToolMessage /> - Raw Markdown Display Snapshots', () => {
])(
'renders with renderMarkdown=$renderMarkdown, useAlternateBuffer=$useAlternateBuffer $description',
async ({ renderMarkdown, useAlternateBuffer, availableTerminalHeight }) => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<StreamingContext.Provider value={StreamingState.Idle}>
<ToolMessage
{...baseProps}
@@ -77,7 +77,6 @@ describe('<ToolMessage /> - Raw Markdown Display Snapshots', () => {
settings: createMockSettings({ ui: { useAlternateBuffer } }),
},
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
unmount();
},
@@ -15,30 +15,27 @@ vi.mock('../GeminiRespondingSpinner.js', () => ({
describe('McpProgressIndicator', () => {
it('renders determinate progress at 50%', async () => {
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<McpProgressIndicator progress={50} total={100} barWidth={20} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
expect(output).toContain('50%');
});
it('renders complete progress at 100%', async () => {
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<McpProgressIndicator progress={100} total={100} barWidth={20} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
expect(output).toContain('100%');
});
it('renders indeterminate progress with raw count', async () => {
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<McpProgressIndicator progress={7} barWidth={20} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
expect(output).toContain('7');
@@ -46,7 +43,7 @@ describe('McpProgressIndicator', () => {
});
it('renders progress with a message', async () => {
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<McpProgressIndicator
progress={30}
total={100}
@@ -54,17 +51,15 @@ describe('McpProgressIndicator', () => {
barWidth={20}
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
expect(output).toContain('Downloading...');
});
it('clamps progress exceeding total to 100%', async () => {
const { lastFrame, waitUntilReady } = render(
const { lastFrame } = await render(
<McpProgressIndicator progress={150} total={100} barWidth={20} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('100%');
expect(output).not.toContain('150%');
@@ -15,11 +15,10 @@ vi.mock('../../utils/commandUtils.js', () => ({
describe('UserMessage', () => {
it('renders normal user message with correct prefix', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<UserMessage text="Hello Gemini" width={80} />,
{ width: 80 },
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -27,11 +26,10 @@ describe('UserMessage', () => {
});
it('renders slash command message', async () => {
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<UserMessage text="/help" width={80} />,
{ width: 80 },
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -40,11 +38,10 @@ describe('UserMessage', () => {
it('renders multiline user message', async () => {
const message = 'Line 1\nLine 2';
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<UserMessage text={message} width={80} />,
{ width: 80 },
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -53,11 +50,10 @@ describe('UserMessage', () => {
it('transforms image paths in user message', async () => {
const message = 'Check out this image: @/path/to/my-image.png';
const { lastFrame, waitUntilReady, unmount } = await renderWithProviders(
const { lastFrame, unmount } = await renderWithProviders(
<UserMessage text={message} width={80} />,
{ width: 80 },
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('[Image my-image.png]');
@@ -10,10 +10,9 @@ import { describe, it, expect } from 'vitest';
describe('WarningMessage', () => {
it('renders with the correct prefix and text', async () => {
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<WarningMessage text="Watch out!" />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();
@@ -22,10 +21,9 @@ describe('WarningMessage', () => {
it('renders multiline warning messages', async () => {
const message = 'Warning line 1\nWarning line 2';
const { lastFrame, waitUntilReady, unmount } = render(
const { lastFrame, unmount } = await render(
<WarningMessage text={message} />,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toMatchSnapshot();