@keber/qa-framework 1.1.0 → 1.1.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/init.js +25 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keber/qa-framework",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Reusable spec-driven QA framework for IDE-agent-assisted automated testing. Installable as an npm package. Provides structure, templates, agent instructions, and optional integrations for Playwright and Azure DevOps.",
5
5
  "keywords": [
6
6
  "qa",
package/scripts/init.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * scripts/init.js Scaffold qa/ folder structure from config
3
+ * scripts/init.js - Scaffold qa/ folder structure from config
4
4
  *
5
5
  * Usage:
6
6
  * qa-framework init
@@ -25,7 +25,9 @@ if (configFlag !== -1 && !args[configFlag + 1]) {
25
25
  process.exit(1);
26
26
  }
27
27
 
28
- const cwd = process.cwd();
28
+ // When run as postinstall, process.cwd() points to node_modules/@keber/qa-framework.
29
+ // INIT_CWD is set by npm to the directory where `npm install` was invoked (the project root).
30
+ const cwd = process.env.INIT_CWD || process.cwd();
29
31
  const explicitConfigPath = configFlag !== -1 ? path.resolve(cwd, args[configFlag + 1]) : null;
30
32
  const rootConfigPath = path.resolve(cwd, 'qa-framework.config.json');
31
33
  const qaConfigPath = path.resolve(cwd, 'qa', 'qa-framework.config.json');
@@ -50,7 +52,7 @@ if (explicitConfigPath) {
50
52
  } else {
51
53
  config = buildBootstrapConfig();
52
54
  configSource = 'generated defaults';
53
- console.log('[qa-framework/init] No config file found. Bootstrapping with default config.');
55
+ process.stderr.write('[qa-framework/init] No config file found. Bootstrapping with default config.\n');
54
56
  }
55
57
 
56
58
  const qaRoot = path.resolve(cwd, config.conventions?.qaRoot ?? 'qa');
@@ -58,7 +60,7 @@ const localConfigPath = path.join(qaRoot, 'qa-framework.config.json');
58
60
 
59
61
  // --skip-if-exists: bail out silently when qa/ is already initialised
60
62
  if (skipIfExists && fs.existsSync(localConfigPath)) {
61
- console.log('[qa-framework/init] qa/ already initialised skipping (postinstall).');
63
+ process.stderr.write('[qa-framework/init] qa/ already initialised - skipping (postinstall).\n');
62
64
  process.exit(0);
63
65
  }
64
66
 
@@ -67,11 +69,11 @@ if (!fs.existsSync(localConfigPath)) {
67
69
  fs.writeFileSync(localConfigPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
68
70
  console.log(` [created] ${path.relative(cwd, localConfigPath)}`);
69
71
  } else {
70
- console.log(` [exists] ${path.relative(cwd, localConfigPath)} skipped`);
72
+ console.log(` [exists] ${path.relative(cwd, localConfigPath)} - skipped`);
71
73
  }
72
74
 
73
- console.log(`[qa-framework/init] Scaffolding qa/ at: ${qaRoot}`);
74
- console.log(`[qa-framework/init] Using config source: ${configSource}`);
75
+ process.stderr.write(`[qa-framework/init] Scaffolding qa/ at: ${qaRoot}\n`);
76
+ process.stderr.write(`[qa-framework/init] Using config source: ${configSource}\n`);
75
77
 
76
78
  // --- Top-level folders ---
77
79
  const topLevelFolders = [
@@ -87,7 +89,7 @@ const topLevelFolders = [
87
89
  for (const folder of topLevelFolders) {
88
90
  const fullPath = path.join(qaRoot, folder);
89
91
  fs.mkdirSync(fullPath, { recursive: true });
90
- console.log(` [created] ${path.relative(process.cwd(), fullPath)}/`);
92
+ console.log(` [created] ${path.relative(cwd, fullPath)}/`);
91
93
  }
92
94
 
93
95
  // --- Standards placeholder ---
@@ -138,9 +140,9 @@ for (const mod of modules) {
138
140
  } else {
139
141
  fs.writeFileSync(dest, `# ${specFile}\n\n> Auto-generated placeholder\n`, 'utf8');
140
142
  }
141
- console.log(` [created] ${path.relative(process.cwd(), dest)}`);
143
+ console.log(` [created] ${path.relative(cwd, dest)}`);
142
144
  } else {
143
- console.log(` [exists] ${path.relative(process.cwd(), dest)} skipped`);
145
+ console.log(` [exists] ${path.relative(cwd, dest)} - skipped`);
144
146
  }
145
147
  }
146
148
 
@@ -150,7 +152,7 @@ for (const mod of modules) {
150
152
  const specTs = path.join(e2eDir, `${subKey}.spec.ts`);
151
153
  if (!fs.existsSync(specTs)) {
152
154
  fs.writeFileSync(specTs, specScaffold(mod.name, sub.name, moduleKey, subKey), 'utf8');
153
- console.log(` [created] ${path.relative(process.cwd(), specTs)}`);
155
+ console.log(` [created] ${path.relative(cwd, specTs)}`);
154
156
  }
155
157
  }
156
158
  }
@@ -162,7 +164,7 @@ for (const file of ['playwright.config.ts', 'global-setup.ts', '.env.example', '
162
164
  const dest = path.join(automationDir, file);
163
165
  if (!fs.existsSync(dest)) {
164
166
  fs.copyFileSync(path.join(scaffoldSrc, file), dest);
165
- console.log(` [created] ${path.relative(process.cwd(), dest)}`);
167
+ console.log(` [created] ${path.relative(cwd, dest)}`);
166
168
  }
167
169
  }
168
170
  const fixturesDir = path.join(automationDir, 'fixtures');
@@ -171,7 +173,7 @@ for (const file of ['auth.ts', 'test-helpers.ts']) {
171
173
  const dest = path.join(fixturesDir, file);
172
174
  if (!fs.existsSync(dest)) {
173
175
  fs.copyFileSync(path.join(scaffoldSrc, 'fixtures', file), dest);
174
- console.log(` [created] ${path.relative(process.cwd(), dest)}`);
176
+ console.log(` [created] ${path.relative(cwd , dest)}`);
175
177
  }
176
178
  }
177
179
 
@@ -246,8 +248,8 @@ This project uses \`@keber/qa-framework\` v${config.frameworkVersion ?? '1.0.0'}
246
248
  ## Agent behavior rules
247
249
 
248
250
  1. Before performing any QA task, read the relevant instruction file from \`qa/00-guides/\`
249
- 2. Always save artifacts in the correct \`qa/\` subfolder refer to \`qa/QA-STRUCTURE-GUIDE.md\`
250
- 3. Never hardcode credentials always use env vars and \`<PLACEHOLDER>\` in documentation
251
+ 2. Always save artifacts in the correct \`qa/\` subfolder - refer to \`qa/QA-STRUCTURE-GUIDE.md\`
252
+ 3. Never hardcode credentials - always use env vars and \`<PLACEHOLDER>\` in documentation
251
253
  4. Follow the naming conventions in \`qa/00-standards/naming-conventions.md\`
252
254
  5. Project QA config is at \`qa/qa-framework.config.json\`
253
255
 
@@ -266,12 +268,13 @@ This project uses \`@keber/qa-framework\` v${config.frameworkVersion ?? '1.0.0'}
266
268
  `;
267
269
  writeIfMissing(copilotInstrPath, copilotInstrContent);
268
270
 
269
- console.log('\n[qa-framework/init] Done!\n');
270
- console.log('Next steps:');
271
- console.log(' 1. Copy qa/07-automation/.env.example to qa/07-automation/.env and fill in credentials');
272
- console.log(' 2. Add qa/07-automation/.env and qa/07-automation/.auth/ to .gitignore');
273
- console.log(' 3. Run: cd qa/07-automation && npm install && npx playwright install chromium');
274
- console.log(' 4. Start filling in spec files with your module\'s real data');
271
+ process.stderr.write('\n[qa-framework/init] ✅ QA framework scaffold complete!\n');
272
+ process.stderr.write('\nNext steps for the agent:\n');
273
+ process.stderr.write(' 1. If ADO integration is needed, run: npm install @keber/ado-qa\n');
274
+ process.stderr.write(' 2. If Playwright automation is needed, run: npm install @playwright/test\n');
275
+ process.stderr.write(' 3. Edit qa/qa-framework.config.json - add your project modules\n');
276
+ process.stderr.write(' 4. Copy qa/07-automation/.env.example -> qa/07-automation/.env and fill in credentials\n');
277
+ process.stderr.write(' 5. Add qa/07-automation/.env and qa/07-automation/.auth/ to .gitignore\n');
275
278
 
276
279
  // -----------------------------------------------------------------------
277
280
  // Helpers
@@ -280,7 +283,7 @@ function writeIfMissing(filePath, content) {
280
283
  if (!fs.existsSync(filePath)) {
281
284
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
282
285
  fs.writeFileSync(filePath, content, 'utf8');
283
- console.log(` [created] ${path.relative(process.cwd(), filePath)}`);
286
+ console.log(` [created] ${path.relative(cwd, filePath)}`);
284
287
  }
285
288
  }
286
289