testronaut 2.0.0 → 2.0.1

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/bin/cli.js CHANGED
@@ -76,6 +76,18 @@ const CLI_VERSION = JSON.parse(
76
76
 
77
77
  const DEFAULT_API_BASE = 'https://api.testronaut.app';
78
78
  const DEV_API_BASE = 'https://staging.api.testronaut.app';
79
+ const PLAYWRIGHT_INSTALL_PROMPT = {
80
+ type: 'confirm',
81
+ name: 'doPw',
82
+ message: 'Install Playwright browsers now?',
83
+ default: true,
84
+ };
85
+ const API_KEY_PROMPT = {
86
+ type: 'password',
87
+ name: 'apiKey',
88
+ message: 'Enter your API key:',
89
+ mask: '*',
90
+ };
79
91
 
80
92
  let args = process.argv.slice(2);
81
93
 
@@ -138,6 +150,14 @@ function isDirectInvocation(argv1 = process.argv[1], moduleUrl = import.meta.url
138
150
  }
139
151
  }
140
152
 
153
+ function isPromptExitError(error) {
154
+ return error instanceof Error && error.name === 'ExitPromptError';
155
+ }
156
+
157
+ function formatCliError(error) {
158
+ return error instanceof Error ? error.message : String(error);
159
+ }
160
+
141
161
  const cliName = detectCliName();
142
162
 
143
163
  // Look for --dev / --developer / --developer-mode / --staging
