@toolstackhq/create-qa-patterns 1.0.2 → 1.0.4

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.
Files changed (3) hide show
  1. package/README.md +11 -0
  2. package/index.js +129 -10
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -41,3 +41,14 @@ When run in a terminal, the CLI shows:
41
41
  - `npm install`
42
42
  - `npx playwright install`
43
43
  - `npm test`
44
+
45
+ ## Prerequisite checks
46
+
47
+ The CLI checks:
48
+
49
+ - required Node.js version
50
+ - `npm` availability for install and test actions
51
+ - `npx` availability for Playwright browser installation
52
+ - `docker` availability and warns if it is missing
53
+
54
+ If `npx playwright install` fails because the host is missing browser dependencies, the CLI keeps the generated project and prints the recovery steps instead of treating scaffold generation as failed.
package/index.js CHANGED
@@ -3,9 +3,14 @@
3
3
  const fs = require("node:fs");
4
4
  const path = require("node:path");
5
5
  const readline = require("node:readline");
6
- const { spawn } = require("node:child_process");
6
+ const { spawn, spawnSync } = require("node:child_process");
7
7
 
8
8
  const DEFAULT_TEMPLATE = "playwright-template";
9
+ const MIN_NODE_VERSION = {
10
+ major: 18,
11
+ minor: 18,
12
+ patch: 0
13
+ };
9
14
  const DEFAULT_GITIGNORE = `node_modules/
10
15
 
11
16
  .env
@@ -53,6 +58,39 @@ Supported templates:
53
58
  `);
54
59
  }
55
60
 
61
+ function parseNodeVersion(version) {
62
+ const normalized = version.replace(/^v/, "");
63
+ const [major = "0", minor = "0", patch = "0"] = normalized.split(".");
64
+
65
+ return {
66
+ major: Number.parseInt(major, 10),
67
+ minor: Number.parseInt(minor, 10),
68
+ patch: Number.parseInt(patch, 10)
69
+ };
70
+ }
71
+
72
+ function isNodeVersionSupported(version) {
73
+ if (version.major !== MIN_NODE_VERSION.major) {
74
+ return version.major > MIN_NODE_VERSION.major;
75
+ }
76
+
77
+ if (version.minor !== MIN_NODE_VERSION.minor) {
78
+ return version.minor > MIN_NODE_VERSION.minor;
79
+ }
80
+
81
+ return version.patch >= MIN_NODE_VERSION.patch;
82
+ }
83
+
84
+ function assertSupportedNodeVersion() {
85
+ const currentVersion = parseNodeVersion(process.version);
86
+
87
+ if (!isNodeVersionSupported(currentVersion)) {
88
+ throw new Error(
89
+ `Node ${MIN_NODE_VERSION.major}.${MIN_NODE_VERSION.minor}.${MIN_NODE_VERSION.patch}+ is required. Current version: ${process.version}`
90
+ );
91
+ }
92
+ }
93
+
56
94
  function resolveTemplate(value) {
57
95
  return TEMPLATE_ALIASES.get(value);
58
96
  }
@@ -65,6 +103,40 @@ function sleep(ms) {
65
103
  return new Promise((resolve) => setTimeout(resolve, ms));
66
104
  }
67
105
 
