mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-10 13:22:51 -07:00
Migrate core render util to use xterm.js as part of the rendering loop. (#19044)
This commit is contained in:
@@ -24,8 +24,6 @@ vi.mock('../../contexts/UIStateContext.js', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
describe('<VirtualizedList />', () => {
|
||||
const keyExtractor = (item: string) => item;
|
||||
|
||||
@@ -60,7 +58,7 @@ describe('<VirtualizedList />', () => {
|
||||
])(
|
||||
'renders only visible items ($name)',
|
||||
async ({ initialScrollIndex, visible, notVisible }) => {
|
||||
const { lastFrame } = render(
|
||||
const { lastFrame, waitUntilReady, unmount } = render(
|
||||
<Box height={10} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
data={longData}
|
||||
@@ -71,9 +69,7 @@ describe('<VirtualizedList />', () => {
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
const frame = lastFrame();
|
||||
visible.forEach((item) => {
|
||||
@@ -83,11 +79,12 @@ describe('<VirtualizedList />', () => {
|
||||
expect(frame).not.toContain(item);
|
||||
});
|
||||
expect(frame).toMatchSnapshot();
|
||||
unmount();
|
||||
},
|
||||
);
|
||||
|
||||
it('sticks to bottom when new items added', async () => {
|
||||
const { lastFrame, rerender } = render(
|
||||
const { lastFrame, rerender, waitUntilReady, unmount } = render(
|
||||
<Box height={10} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
data={longData}
|
||||
@@ -98,38 +95,37 @@ describe('<VirtualizedList />', () => {
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toContain('Item 99');
|
||||
|
||||
// Add items
|
||||
const newData = [...longData, 'Item 100', 'Item 101'];
|
||||
rerender(
|
||||
<Box height={10} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
data={newData}
|
||||
renderItem={renderItem1px}
|
||||
keyExtractor={keyExtractor}
|
||||
estimatedItemHeight={() => itemHeight}
|
||||
// We don't need to pass initialScrollIndex again for it to stick,
|
||||
// but passing it doesn't hurt. The component should auto-stick because it was at bottom.
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
rerender(
|
||||
<Box height={10} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
data={newData}
|
||||
renderItem={renderItem1px}
|
||||
keyExtractor={keyExtractor}
|
||||
estimatedItemHeight={() => itemHeight}
|
||||
// We don't need to pass initialScrollIndex again for it to stick,
|
||||
// but passing it doesn't hurt. The component should auto-stick because it was at bottom.
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
const frame = lastFrame();
|
||||
expect(frame).toContain('Item 101');
|
||||
expect(frame).not.toContain('Item 0');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('scrolls down to show new items when requested via ref', async () => {
|
||||
const ref = createRef<VirtualizedListRef<string>>();
|
||||
const { lastFrame } = render(
|
||||
const { lastFrame, waitUntilReady, unmount } = render(
|
||||
<Box height={10} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
ref={ref}
|
||||
@@ -140,20 +136,19 @@ describe('<VirtualizedList />', () => {
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toContain('Item 0');
|
||||
|
||||
// Scroll to bottom via ref
|
||||
await act(async () => {
|
||||
ref.current?.scrollToEnd();
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
const frame = lastFrame();
|
||||
expect(frame).toContain('Item 99');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -184,7 +179,7 @@ describe('<VirtualizedList />', () => {
|
||||
(_, i) => `Item ${i}`,
|
||||
);
|
||||
|
||||
const { lastFrame } = render(
|
||||
const { lastFrame, waitUntilReady, unmount } = render(
|
||||
<Box height={20} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
data={veryLongData}
|
||||
@@ -197,13 +192,12 @@ describe('<VirtualizedList />', () => {
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
const frame = lastFrame();
|
||||
expect(mountedCount).toBe(expectedMountedCount);
|
||||
expect(frame).toMatchSnapshot();
|
||||
unmount();
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -267,10 +261,8 @@ describe('<VirtualizedList />', () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const { lastFrame } = render(<TestComponent />);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
const { lastFrame, waitUntilReady, unmount } = render(<TestComponent />);
|
||||
await waitUntilReady();
|
||||
|
||||
// Initially, only Item 0 (height 10) fills the 10px viewport
|
||||
expect(lastFrame()).toContain('Item 0');
|
||||
@@ -279,13 +271,14 @@ describe('<VirtualizedList />', () => {
|
||||
// Shrink Item 0 to 1px via context
|
||||
await act(async () => {
|
||||
setHeightFn(1);
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
// Now Item 0 is 1px, so Items 1-9 should also be visible to fill 10px
|
||||
expect(lastFrame()).toContain('Item 0');
|
||||
expect(lastFrame()).toContain('Item 1');
|
||||
expect(lastFrame()).toContain('Item 9');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('updates scroll position correctly when scrollBy is called multiple times in the same tick', async () => {
|
||||
@@ -299,7 +292,7 @@ describe('<VirtualizedList />', () => {
|
||||
);
|
||||
const keyExtractor = (item: string) => item;
|
||||
|
||||
render(
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<Box height={10} width={100} borderStyle="round">
|
||||
<VirtualizedList
|
||||
ref={ref}
|
||||
@@ -310,26 +303,25 @@ describe('<VirtualizedList />', () => {
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(ref.current?.getScrollState().scrollTop).toBe(0);
|
||||
|
||||
await act(async () => {
|
||||
ref.current?.scrollBy(1);
|
||||
ref.current?.scrollBy(1);
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(ref.current?.getScrollState().scrollTop).toBe(2);
|
||||
|
||||
await act(async () => {
|
||||
ref.current?.scrollBy(2);
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(ref.current?.getScrollState().scrollTop).toBe(4);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('renders correctly in copyModeEnabled when scrolled', async () => {
|
||||
@@ -340,7 +332,7 @@ describe('<VirtualizedList />', () => {
|
||||
|
||||
const longData = Array.from({ length: 100 }, (_, i) => `Item ${i}`);
|
||||
// Use copy mode
|
||||
const { lastFrame } = render(
|
||||
const { lastFrame, waitUntilReady, unmount } = render(
|
||||
<Box height={10} width={100}>
|
||||
<VirtualizedList
|
||||
data={longData}
|
||||
@@ -355,9 +347,7 @@ describe('<VirtualizedList />', () => {
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
// Item 50 should be visible
|
||||
expect(lastFrame()).toContain('Item 50');
|
||||
@@ -365,5 +355,6 @@ describe('<VirtualizedList />', () => {
|
||||
expect(lastFrame()).toContain('Item 59');
|
||||
// But far away items should not be (ensures we are actually scrolled)
|
||||
expect(lastFrame()).not.toContain('Item 0');
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user