@@ -367,6 +387,8 @@ export const __test__ = {
367
387
  parseOptimizationArgs,
368
388
  detectCliName,
369
389
  isDirectInvocation,
390
+ isPromptExitError,
391
+ formatCliError,
370
392
  resolveMissionPath,
371
393
  collectReportScreenshotNames,
372
394
  collectReportScreenshotPaths,
@@ -374,6 +396,8 @@ export const __test__ = {
374
396
  closestMissionMatch,
375
397
  resolveReportFile,
376
398
  buildEffectiveConfig,
399
+ PLAYWRIGHT_INSTALL_PROMPT,
400
+ API_KEY_PROMPT,
377
401
  };
378
402
 
379
403
  function resolveReportDir(config = {}, cwd = process.cwd()) {
@@ -893,9 +917,7 @@ if (args.includes('--init')) {
893
917
  await createWelcomeMission();
894
918
 
895
919
  const { default: inquirer } = await import('inquirer');
896
- const { doPw } = await inquirer.prompt([
897
- { type: 'confirm', name: 'doPw', message: 'Install Playwright browsers now?', default: true }
898
- ]);
920
+ const { doPw } = await inquirer.prompt([PLAYWRIGHT_INSTALL_PROMPT]);
899
921
 
900
922
  if (doPw) {
901
923
  // ensure @playwright/test exists so the installer can pin to its version
@@ -1438,14 +1460,7 @@ async function handleLogin() {
1438
1460
 
1439
1461
  // If API key is not provided, prompt the user for it
1440
1462
  if (!apiKey) {
1441
- const responses = await inquirer.prompt([
1442
- {
1443
- type: 'password',
1444
- name: 'apiKey',
1445
- message: 'Enter your API key:',
1446
- mask: '*'
1447
- }
1448
- ]);
1463
+ const responses = await inquirer.prompt([API_KEY_PROMPT]);
1449
1464
  apiKey = responses.apiKey;
1450
1465
  }
1451
1466
 
@@ -1487,7 +1502,7 @@ async function handleLogin() {
1487
1502
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
1488
1503
  console.log('✅ Login successful! Session token saved to testronaut-config.json.');
1489
1504
  } catch (error) {
1490
- console.error('❌ Error during login:', error);
1505
+ console.error('❌ Error during login:', formatCliError(error));
1491
1506
  process.exit(1);
1492
1507
  }
1493
1508
  }
@@ -1845,5 +1860,14 @@ async function serveLatestReport() {
1845
1860
  }
1846
1861
 
1847
1862
  if (isDirectInvocation()) {
1848
- await main();
1863
+ try {
1864
+ await main();
1865
+ } catch (error) {
1866
+ if (isPromptExitError(error)) {
1867
+ console.error('Prompt cancelled.');
1868
+ process.exitCode = 130;
1869
+ } else {
1870
+ throw error;
1871
+ }
1872
+ }
1849
1873
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testronaut",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "main": "./runner/testronaut.js",
5
5
  "bin": {
6
6
  "testronaut": "bin/cli.js"
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "type": "module",
14
14
  "engines": {
15
- "node": ">=20"
15
+ "node": ">=20.17.0"
16
16
  },
17
17
  "scripts": {
18
18
  "benchmark:optimization": "node ./experiments/optimizationBenchmark.js",
@@ -37,7 +37,7 @@
37
37
  "cheerio": "^1.1.0",
38
38
  "dotenv": "^17.2.0",
39
39
  "fast-glob": "^3.3.3",
40
- "inquirer": "^12.9.1",
40
+ "inquirer": "^14.2.2",
41
41
  "jiti": "^2.7.0",
42
42
  "node-fetch": "^3.3.2",
43
43
  "openai": "^6.39.0",
@@ -22,6 +22,40 @@ describe('cli helpers', () => {
22
22
  expect(__test__.DEFAULT_API_BASE).toBe('https://api.testronaut.app');
23
23
  });
24
24
 
25
+ it('keeps interactive prompt contracts compatible with Inquirer 14', () => {
26
+ expect(__test__.PLAYWRIGHT_INSTALL_PROMPT).toEqual({
27
+ type: 'confirm',
28
+ name: 'doPw',
29
+ message: 'Install Playwright browsers now?',
30
+ default: true,
31
+ });
32
+ expect(__test__.API_KEY_PROMPT).toEqual({
33
+ type: 'password',
34
+ name: 'apiKey',
35
+ message: 'Enter your API key:',
36
+ mask: '*',
37
+ });
38
+ });
39
+
40
+ it('recognizes Inquirer prompt cancellation without swallowing other failures', () => {
41
+ const cancelled = new Error('User force closed the prompt with SIGINT');
42
+ cancelled.name = 'ExitPromptError';
43
+
44
+ expect(__test__.isPromptExitError(cancelled)).toBe(true);
45
+ expect(__test__.isPromptExitError(new Error('network failed'))).toBe(false);
46
+ expect(__test__.isPromptExitError({ name: 'ExitPromptError' })).toBe(false);
47
+ });
48
+
49
+ it('formats CLI errors without printing stack traces', () => {
50
+ const error = new Error('login 401 Unauthorized: {"error":"Invalid API key"}');
51
+
52
+ expect(__test__.formatCliError(error)).toBe(
53
+ 'login 401 Unauthorized: {"error":"Invalid API key"}',
54
+ );
55
+ expect(__test__.formatCliError(error)).not.toContain(' at ');
56
+ expect(__test__.formatCliError('request failed')).toBe('request failed');
57
+ });
58
+
25
59
  it('guessMimeType returns expected types', () => {
26
60
  const { guessMimeType } = __test__;
27
61
  expect(guessMimeType('file.html')).toContain('text/html');
@@ -7,9 +7,8 @@ const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'))
7
7
  const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
8
8
 
9
9
  describe('runtime dependency compatibility', () => {
10
- it('declares the Node runtime required by the installed Playwright version', () => {
10
+ it('records the Node runtime required by the installed Playwright version', () => {
11
11
  const playwright = lock.packages['node_modules/playwright'];
12
- expect(pkg.engines.node).toBe('>=20');
13
12
  expect(playwright.engines.node).toBe('>=20');
14
13
  });
15
14
 
@@ -19,4 +18,14 @@ describe('runtime dependency compatibility', () => {
19
18
  expect(lock.packages['node_modules/playwright'].version).toBe('1.63.0');
20
19
  expect(lock.packages['node_modules/playwright-core'].version).toBe('1.63.0');
21
20
  });
21
+
22
+ it('declares the minimum Node runtime required by Inquirer 14', () => {
23
+ const inquirer = lock.packages['node_modules/inquirer'];
24
+ expect(pkg.engines.node).toBe('>=20.17.0');
25
+ expect(lock.packages[''].engines.node).toBe(pkg.engines.node);
26
+ expect(pkg.dependencies.inquirer).toBe('^14.2.2');
27
+ expect(lock.packages[''].dependencies.inquirer).toBe(pkg.dependencies.inquirer);
28
+ expect(inquirer.version).toBe('14.2.2');
29
+ expect(inquirer.engines.node).toContain('^20.17.0');
30
+ });
22
31
  });