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

@@ -5,7 +5,6 @@
*/
import { render, renderWithProviders } from '../../../test-utils/render.js';
import { waitFor } from '../../../test-utils/async.js';
import { OverflowProvider } from '../../contexts/OverflowContext.js';
import { MaxSizedBox } from './MaxSizedBox.js';
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
@@ -14,7 +13,7 @@ import { describe, it, expect } from 'vitest';
describe('<MaxSizedBox />', () => {
it('renders children without truncation when they fit', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={10}>
<Box>
@@ -23,13 +22,14 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() => expect(lastFrame()).toContain('Hello, World!'));
await waitUntilReady();
expect(lastFrame()).toContain('Hello, World!');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('hides lines when content exceeds maxHeight', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={2}>
<Box flexDirection="column">
@@ -40,15 +40,14 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... first 2 lines hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... first 2 lines hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('hides lines at the end when content exceeds maxHeight and overflowDirection is bottom', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={2} overflowDirection="bottom">
<Box flexDirection="column">
@@ -59,15 +58,14 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... last 2 lines hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... last 2 lines hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows plural "lines" when more than one line is hidden', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={2}>
<Box flexDirection="column">
@@ -78,15 +76,14 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... first 2 lines hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... first 2 lines hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('shows singular "line" when exactly one line is hidden', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={2} additionalHiddenLinesCount={1}>
<Box flexDirection="column">
@@ -95,15 +92,14 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... first 1 line hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... first 1 line hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('accounts for additionalHiddenLinesCount', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={2} additionalHiddenLinesCount={5}>
<Box flexDirection="column">
@@ -114,15 +110,14 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... first 7 lines hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... first 7 lines hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('wraps text that exceeds maxWidth', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={10} maxHeight={5}>
<Box>
@@ -132,13 +127,14 @@ describe('<MaxSizedBox />', () => {
</OverflowProvider>,
);
await waitFor(() => expect(lastFrame()).toContain('This is a'));
await waitUntilReady();
expect(lastFrame()).toContain('This is a');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('does not truncate when maxHeight is undefined', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={undefined}>
<Box flexDirection="column">
@@ -148,25 +144,25 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() => expect(lastFrame()).toContain('Line 1'));
await waitUntilReady();
expect(lastFrame()).toContain('Line 1');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('renders an empty box for empty children', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={10}></MaxSizedBox>
</OverflowProvider>,
);
// Use waitFor to ensure ResizeObserver has a chance to run
await waitFor(() => expect(lastFrame()).toBeDefined());
expect(lastFrame()?.trim()).equals('');
await waitUntilReady();
expect(lastFrame({ allowEmpty: true })?.trim()).equals('');
unmount();
});
it('handles React.Fragment as a child', async () => {
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={10}>
<Box flexDirection="column">
@@ -179,7 +175,8 @@ describe('<MaxSizedBox />', () => {
</MaxSizedBox>
</OverflowProvider>,
);
await waitFor(() => expect(lastFrame()).toContain('Line 1 from Fragment'));
await waitUntilReady();
expect(lastFrame()).toContain('Line 1 from Fragment');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -189,7 +186,7 @@ describe('<MaxSizedBox />', () => {
{ length: 30 },
(_, i) => `Line ${i + 1}`,
).join('\n');
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={10} overflowDirection="top">
<Box>
@@ -199,9 +196,8 @@ describe('<MaxSizedBox />', () => {
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... first 21 lines hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... first 21 lines hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -211,7 +207,7 @@ describe('<MaxSizedBox />', () => {
{ length: 30 },
(_, i) => `Line ${i + 1}`,
).join('\n');
const { lastFrame, unmount } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<OverflowProvider>
<MaxSizedBox maxWidth={80} maxHeight={10} overflowDirection="bottom">
<Box>
@@ -221,9 +217,8 @@ describe('<MaxSizedBox />', () => {
</OverflowProvider>,
);
await waitFor(() =>
expect(lastFrame()).toContain('... last 21 lines hidden ...'),
);
await waitUntilReady();
expect(lastFrame()).toContain('... last 21 lines hidden ...');
expect(lastFrame()).toMatchSnapshot();
unmount();
});
@@ -233,7 +228,7 @@ describe('<MaxSizedBox />', () => {
{ length: 20 },
(_, i) => `- Step ${i + 1}: Do something important`,
).join('\n');
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
<MaxSizedBox maxWidth={80} maxHeight={5} overflowDirection="bottom">
<MarkdownDisplay
text={`## Plan\n\n${markdownContent}`}
@@ -244,14 +239,16 @@ describe('<MaxSizedBox />', () => {
{ width: 80 },
);
await waitFor(() => expect(lastFrame()).toContain('... last'));
await waitUntilReady();
expect(lastFrame()).toContain('... last');
const frame = lastFrame()!;
const lines = frame.split('\n');
const frame = lastFrame();
const lines = frame.trim().split('\n');
const lastLine = lines[lines.length - 1];
// The last line should only contain the hidden indicator, no leaked content
expect(lastLine).toMatch(/^\.\.\. last \d+ lines? hidden \.\.\.$/);
expect(lastFrame()).toMatchSnapshot();
unmount();
});
});