@inquirer/testing 3.1.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/jest.d.ts +3 -1
- package/dist/jest.js +133 -56
- package/dist/vitest.d.ts +3 -1
- package/dist/vitest.js +133 -54
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -73,11 +73,42 @@ describe('input prompt', () => {
|
|
|
73
73
|
|
|
74
74
|
- `answer` (`Promise`) - Resolves when an answer is provided and valid
|
|
75
75
|
- `getScreen` (`({ raw?: boolean }) => string`) - Returns the current screen content. By default strips ANSI codes
|
|
76
|
+
- `nextRender` (`() => Promise<void>`) - Wait for the next screen update. Use after triggering async actions (e.g. pressing enter with validation). Coalesces rapid back-to-back renders so a single `await nextRender()` captures the final settled state
|
|
76
77
|
- `events` - Utilities to interact with the prompt:
|
|
77
78
|
- `keypress(key: string | KeyObject)` - Trigger a keypress event
|
|
78
79
|
- `type(text: string)` - Type text into the prompt
|
|
79
80
|
- `getFullOutput` (`() => Promise<string>`) - Returns the full output interpreted through a virtual terminal, resolving ANSI escape sequences into the actual screen state
|
|
80
81
|
|
|
82
|
+
### Async actions and `nextRender()`
|
|
83
|
+
|
|
84
|
+
When a keypress triggers an asynchronous action (such as input validation), the screen won't update synchronously. Use `nextRender()` to wait for the prompt to settle before reading the screen:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { render } from '@inquirer/testing';
|
|
88
|
+
import input from '@inquirer/input';
|
|
89
|
+
|
|
90
|
+
it('shows a validation error', async () => {
|
|
91
|
+
const { answer, events, getScreen, nextRender } = await render(input, {
|
|
92
|
+
message: 'Enter a number',
|
|
93
|
+
validate: (value) => /^\d+$/.test(value) || 'Must be a number',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
events.type('abc');
|
|
97
|
+
events.keypress('enter');
|
|
98
|
+
|
|
99
|
+
await nextRender(); // wait for validation to complete and the error to render
|
|
100
|
+
expect(getScreen()).toContain('Must be a number');
|
|
101
|
+
|
|
102
|
+
events.keypress('backspace');
|
|
103
|
+
events.keypress('backspace');
|
|
104
|
+
events.keypress('backspace');
|
|
105
|
+
events.type('42');
|
|
106
|
+
events.keypress('enter');
|
|
107
|
+
|
|
108
|
+
await expect(answer).resolves.toEqual('42');
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
81
112
|
### Unit Testing Example
|
|
82
113
|
|
|
83
114
|
You can refer to the [`@inquirer/input` test suite](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/input/input.test.ts) for a comprehensive unit testing example using `render()`.
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -30,6 +30,20 @@ export async function render(prompt, config, options) {
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
};
|
|
33
|
+
let rendersConsumed = output.writeCount;
|
|
34
|
+
function nextRender() {
|
|
35
|
+
const waitForRender = output.writeCount > rendersConsumed
|
|
36
|
+
? Promise.resolve()
|
|
37
|
+
: new Promise((resolve) => output.once('render', resolve));
|
|
38
|
+
// After detecting a render, let the event loop settle so that multiple
|
|
39
|
+
// synchronous-ish renders (e.g. validation: loading → error) are coalesced.
|
|
40
|
+
return waitForRender.then(() => new Promise((resolve) => {
|
|
41
|
+
setImmediate(() => {
|
|
42
|
+
rendersConsumed = output.writeCount;
|
|
43
|
+
resolve();
|
|
44
|
+
});
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
33
47
|
return {
|
|
34
48
|
answer,
|
|
35
49
|
input,
|
|
@@ -44,5 +58,6 @@ export async function render(prompt, config, options) {
|
|
|
44
58
|
return fullOutput;
|
|
45
59
|
return interpretTerminalOutput(fullOutput);
|
|
46
60
|
},
|
|
61
|
+
nextRender,
|
|
47
62
|
};
|
|
48
63
|
}
|
package/dist/jest.d.ts
CHANGED
|
@@ -15,5 +15,7 @@ export { screenInstance as screen };
|
|
|
15
15
|
* });
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
-
export declare function wrapPrompt<Value, Config>(prompt: Prompt<Value, Config>
|
|
18
|
+
export declare function wrapPrompt<Value, Config>(prompt: Prompt<Value, Config> | {
|
|
19
|
+
default: Prompt<Value, Config>;
|
|
20
|
+
}): Prompt<Value, Config>;
|
|
19
21
|
export { Screen, type KeypressEvent } from './screen.js';
|
package/dist/jest.js
CHANGED
|
@@ -22,9 +22,13 @@ beforeEach(() => {
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
export function wrapPrompt(prompt) {
|
|
25
|
+
// Unwrap SWC-style module namespace objects where barrel re-exports like
|
|
26
|
+
// `export { default as input } from '@inquirer/input'` get transformed into
|
|
27
|
+
// `{ default: fn }` instead of the function directly.
|
|
28
|
+
const fn = typeof prompt === 'function' ? prompt : prompt.default;
|
|
25
29
|
return (config, context) => {
|
|
26
30
|
const output = screenInstance.createOutput();
|
|
27
|
-
const promise =
|
|
31
|
+
const promise = fn(config, {
|
|
28
32
|
...context,
|
|
29
33
|
input: screenInstance.input,
|
|
30
34
|
output,
|
|
@@ -33,87 +37,160 @@ export function wrapPrompt(prompt) {
|
|
|
33
37
|
return promise;
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
|
-
//
|
|
40
|
+
// Prompt names used by the @inquirer/prompts barrel mock to wrap only prompt exports.
|
|
41
|
+
const promptNames = [
|
|
42
|
+
'input',
|
|
43
|
+
'select',
|
|
44
|
+
'confirm',
|
|
45
|
+
'checkbox',
|
|
46
|
+
'password',
|
|
47
|
+
'expand',
|
|
48
|
+
'rawlist',
|
|
49
|
+
'number',
|
|
50
|
+
'search',
|
|
51
|
+
'editor',
|
|
52
|
+
];
|
|
53
|
+
// Mock individual prompt packages (covers `import input from '@inquirer/input'` style).
|
|
54
|
+
// All prompt packages are optional peer dependencies, so factories silently skip
|
|
55
|
+
// packages that aren't installed in the consumer's project.
|
|
37
56
|
jest.mock('@inquirer/input', () => {
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
try {
|
|
58
|
+
const actual = jest.requireActual('@inquirer/input');
|
|
59
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
40
64
|
});
|
|
41
65
|
jest.mock('@inquirer/select', () => {
|
|
42
|
-
|
|
43
|
-
|
|
66
|
+
try {
|
|
67
|
+
const actual = jest.requireActual('@inquirer/select');
|
|
68
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
44
73
|
});
|
|
45
74
|
jest.mock('@inquirer/confirm', () => {
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
try {
|
|
76
|
+
const actual = jest.requireActual('@inquirer/confirm');
|
|
77
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
48
82
|
});
|
|
49
83
|
jest.mock('@inquirer/checkbox', () => {
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
try {
|
|
85
|
+
const actual = jest.requireActual('@inquirer/checkbox');
|
|
86
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
52
91
|
});
|
|
53
92
|
jest.mock('@inquirer/password', () => {
|
|
54
|
-
|
|
55
|
-
|
|
93
|
+
try {
|
|
94
|
+
const actual = jest.requireActual('@inquirer/password');
|
|
95
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
56
100
|
});
|
|
57
101
|
jest.mock('@inquirer/expand', () => {
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
try {
|
|
103
|
+
const actual = jest.requireActual('@inquirer/expand');
|
|
104
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
60
109
|
});
|
|
61
110
|
jest.mock('@inquirer/rawlist', () => {
|
|
62
|
-
|
|
63
|
-
|
|
111
|
+
try {
|
|
112
|
+
const actual = jest.requireActual('@inquirer/rawlist');
|
|
113
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return {};
|
|
117
|
+
}
|
|
64
118
|
});
|
|
65
119
|
jest.mock('@inquirer/number', () => {
|
|
66
|
-
|
|
67
|
-
|
|
120
|
+
try {
|
|
121
|
+
const actual = jest.requireActual('@inquirer/number');
|
|
122
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
68
127
|
});
|
|
69
128
|
jest.mock('@inquirer/search', () => {
|
|
70
|
-
|
|
71
|
-
|
|
129
|
+
try {
|
|
130
|
+
const actual = jest.requireActual('@inquirer/search');
|
|
131
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
72
136
|
});
|
|
73
137
|
jest.mock('@inquirer/editor', () => {
|
|
74
|
-
|
|
75
|
-
|
|
138
|
+
try {
|
|
139
|
+
const actual = jest.requireActual('@inquirer/editor');
|
|
140
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
76
145
|
});
|
|
77
146
|
// Mock @inquirer/prompts barrel re-exports (covers `import { input } from '@inquirer/prompts'` style).
|
|
78
147
|
// Jest's module mock for individual packages doesn't propagate through barrel re-exports.
|
|
148
|
+
// Only prompt functions are wrapped; other exports (like Separator) are passed through.
|
|
79
149
|
jest.mock('@inquirer/prompts', () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
...actual
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
150
|
+
try {
|
|
151
|
+
const actual = jest.requireActual('@inquirer/prompts');
|
|
152
|
+
const wrapped = { ...actual };
|
|
153
|
+
for (const name of promptNames) {
|
|
154
|
+
if (name in actual) {
|
|
155
|
+
wrapped[name] = wrapPrompt(actual[name]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return wrapped;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return {};
|
|
162
|
+
}
|
|
94
163
|
});
|
|
95
164
|
// Mock the external editor to capture typed input instead of spawning a real editor.
|
|
96
165
|
// Buffers all screen.type() calls and submits on screen.keypress('enter'), matching
|
|
97
166
|
// the interaction pattern of other prompts (type → enter).
|
|
98
|
-
jest.mock('@inquirer/external-editor', () =>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
167
|
+
jest.mock('@inquirer/external-editor', () => {
|
|
168
|
+
try {
|
|
169
|
+
jest.requireActual('@inquirer/external-editor');
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
editAsync: (_text, callback) => {
|
|
176
|
+
let buffer = '';
|
|
177
|
+
const typeSpy = jest
|
|
178
|
+
.spyOn(screenInstance, 'type')
|
|
179
|
+
.mockImplementation((text) => {
|
|
180
|
+
buffer += text;
|
|
181
|
+
});
|
|
182
|
+
const keypressSpy = jest
|
|
183
|
+
.spyOn(screenInstance, 'keypress')
|
|
184
|
+
.mockImplementation((key) => {
|
|
185
|
+
const name = typeof key === 'string' ? key : key.name;
|
|
186
|
+
if (name === 'enter' || name === 'return') {
|
|
187
|
+
typeSpy.mockRestore();
|
|
188
|
+
keypressSpy.mockRestore();
|
|
189
|
+
process.nextTick(() => callback(undefined, buffer));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
});
|
|
118
195
|
// Re-export Screen class and KeypressEvent type for advanced use cases
|
|
119
196
|
export { Screen } from './screen.js';
|
package/dist/vitest.d.ts
CHANGED
|
@@ -16,5 +16,7 @@ export { screenInstance as screen };
|
|
|
16
16
|
* });
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
export declare function wrapPrompt<Value, Config>(prompt: Prompt<Value, Config>
|
|
19
|
+
export declare function wrapPrompt<Value, Config>(prompt: Prompt<Value, Config> | {
|
|
20
|
+
default: Prompt<Value, Config>;
|
|
21
|
+
}): Prompt<Value, Config>;
|
|
20
22
|
export { Screen, type KeypressEvent } from './screen.js';
|
package/dist/vitest.js
CHANGED
|
@@ -22,9 +22,13 @@ beforeEach(() => {
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
export function wrapPrompt(prompt) {
|
|
25
|
+
// Unwrap SWC-style module namespace objects where barrel re-exports like
|
|
26
|
+
// `export { default as input } from '@inquirer/input'` get transformed into
|
|
27
|
+
// `{ default: fn }` instead of the function directly.
|
|
28
|
+
const fn = typeof prompt === 'function' ? prompt : prompt.default;
|
|
25
29
|
return (config, context) => {
|
|
26
30
|
const output = screenInstance.createOutput();
|
|
27
|
-
const promise =
|
|
31
|
+
const promise = fn(config, {
|
|
28
32
|
...context,
|
|
29
33
|
input: screenInstance.input,
|
|
30
34
|
output,
|
|
@@ -33,86 +37,161 @@ export function wrapPrompt(prompt) {
|
|
|
33
37
|
return promise;
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
|
-
//
|
|
40
|
+
// Prompt names used by the @inquirer/prompts barrel mock to wrap only prompt exports.
|
|
41
|
+
const promptNames = [
|
|
42
|
+
'input',
|
|
43
|
+
'select',
|
|
44
|
+
'confirm',
|
|
45
|
+
'checkbox',
|
|
46
|
+
'password',
|
|
47
|
+
'expand',
|
|
48
|
+
'rawlist',
|
|
49
|
+
'number',
|
|
50
|
+
'search',
|
|
51
|
+
'editor',
|
|
52
|
+
];
|
|
53
|
+
// Mock individual prompt packages (covers `import input from '@inquirer/input'` style).
|
|
54
|
+
// All prompt packages are optional peer dependencies, so factories silently skip
|
|
55
|
+
// packages that aren't installed in the consumer's project.
|
|
37
56
|
vi.mock('@inquirer/input', async (importOriginal) => {
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
try {
|
|
58
|
+
const actual = await importOriginal();
|
|
59
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
40
64
|
});
|
|
41
65
|
vi.mock('@inquirer/select', async (importOriginal) => {
|
|
42
|
-
|
|
43
|
-
|
|
66
|
+
try {
|
|
67
|
+
const actual = await importOriginal();
|
|
68
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
44
73
|
});
|
|
45
74
|
vi.mock('@inquirer/confirm', async (importOriginal) => {
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
try {
|
|
76
|
+
const actual = await importOriginal();
|
|
77
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
48
82
|
});
|
|
49
83
|
vi.mock('@inquirer/checkbox', async (importOriginal) => {
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
try {
|
|
85
|
+
const actual = await importOriginal();
|
|
86
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
52
91
|
});
|
|
53
92
|
vi.mock('@inquirer/password', async (importOriginal) => {
|
|
54
|
-
|
|
55
|
-
|
|
93
|
+
try {
|
|
94
|
+
const actual = await importOriginal();
|
|
95
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
56
100
|
});
|
|
57
101
|
vi.mock('@inquirer/expand', async (importOriginal) => {
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
try {
|
|
103
|
+
const actual = await importOriginal();
|
|
104
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
60
109
|
});
|
|
61
110
|
vi.mock('@inquirer/rawlist', async (importOriginal) => {
|
|
62
|
-
|
|
63
|
-
|
|
111
|
+
try {
|
|
112
|
+
const actual = await importOriginal();
|
|
113
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return {};
|
|
117
|
+
}
|
|
64
118
|
});
|
|
65
119
|
vi.mock('@inquirer/number', async (importOriginal) => {
|
|
66
|
-
|
|
67
|
-
|
|
120
|
+
try {
|
|
121
|
+
const actual = await importOriginal();
|
|
122
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
68
127
|
});
|
|
69
128
|
vi.mock('@inquirer/search', async (importOriginal) => {
|
|
70
|
-
|
|
71
|
-
|
|
129
|
+
try {
|
|
130
|
+
const actual = await importOriginal();
|
|
131
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
72
136
|
});
|
|
73
137
|
vi.mock('@inquirer/editor', async (importOriginal) => {
|
|
74
|
-
|
|
75
|
-
|
|
138
|
+
try {
|
|
139
|
+
const actual = await importOriginal();
|
|
140
|
+
return { ...actual, default: wrapPrompt(actual.default) };
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
76
145
|
});
|
|
77
146
|
// Mock @inquirer/prompts barrel re-exports (covers `import { input } from '@inquirer/prompts'` style).
|
|
78
147
|
// While Vitest's module interception often propagates through ESM re-exports, an explicit mock
|
|
79
148
|
// ensures consistent behavior across all environments and bundler configurations.
|
|
149
|
+
// Only prompt functions are wrapped; other exports (like Separator) are passed through.
|
|
80
150
|
vi.mock('@inquirer/prompts', async (importOriginal) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
...actual
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
};
|
|
151
|
+
try {
|
|
152
|
+
const actual = await importOriginal();
|
|
153
|
+
const wrapped = { ...actual };
|
|
154
|
+
for (const name of promptNames) {
|
|
155
|
+
if (name in actual) {
|
|
156
|
+
wrapped[name] = wrapPrompt(actual[name]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return wrapped;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
95
164
|
});
|
|
96
165
|
// Mock the external editor to capture typed input instead of spawning a real editor.
|
|
97
166
|
// Buffers all screen.type() calls and submits on screen.keypress('enter'), matching
|
|
98
167
|
// the interaction pattern of other prompts (type → enter).
|
|
99
|
-
vi.mock('@inquirer/external-editor', () =>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
168
|
+
vi.mock('@inquirer/external-editor', async (importOriginal) => {
|
|
169
|
+
try {
|
|
170
|
+
await importOriginal();
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
editAsync: (_text, callback) => {
|
|
177
|
+
let buffer = '';
|
|
178
|
+
const typeSpy = vi
|
|
179
|
+
.spyOn(screenInstance, 'type')
|
|
180
|
+
.mockImplementation((text) => {
|
|
181
|
+
buffer += text;
|
|
182
|
+
});
|
|
183
|
+
const keypressSpy = vi
|
|
184
|
+
.spyOn(screenInstance, 'keypress')
|
|
185
|
+
.mockImplementation((key) => {
|
|
186
|
+
const name = typeof key === 'string' ? key : key.name;
|
|
187
|
+
if (name === 'enter' || name === 'return') {
|
|
188
|
+
typeSpy.mockRestore();
|
|
189
|
+
keypressSpy.mockRestore();
|
|
190
|
+
process.nextTick(() => callback(undefined, buffer));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
});
|
|
117
196
|
// Re-export Screen class and KeypressEvent type for advanced use cases
|
|
118
197
|
export { Screen } from './screen.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inquirer/testing",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Inquirer testing utilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"answer",
|
|
@@ -84,15 +84,15 @@
|
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@inquirer/type": "^4.0.3",
|
|
87
|
-
"@xterm/headless": "^
|
|
87
|
+
"@xterm/headless": "^6.0.0",
|
|
88
88
|
"mute-stream": "^3.0.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
|
-
"@types/jest": "^
|
|
91
|
+
"@types/jest": "^30.0.0",
|
|
92
92
|
"@types/mute-stream": "^0.0.4",
|
|
93
93
|
"@types/node": "^25.0.2",
|
|
94
94
|
"typescript": "^5.9.3",
|
|
95
|
-
"vitest": "^
|
|
95
|
+
"vitest": "^4.0.18"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
98
|
"@inquirer/checkbox": ">=1.0.0",
|
|
@@ -167,5 +167,5 @@
|
|
|
167
167
|
},
|
|
168
168
|
"main": "./dist/index.js",
|
|
169
169
|
"types": "./dist/index.d.ts",
|
|
170
|
-
"gitHead": "
|
|
170
|
+
"gitHead": "526eca2e64853510821ffd457561840ec0cbfb93"
|
|
171
171
|
}
|