Migrate core render util to use xterm.js as part of the rendering loop. (#19044)

This commit is contained in:
Jacob Richman
2026-02-18 16:46:50 -08:00
committed by GitHub
parent 04c52513e7
commit 04f65f3d55
213 changed files with 7065 additions and 3852 deletions

View File

@@ -33,7 +33,7 @@ vi.mock('../contexts/SettingsContext.js', async (importOriginal) => {
const useSessionStatsMock = vi.mocked(SessionContext.useSessionStats);
const useSettingsMock = vi.mocked(SettingsContext.useSettings);
const renderWithMockedStats = (
const renderWithMockedStats = async (
metrics: SessionMetrics,
width?: number,
currentModel: string = 'gemini-2.5-pro',
@@ -59,7 +59,12 @@ const renderWithMockedStats = (
},
} as unknown as LoadedSettings);
return render(<ModelStatsDisplay currentModel={currentModel} />, width);
const result = render(
<ModelStatsDisplay currentModel={currentModel} />,
width,
);
await result.waitUntilReady();
return result;
};
describe('<ModelStatsDisplay />', () => {
@@ -76,8 +81,8 @@ describe('<ModelStatsDisplay />', () => {
vi.restoreAllMocks();
});
it('should render "no API calls" message when there are no active models', () => {
const { lastFrame } = renderWithMockedStats({
it('should render "no API calls" message when there are no active models', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {},
tools: {
totalCalls: 0,
@@ -102,10 +107,11 @@ describe('<ModelStatsDisplay />', () => {
'No API calls have been made in this session.',
);
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('should not display conditional rows if no model has data for them', () => {
const { lastFrame } = renderWithMockedStats({
it('should not display conditional rows if no model has data for them', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
@@ -145,10 +151,11 @@ describe('<ModelStatsDisplay />', () => {
expect(output).not.toContain('Thoughts');
expect(output).not.toContain('Tool');
expect(output).toMatchSnapshot();
unmount();
});
it('should display conditional rows if at least one model has data', () => {
const { lastFrame } = renderWithMockedStats({
it('should display conditional rows if at least one model has data', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
@@ -201,10 +208,11 @@ describe('<ModelStatsDisplay />', () => {
expect(output).toContain('Thoughts');
expect(output).toContain('Tool');
expect(output).toMatchSnapshot();
unmount();
});
it('should display stats for multiple models correctly', () => {
const { lastFrame } = renderWithMockedStats({
it('should display stats for multiple models correctly', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 10, totalErrors: 1, totalLatencyMs: 1000 },
@@ -256,10 +264,11 @@ describe('<ModelStatsDisplay />', () => {
expect(output).toContain('gemini-2.5-pro');
expect(output).toContain('gemini-2.5-flash');
expect(output).toMatchSnapshot();
unmount();
});
it('should handle large values without wrapping or overlapping', () => {
const { lastFrame } = renderWithMockedStats({
it('should handle large values without wrapping or overlapping', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: {
@@ -299,10 +308,11 @@ describe('<ModelStatsDisplay />', () => {
});
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('should display a single model correctly', () => {
const { lastFrame } = renderWithMockedStats({
it('should display a single model correctly', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
@@ -341,10 +351,11 @@ describe('<ModelStatsDisplay />', () => {
expect(output).toContain('gemini-2.5-pro');
expect(output).not.toContain('gemini-2.5-flash');
expect(output).toMatchSnapshot();
unmount();
});
it('should handle models with long names (gemini-3-*-preview) without layout breaking', () => {
const { lastFrame } = renderWithMockedStats(
it('should handle models with long names (gemini-3-*-preview) without layout breaking', async () => {
const { lastFrame, unmount } = await renderWithMockedStats(
{
models: {
'gemini-3-pro-preview': {
@@ -399,10 +410,11 @@ describe('<ModelStatsDisplay />', () => {
const output = lastFrame();
expect(output).toContain('gemini-3-pro-');
expect(output).toContain('gemini-3-flash-');
unmount();
});
it('should display role breakdown correctly', () => {
const { lastFrame } = renderWithMockedStats({
it('should display role breakdown correctly', async () => {
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 2, totalErrors: 0, totalLatencyMs: 200 },
@@ -458,9 +470,10 @@ describe('<ModelStatsDisplay />', () => {
expect(output).toContain('Output');
expect(output).toContain('Cache Reads');
expect(output).toMatchSnapshot();
unmount();
});
it('should render user identity information when provided', () => {
it('should render user identity information when provided', async () => {
useSettingsMock.mockReturnValue({
merged: {
ui: {
@@ -469,14 +482,6 @@ describe('<ModelStatsDisplay />', () => {
},
} as unknown as LoadedSettings);
const { lastFrame } = render(
<ModelStatsDisplay
selectedAuthType="oauth"
userEmail="test@example.com"
tier="Pro"
/>,
);
useSessionStatsMock.mockReturnValue({
stats: {
sessionId: 'test-session',
@@ -523,19 +528,29 @@ describe('<ModelStatsDisplay />', () => {
startNewPrompt: vi.fn(),
});
const { lastFrame, waitUntilReady, unmount } = render(
<ModelStatsDisplay
selectedAuthType="oauth"
userEmail="test@example.com"
tier="Pro"
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('Auth Method:');
expect(output).toContain('Logged in with Google');
expect(output).toContain('(test@example.com)');
expect(output).toContain('Tier:');
expect(output).toContain('Pro');
unmount();
});
it('should handle long role name layout', () => {
it('should handle long role name layout', async () => {
// Use the longest valid role name to test layout
const longRoleName = LlmRole.UTILITY_LOOP_DETECTOR;
const { lastFrame } = renderWithMockedStats({
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
@@ -588,12 +603,13 @@ describe('<ModelStatsDisplay />', () => {
const output = lastFrame();
expect(output).toContain(longRoleName);
expect(output).toMatchSnapshot();
unmount();
});
it('should filter out invalid role names', () => {
it('should filter out invalid role names', async () => {
const invalidRoleName =
'this_is_a_very_long_role_name_that_should_be_wrapped' as LlmRole;
const { lastFrame } = renderWithMockedStats({
const { lastFrame, unmount } = await renderWithMockedStats({
models: {
'gemini-2.5-pro': {
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
@@ -646,5 +662,6 @@ describe('<ModelStatsDisplay />', () => {
const output = lastFrame();
expect(output).not.toContain(invalidRoleName);
expect(output).toMatchSnapshot();
unmount();
});
});