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

@@ -46,8 +46,8 @@ describe('AskUserDialog', () => {
},
];
it('renders question and options', () => {
const { lastFrame } = renderWithProviders(
it('renders question and options', async () => {
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={authQuestion}
onSubmit={vi.fn()}
@@ -57,6 +57,7 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -125,7 +126,7 @@ describe('AskUserDialog', () => {
actions(stdin);
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith(expectedSubmit);
});
});
@@ -133,7 +134,7 @@ describe('AskUserDialog', () => {
it('handles custom option in single select with inline typing', async () => {
const onSubmit = vi.fn();
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={authQuestion}
onSubmit={onSubmit}
@@ -147,7 +148,8 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\x1b[B');
writeKey(stdin, '\x1b[B');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Enter a custom value');
});
@@ -156,14 +158,15 @@ describe('AskUserDialog', () => {
writeKey(stdin, char);
}
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('API Key');
});
// Press Enter to submit the custom value
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({ '0': 'API Key' });
});
});
@@ -180,7 +183,7 @@ describe('AskUserDialog', () => {
];
const onSubmit = vi.fn();
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={authQuestionWithOther}
onSubmit={onSubmit}
@@ -207,15 +210,17 @@ describe('AskUserDialog', () => {
writeKey(stdin, char);
}
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Line 1');
await waitUntilReady();
expect(lastFrame()).toContain('Line 2');
});
// Press Enter to submit
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({ '0': 'Line 1\nLine 2' });
});
});
@@ -240,7 +245,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -251,14 +256,19 @@ describe('AskUserDialog', () => {
{ useAlternateBuffer },
);
await waitFor(() => {
await waitFor(async () => {
if (expectedArrows) {
await waitUntilReady();
expect(lastFrame()).toContain('▲');
await waitUntilReady();
expect(lastFrame()).toContain('▼');
} else {
await waitUntilReady();
expect(lastFrame()).not.toContain('▲');
await waitUntilReady();
expect(lastFrame()).not.toContain('▼');
}
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
});
@@ -266,7 +276,7 @@ describe('AskUserDialog', () => {
);
it('navigates to custom option when typing unbound characters (Type-to-Jump)', async () => {
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={authQuestion}
onSubmit={vi.fn()}
@@ -279,10 +289,12 @@ describe('AskUserDialog', () => {
// Type a character without navigating down
writeKey(stdin, 'A');
await waitFor(() => {
await waitFor(async () => {
// Should show the custom input with 'A'
// Placeholder is hidden when text is present
await waitUntilReady();
expect(lastFrame()).toContain('A');
await waitUntilReady();
expect(lastFrame()).toContain('3. A');
});
@@ -290,12 +302,13 @@ describe('AskUserDialog', () => {
writeKey(stdin, 'P');
writeKey(stdin, 'I');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('API');
});
});
it('shows progress header for multiple questions', () => {
it('shows progress header for multiple questions', async () => {
const multiQuestions: Question[] = [
{
question: 'Which database should we use?',
@@ -319,7 +332,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={vi.fn()}
@@ -329,11 +342,12 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
it('hides progress header for single question', () => {
const { lastFrame } = renderWithProviders(
it('hides progress header for single question', async () => {
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={authQuestion}
onSubmit={vi.fn()}
@@ -343,11 +357,12 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
it('shows keyboard hints', () => {
const { lastFrame } = renderWithProviders(
it('shows keyboard hints', async () => {
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={authQuestion}
onSubmit={vi.fn()}
@@ -357,6 +372,7 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -380,7 +396,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={vi.fn()}
@@ -390,17 +406,20 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toContain('Which testing framework?');
writeKey(stdin, '\x1b[C'); // Right arrow
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Which CI provider?');
});
writeKey(stdin, '\x1b[D'); // Left arrow
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Which testing framework?');
});
});
@@ -424,7 +443,7 @@ describe('AskUserDialog', () => {
];
const onSubmit = vi.fn();
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={onSubmit}
@@ -437,40 +456,44 @@ describe('AskUserDialog', () => {
// Answer first question (should auto-advance)
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Which bundler?');
});
// Navigate back
writeKey(stdin, '\x1b[D');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Which package manager?');
});
// Navigate forward
writeKey(stdin, '\x1b[C');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Which bundler?');
});
// Answer second question
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Review your answers:');
});
// Submit from Review
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({ '0': 'pnpm', '1': 'Vite' });
});
});
it('shows Review tab in progress header for multiple questions', () => {
it('shows Review tab in progress header for multiple questions', async () => {
const multiQuestions: Question[] = [
{
question: 'Which framework?',
@@ -494,7 +517,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={vi.fn()}
@@ -504,6 +527,7 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -525,7 +549,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={vi.fn()}
@@ -537,19 +561,22 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\x1b[C'); // Right arrow
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Add documentation?');
});
writeKey(stdin, '\x1b[C'); // Right arrow to Review
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
writeKey(stdin, '\x1b[D'); // Left arrow back
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Add documentation?');
});
});
@@ -572,7 +599,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={vi.fn()}
@@ -586,7 +613,8 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\x1b[C');
writeKey(stdin, '\x1b[C');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
});
@@ -627,13 +655,13 @@ describe('AskUserDialog', () => {
// Submit
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({ '0': 'Node 20' });
});
});
describe('Text type questions', () => {
it('renders text input for type: "text"', () => {
it('renders text input for type: "text"', async () => {
const textQuestion: Question[] = [
{
question: 'What should we name this component?',
@@ -643,7 +671,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={textQuestion}
onSubmit={vi.fn()}
@@ -653,10 +681,11 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
it('shows default placeholder when none provided', () => {
it('shows default placeholder when none provided', async () => {
const textQuestion: Question[] = [
{
question: 'Enter the database connection string:',
@@ -665,7 +694,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={textQuestion}
onSubmit={vi.fn()}
@@ -675,6 +704,7 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -687,7 +717,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={textQuestion}
onSubmit={vi.fn()}
@@ -701,19 +731,22 @@ describe('AskUserDialog', () => {
writeKey(stdin, char);
}
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('abc');
});
writeKey(stdin, '\x7f'); // Backspace
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('ab');
await waitUntilReady();
expect(lastFrame()).not.toContain('abc');
});
});
it('shows correct keyboard hints for text type', () => {
it('shows correct keyboard hints for text type', async () => {
const textQuestion: Question[] = [
{
question: 'Enter the variable name:',
@@ -722,7 +755,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={textQuestion}
onSubmit={vi.fn()}
@@ -732,6 +765,7 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
@@ -754,7 +788,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={mixedQuestions}
onSubmit={vi.fn()}
@@ -770,13 +804,15 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\t'); // Use Tab instead of Right arrow when text input is active
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Should it be async?');
});
writeKey(stdin, '\x1b[D'); // Left arrow should work when NOT focusing a text input
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('useAuth');
});
});
@@ -802,7 +838,7 @@ describe('AskUserDialog', () => {
];
const onSubmit = vi.fn();
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={mixedQuestions}
onSubmit={onSubmit}
@@ -818,23 +854,29 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Which styling approach?');
});
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Review your answers:');
await waitUntilReady();
expect(lastFrame()).toContain('Name');
await waitUntilReady();
expect(lastFrame()).toContain('DataTable');
await waitUntilReady();
expect(lastFrame()).toContain('Style');
await waitUntilReady();
expect(lastFrame()).toContain('CSS Modules');
});
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({
'0': 'DataTable',
'1': 'CSS Modules',
@@ -864,7 +906,7 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\r');
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({});
});
});
@@ -879,7 +921,7 @@ describe('AskUserDialog', () => {
];
const onCancel = vi.fn();
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={textQuestion}
onSubmit={vi.fn()}
@@ -893,16 +935,19 @@ describe('AskUserDialog', () => {
writeKey(stdin, char);
}
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('SomeText');
});
// Send Ctrl+C
writeKey(stdin, '\x03'); // Ctrl+C
await waitFor(() => {
await waitFor(async () => {
// Text should be cleared
await waitUntilReady();
expect(lastFrame()).not.toContain('SomeText');
await waitUntilReady();
expect(lastFrame()).toContain('>');
});
@@ -926,7 +971,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={vi.fn()}
@@ -938,13 +983,15 @@ describe('AskUserDialog', () => {
// 1. Move to Text Q (Right arrow works for Choice Q)
writeKey(stdin, '\x1b[C');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Text Q?');
});
// 2. Type something in Text Q to make isEditingCustomOption true
writeKey(stdin, 'a');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('a');
});
@@ -952,18 +999,21 @@ describe('AskUserDialog', () => {
// When typing 'a', cursor is at index 1.
// We need to move cursor to index 0 first for Left arrow to work for navigation.
writeKey(stdin, '\x1b[D'); // Left arrow moves cursor to index 0
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Text Q?');
});
writeKey(stdin, '\x1b[D'); // Second Left arrow should now trigger navigation
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Choice Q?');
});
// 4. Immediately try Right arrow to go back to Text Q
writeKey(stdin, '\x1b[C');
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Text Q?');
});
});
@@ -987,7 +1037,7 @@ describe('AskUserDialog', () => {
];
const onSubmit = vi.fn();
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={multiQuestions}
onSubmit={onSubmit}
@@ -1001,14 +1051,16 @@ describe('AskUserDialog', () => {
act(() => {
stdin.write('\r'); // Select A1 for Q1 -> triggers autoAdvance
});
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Question 2?');
});
act(() => {
stdin.write('\r'); // Select A2 for Q2 -> triggers autoAdvance to Review
});
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toContain('Review your answers:');
});
@@ -1016,7 +1068,7 @@ describe('AskUserDialog', () => {
stdin.write('\r'); // Submit from Review
});
await waitFor(() => {
await waitFor(async () => {
expect(onSubmit).toHaveBeenCalledWith({
'0': 'A1',
'1': 'A2',
@@ -1037,7 +1089,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -1048,7 +1100,8 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
const frame = lastFrame();
// Plain text should be rendered as bold
expect(frame).toContain(chalk.bold('Which option do you prefer?'));
@@ -1066,7 +1119,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -1077,7 +1130,8 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
const frame = lastFrame();
// Should NOT have double-bold (the whole question bolded AND "this" bolded)
// "Is " should not be bold, only "this" should be bold
@@ -1098,7 +1152,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -1109,7 +1163,8 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
const frame = lastFrame();
// Check for chalk.bold('this') - asterisks should be gone, text should be bold
expect(frame).toContain(chalk.bold('this'));
@@ -1128,7 +1183,7 @@ describe('AskUserDialog', () => {
},
];
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -1139,7 +1194,8 @@ describe('AskUserDialog', () => {
{ width: 120 },
);
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
const frame = lastFrame();
// Backticks should be removed
expect(frame).toContain('npm start');
@@ -1148,7 +1204,7 @@ describe('AskUserDialog', () => {
});
});
it('uses availableTerminalHeight from UIStateContext if availableHeight prop is missing', () => {
it('uses availableTerminalHeight from UIStateContext if availableHeight prop is missing', async () => {
const questions: Question[] = [
{
question: 'Choose an option',
@@ -1166,7 +1222,7 @@ describe('AskUserDialog', () => {
availableTerminalHeight: 5, // Small height to force scroll arrows
} as UIState;
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<UIStateContext.Provider value={mockUIState}>
<AskUserDialog
questions={questions}
@@ -1179,11 +1235,13 @@ describe('AskUserDialog', () => {
);
// With height 5 and alternate buffer disabled, it should show scroll arrows (▲)
await waitUntilReady();
expect(lastFrame()).toContain('▲');
await waitUntilReady();
expect(lastFrame()).toContain('▼');
});
it('does NOT truncate the question when in alternate buffer mode even with small height', () => {
it('does NOT truncate the question when in alternate buffer mode even with small height', async () => {
const longQuestion =
'This is a very long question ' + 'with many words '.repeat(10);
const questions: Question[] = [
@@ -1200,7 +1258,7 @@ describe('AskUserDialog', () => {
availableTerminalHeight: 5,
} as UIState;
const { lastFrame } = renderWithProviders(
const { lastFrame, waitUntilReady } = renderWithProviders(
<UIStateContext.Provider value={mockUIState}>
<AskUserDialog
questions={questions}
@@ -1213,8 +1271,10 @@ describe('AskUserDialog', () => {
);
// Should NOT contain the truncation message
await waitUntilReady();
expect(lastFrame()).not.toContain('hidden ...');
// Should contain the full long question (or at least its parts)
await waitUntilReady();
expect(lastFrame()).toContain('This is a very long question');
});
@@ -1234,7 +1294,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -1248,7 +1308,8 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\x1b[B'); // Down
writeKey(stdin, '\x1b[B'); // Down to Other
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
});
@@ -1267,7 +1328,7 @@ describe('AskUserDialog', () => {
},
];
const { stdin, lastFrame } = renderWithProviders(
const { stdin, lastFrame, waitUntilReady } = renderWithProviders(
<AskUserDialog
questions={questions}
onSubmit={vi.fn()}
@@ -1281,7 +1342,8 @@ describe('AskUserDialog', () => {
writeKey(stdin, '\x1b[B'); // Down
writeKey(stdin, '\x1b[B'); // Down to Other
await waitFor(() => {
await waitFor(async () => {
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
});