106
+ function commandExists(command) {
107
+ const result = spawnSync(getCommandName(command), ["--version"], {
108
+ stdio: "ignore"
109
+ });
110
+
111
+ return !result.error && result.status === 0;
112
+ }
113
+
114
+ function collectPrerequisites() {
115
+ return {
116
+ npm: commandExists("npm"),
117
+ npx: commandExists("npx"),
118
+ docker: commandExists("docker")
119
+ };
120
+ }
121
+
122
+ function printPrerequisiteWarnings(prerequisites) {
123
+ if (!prerequisites.npm) {
124
+ process.stdout.write("Warning: npm was not found. Automated install and test steps will be unavailable.\n");
125
+ }
126
+
127
+ if (!prerequisites.npx) {
128
+ process.stdout.write("Warning: npx was not found. Playwright browser installation will be unavailable.\n");
129
+ }
130
+
131
+ if (!prerequisites.docker) {
132
+ process.stdout.write("Warning: docker was not found. Docker-based template flows will not run until Docker is installed.\n");
133
+ }
134
+
135
+ if (!prerequisites.npm || !prerequisites.npx || !prerequisites.docker) {
136
+ process.stdout.write("\n");
137
+ }
138
+ }
139
+
68
140
  function createLineInterface() {
69
141
  return readline.createInterface({
70
142
  input: process.stdin,
@@ -372,6 +444,26 @@ function getCommandName(base) {
372
444
  return base;
373
445
  }
374
446
 
447
+ function printPlaywrightInstallRecovery(targetDirectory) {
448
+ process.stdout.write(`
449
+ Playwright browser installation did not complete.
450
+
451
+ Common cause:
452
+ Missing OS packages required to run Playwright browsers.
453
+
454
+ Recommended next steps:
455
+ cd ${path.relative(process.cwd(), targetDirectory) || "."}
456
+ sudo npx playwright install-deps
457
+ npx playwright install
458
+
459
+ If you already know the missing package name, install it with your system package manager and then rerun:
460
+ npx playwright install
461
+
462
+ The template was generated successfully. You can complete browser setup later.
463
+
464
+ `);
465
+ }
466
+
375
467
  function runCommand(command, args, cwd) {
376
468
  return new Promise((resolve, reject) => {
377
469
  const child = spawn(getCommandName(command), args, {
@@ -421,34 +513,61 @@ async function runPostGenerateActions(targetDirectory) {
421
513
  return;
422
514
  }
423
515
 
424
- const shouldInstallDependencies = await askYesNo("Run npm install now?", true);
516
+ const prerequisites = collectPrerequisites();
425
517
 
426
- if (shouldInstallDependencies) {
427
- await runCommand("npm", ["install"], targetDirectory);
518
+ if (prerequisites.npm) {
519
+ const shouldInstallDependencies = await askYesNo("Run npm install now?", true);
520
+
521
+ if (shouldInstallDependencies) {
522
+ await runCommand("npm", ["install"], targetDirectory);
523
+ }
524
+ } else {
525
+ process.stdout.write("Skipping npm install prompt because npm is not available.\n");
428
526
  }
429
527
 
430
- const shouldInstallPlaywright = await askYesNo("Run npx playwright install now?", true);
528
+ if (prerequisites.npx) {
529
+ const shouldInstallPlaywright = await askYesNo("Run npx playwright install now?", true);
530
+
531
+ if (shouldInstallPlaywright) {
532
+ try {
533
+ await runCommand("npx", ["playwright", "install"], targetDirectory);
534
+ } catch (error) {
535
+ printPlaywrightInstallRecovery(targetDirectory);
431
536
 
432
- if (shouldInstallPlaywright) {
433
- await runCommand("npx", ["playwright", "install"], targetDirectory);
537
+ const shouldContinue = await askYesNo("Continue without completing Playwright browser install?", true);
538
+
539
+ if (!shouldContinue) {
540
+ throw error;
541
+ }
542
+ }
543
+ }
544
+ } else {
545
+ process.stdout.write("Skipping Playwright browser install prompt because npx is not available.\n");
434
546
  }
435
547
 
436
- const shouldRunTests = await askYesNo("Run npm test now?", false);
548
+ if (prerequisites.npm) {
549
+ const shouldRunTests = await askYesNo("Run npm test now?", false);
437
550
 
438
- if (shouldRunTests) {
439
- await runCommand("npm", ["test"], targetDirectory);
551
+ if (shouldRunTests) {
552
+ await runCommand("npm", ["test"], targetDirectory);
553
+ }
554
+ } else {
555
+ process.stdout.write("Skipping npm test prompt because npm is not available.\n");
440
556
  }
441
557
  }
442
558
 
443
559
  async function main() {
444
560
  const args = process.argv.slice(2);
445
561
 
562
+ assertSupportedNodeVersion();
563
+
446
564
  if (args.includes("--help") || args.includes("-h")) {
447
565
  printHelp();
448
566
  return;
449
567
  }
450
568
 
451
569
  const { templateName, targetDirectory, generatedInCurrentDirectory } = await resolveScaffoldArgs(args);
570
+ printPrerequisiteWarnings(collectPrerequisites());
452
571
  await scaffoldProject(templateName, targetDirectory);
453
572
  printSuccess(templateName, targetDirectory, generatedInCurrentDirectory);
454
573
  await runPostGenerateActions(targetDirectory);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolstackhq/create-qa-patterns",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "CLI for generating QA framework templates.",
5
5
  "license": "MIT",
6
6
  "repository": {