mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-25 04:24:51 -07:00
Migrate core render util to use xterm.js as part of the rendering loop. (#19044)
This commit is contained in:
@@ -62,7 +62,12 @@ const createConversation = (messages: MessageRecord[]): ConversationRecord => ({
|
||||
});
|
||||
|
||||
describe('RewindViewer', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
@@ -87,18 +92,20 @@ describe('RewindViewer', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
])('renders $name', ({ messages }) => {
|
||||
])('renders $name', async ({ messages }) => {
|
||||
const conversation = createConversation(messages as MessageRecord[]);
|
||||
const onExit = vi.fn();
|
||||
const onRewind = vi.fn();
|
||||
const { lastFrame } = renderWithProviders(
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={onExit}
|
||||
onRewind={onRewind}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,13 +120,14 @@ describe('RewindViewer', () => {
|
||||
]);
|
||||
const onExit = vi.fn();
|
||||
const onRewind = vi.fn();
|
||||
const { lastFrame, stdin } = renderWithProviders(
|
||||
const { lastFrame, stdin, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={onExit}
|
||||
onRewind={onRewind}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
// Initial state
|
||||
expect(lastFrame()).toMatchSnapshot('initial-state');
|
||||
@@ -128,10 +136,12 @@ describe('RewindViewer', () => {
|
||||
act(() => {
|
||||
stdin.write('\x1b[B');
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toMatchSnapshot('after-down');
|
||||
});
|
||||
unmount();
|
||||
});
|
||||
|
||||
describe('Navigation', () => {
|
||||
@@ -144,20 +154,30 @@ describe('RewindViewer', () => {
|
||||
{ type: 'user', content: 'Q2', id: '2', timestamp: '1' },
|
||||
{ type: 'user', content: 'Q3', id: '3', timestamp: '1' },
|
||||
]);
|
||||
const { lastFrame, stdin } = renderWithProviders(
|
||||
const { lastFrame, stdin, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={vi.fn()}
|
||||
onRewind={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
act(() => {
|
||||
stdin.write(sequence);
|
||||
});
|
||||
await waitUntilReady();
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toMatchSnapshot(expectedSnapshot);
|
||||
const frame = lastFrame();
|
||||
expect(frame).toMatchSnapshot(expectedSnapshot);
|
||||
if (expectedSnapshot === 'after-up') {
|
||||
const headerLines = frame
|
||||
?.split('\n')
|
||||
.filter((line) => line.includes('╭───'));
|
||||
expect(headerLines).toHaveLength(1);
|
||||
}
|
||||
});
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('handles cyclic navigation', async () => {
|
||||
@@ -166,18 +186,20 @@ describe('RewindViewer', () => {
|
||||
{ type: 'user', content: 'Q2', id: '2', timestamp: '1' },
|
||||
{ type: 'user', content: 'Q3', id: '3', timestamp: '1' },
|
||||
]);
|
||||
const { lastFrame, stdin } = renderWithProviders(
|
||||
const { lastFrame, stdin, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={vi.fn()}
|
||||
onRewind={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
// Up from first -> Last
|
||||
act(() => {
|
||||
stdin.write('\x1b[A');
|
||||
});
|
||||
await waitUntilReady();
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toMatchSnapshot('cyclic-up');
|
||||
});
|
||||
@@ -186,9 +208,11 @@ describe('RewindViewer', () => {
|
||||
act(() => {
|
||||
stdin.write('\x1b[B');
|
||||
});
|
||||
await waitUntilReady();
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toMatchSnapshot('cyclic-down');
|
||||
});
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -199,14 +223,16 @@ describe('RewindViewer', () => {
|
||||
actionStep: async (
|
||||
stdin: { write: (data: string) => void },
|
||||
lastFrame: () => string | undefined,
|
||||
waitUntilReady: () => Promise<void>,
|
||||
) => {
|
||||
// Wait for confirmation dialog to be rendered and interactive
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('Confirm Rewind');
|
||||
});
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
stdin.write('\r');
|
||||
});
|
||||
await waitUntilReady();
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -214,14 +240,18 @@ describe('RewindViewer', () => {
|
||||
actionStep: async (
|
||||
stdin: { write: (data: string) => void },
|
||||
lastFrame: () => string | undefined,
|
||||
waitUntilReady: () => Promise<void>,
|
||||
) => {
|
||||
// Wait for confirmation dialog
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('Confirm Rewind');
|
||||
});
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
stdin.write('\x1b');
|
||||
});
|
||||
await act(async () => {
|
||||
await waitUntilReady();
|
||||
});
|
||||
// Wait for return to main view
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('> Rewind');
|
||||
@@ -233,23 +263,26 @@ describe('RewindViewer', () => {
|
||||
{ type: 'user', content: 'Original Prompt', id: '1', timestamp: '1' },
|
||||
]);
|
||||
const onRewind = vi.fn();
|
||||
const { lastFrame, stdin } = renderWithProviders(
|
||||
const { lastFrame, stdin, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={vi.fn()}
|
||||
onRewind={onRewind}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
// Select
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
stdin.write('\x1b[A'); // Move up from 'Stay at current position'
|
||||
stdin.write('\r');
|
||||
});
|
||||
await waitUntilReady();
|
||||
expect(lastFrame()).toMatchSnapshot('confirmation-dialog');
|
||||
|
||||
// Act
|
||||
await actionStep(stdin, lastFrame);
|
||||
await actionStep(stdin, lastFrame, waitUntilReady);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -287,13 +320,14 @@ describe('RewindViewer', () => {
|
||||
},
|
||||
]);
|
||||
const onRewind = vi.fn();
|
||||
const { lastFrame, stdin } = renderWithProviders(
|
||||
const { lastFrame, stdin, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={vi.fn()}
|
||||
onRewind={onRewind}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
|
||||
@@ -302,6 +336,7 @@ describe('RewindViewer', () => {
|
||||
stdin.write('\x1b[A'); // Move up from 'Stay at current position'
|
||||
stdin.write('\r'); // Select
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
// Wait for confirmation dialog
|
||||
await waitFor(() => {
|
||||
@@ -312,14 +347,16 @@ describe('RewindViewer', () => {
|
||||
act(() => {
|
||||
stdin.write('\r');
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onRewind).toHaveBeenCalledWith('1', expected, expect.anything());
|
||||
});
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
it('updates content when conversation changes (background update)', () => {
|
||||
it('updates content when conversation changes (background update)', async () => {
|
||||
const messages: MessageRecord[] = [
|
||||
{ type: 'user', content: 'Message 1', id: '1', timestamp: '1' },
|
||||
];
|
||||
@@ -327,13 +364,14 @@ describe('RewindViewer', () => {
|
||||
const onExit = vi.fn();
|
||||
const onRewind = vi.fn();
|
||||
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={onExit}
|
||||
onRewind={onRewind}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot('initial');
|
||||
|
||||
@@ -345,14 +383,20 @@ describe('RewindViewer', () => {
|
||||
];
|
||||
conversation = createConversation(newMessages);
|
||||
|
||||
const { lastFrame: lastFrame2 } = renderWithProviders(
|
||||
const {
|
||||
lastFrame: lastFrame2,
|
||||
waitUntilReady: waitUntilReady2,
|
||||
unmount: unmount2,
|
||||
} = renderWithProviders(
|
||||
<RewindViewer
|
||||
conversation={conversation}
|
||||
onExit={onExit}
|
||||
onRewind={onRewind}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady2();
|
||||
|
||||
expect(lastFrame2()).toMatchSnapshot('after-update');
|
||||
unmount2();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user