@inquirer/testing 3.1.1 → 3.2.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/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>): 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 = prompt(config, {
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
- // Mock individual prompt packages (covers `import input from '@inquirer/input'` style)
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
- const actual = jest.requireActual('@inquirer/input');
39
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/select');
43
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/confirm');
47
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/checkbox');
51
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/password');
55
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/expand');
59
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/rawlist');
63
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/number');
67
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/search');
71
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/editor');
75
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = jest.requireActual('@inquirer/prompts');
81
- return {
82
- ...actual,
83
- input: wrapPrompt(actual.input),
84
- select: wrapPrompt(actual.select),
85
- confirm: wrapPrompt(actual.confirm),
86
- checkbox: wrapPrompt(actual.checkbox),
87
- password: wrapPrompt(actual.password),
88
- expand: wrapPrompt(actual.expand),
89
- rawlist: wrapPrompt(actual.rawlist),
90
- number: wrapPrompt(actual.number),
91
- search: wrapPrompt(actual.search),
92
- editor: wrapPrompt(actual.editor),
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
- editAsync: (_text, callback) => {
100
- let buffer = '';
101
- const typeSpy = jest
102
- .spyOn(screenInstance, 'type')
103
- .mockImplementation((text) => {
104
- buffer += text;
105
- });
106
- const keypressSpy = jest
107
- .spyOn(screenInstance, 'keypress')
108
- .mockImplementation((key) => {
109
- const name = typeof key === 'string' ? key : key.name;
110
- if (name === 'enter' || name === 'return') {
111
- typeSpy.mockRestore();
112
- keypressSpy.mockRestore();
113
- process.nextTick(() => callback(undefined, buffer));
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>): 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 = prompt(config, {
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
- // Mock individual prompt packages (covers `import input from '@inquirer/input'` style)
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
- const actual = await importOriginal();
39
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
43
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
47
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
51
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
55
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
59
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
63
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
67
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
71
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
75
- return { ...actual, default: wrapPrompt(actual.default) };
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
- const actual = await importOriginal();
82
- return {
83
- ...actual,
84
- input: wrapPrompt(actual.input),
85
- select: wrapPrompt(actual.select),
86
- confirm: wrapPrompt(actual.confirm),
87
- checkbox: wrapPrompt(actual.checkbox),
88
- password: wrapPrompt(actual.password),
89
- expand: wrapPrompt(actual.expand),
90
- rawlist: wrapPrompt(actual.rawlist),
91
- number: wrapPrompt(actual.number),
92
- search: wrapPrompt(actual.search),
93
- editor: wrapPrompt(actual.editor),
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
- editAsync: (_text, callback) => {
101
- let buffer = '';
102
- const typeSpy = vi
103
- .spyOn(screenInstance, 'type')
104
- .mockImplementation((text) => {
105
- buffer += text;
106
- });
107
- const keypressSpy = vi.spyOn(screenInstance, 'keypress').mockImplementation((key) => {
108
- const name = typeof key === 'string' ? key : key.name;
109
- if (name === 'enter' || name === 'return') {
110
- typeSpy.mockRestore();
111
- keypressSpy.mockRestore();
112
- process.nextTick(() => callback(undefined, buffer));
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.1.1",
3
+ "version": "3.2.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": "^5.5.0",
87
+ "@xterm/headless": "^6.0.0",
88
88
  "mute-stream": "^3.0.0"
89
89
  },
90
90
  "devDependencies": {
91
- "@types/jest": "^29.5.0",
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": "^3.0.0"
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": "48b5d7e8b14d5c9fc4a19a8f1ead20a7593b29e1"
170
+ "gitHead": "fd001c191cfb287b430d5e90cb159cf8f6500dc5"
171
171
  }