@keber/qa-framework 1.1.1 → 1.1.3

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 CHANGED
@@ -28,27 +28,38 @@ This framework was designed to be:
28
28
 
29
29
  ## Quick Start
30
30
 
31
- ### Option A: Install from npm (recommended)
31
+ ### Install from npm
32
32
 
33
33
  ```bash
34
- npm install --save-dev github:keber/qa-framework
35
- npx qa-framework init
34
+ npm install @keber/qa-framework
36
35
  ```
37
36
 
38
- ### Option B: Clone directly (during early adoption)
37
+ The postinstall script scaffolds the `qa/` structure automatically. No need to run `init` manually.
38
+
39
+ ### Using with an AI agent (GitHub Copilot, Claude, etc.)
40
+
41
+ Use this prompt in your IDE agent chat:
42
+
43
+ ```
44
+ Install @keber/qa-framework and set up the project following qa/AGENT-NEXT-STEPS.md
45
+ ```
46
+
47
+ The install creates `qa/AGENT-NEXT-STEPS.md` with the exact steps the agent needs to complete the setup (optional integrations, module configuration, credentials, etc.).
48
+
49
+ ### Using manually (without an agent)
39
50
 
40
51
  ```bash
41
- # Clone into your project's tools directory or as a submodule
42
- git clone <this-repo> tools/qa-framework
43
- node tools/qa-framework/scripts/cli.js init
52
+ npm install @keber/qa-framework
53
+ # then read qa/AGENT-NEXT-STEPS.md for next steps
44
54
  ```
45
55
 
46
56
  The `init` command will:
47
57
 
48
58
  1. Create the `qa/` directory tree in your project root
49
- 2. Copy all base templates into place
59
+ 2. Copy all base templates and agent instructions into place
50
60
  3. Create `qa/qa-framework.config.json` for project-specific settings
51
- 4. Optionally set up Playwright and Azure DevOps integrations
61
+ 4. Create `.github/copilot-instructions.md` with QA agent behavior rules
62
+ 5. Create `qa/AGENT-NEXT-STEPS.md` with follow-up steps
52
63
 
53
64
  ---
54
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keber/qa-framework",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
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
@@ -52,7 +52,7 @@ if (explicitConfigPath) {
52
52
  } else {
53
53
  config = buildBootstrapConfig();
54
54
  configSource = 'generated defaults';
55
- 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');
56
56
  }
57
57
 
58
58
  const qaRoot = path.resolve(cwd, config.conventions?.qaRoot ?? 'qa');
@@ -60,7 +60,7 @@ const localConfigPath = path.join(qaRoot, 'qa-framework.config.json');
60
60
 
61
61
  // --skip-if-exists: bail out silently when qa/ is already initialised
62
62
  if (skipIfExists && fs.existsSync(localConfigPath)) {
63
- console.log('[qa-framework/init] qa/ already initialised skipping (postinstall).');
63
+ process.stderr.write('[qa-framework/init] qa/ already initialised - skipping (postinstall).\n');
64
64
  process.exit(0);
65
65
  }
66
66
 
@@ -69,11 +69,11 @@ if (!fs.existsSync(localConfigPath)) {
69
69
  fs.writeFileSync(localConfigPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
70
70
  console.log(` [created] ${path.relative(cwd, localConfigPath)}`);
71
71
  } else {
72
- console.log(` [exists] ${path.relative(cwd, localConfigPath)} skipped`);
72
+ console.log(` [exists] ${path.relative(cwd, localConfigPath)} - skipped`);
73
73
  }
74
74
 
75
- console.log(`[qa-framework/init] Scaffolding qa/ at: ${qaRoot}`);
76
- 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`);
77
77
 
78
78
  // --- Top-level folders ---
79
79
  const topLevelFolders = [
@@ -89,7 +89,7 @@ const topLevelFolders = [
89
89
  for (const folder of topLevelFolders) {
90
90
  const fullPath = path.join(qaRoot, folder);
91
91
  fs.mkdirSync(fullPath, { recursive: true });
92
- console.log(` [created] ${path.relative(process.cwd(), fullPath)}/`);
92
+ console.log(` [created] ${path.relative(cwd, fullPath)}/`);
93
93
  }
94
94
 
95
95
  // --- Standards placeholder ---
@@ -140,9 +140,9 @@ for (const mod of modules) {
140
140
  } else {
141
141
  fs.writeFileSync(dest, `# ${specFile}\n\n> Auto-generated placeholder\n`, 'utf8');
142
142
  }
143
- console.log(` [created] ${path.relative(process.cwd(), dest)}`);
143
+ console.log(` [created] ${path.relative(cwd, dest)}`);
144
144
  } else {
145
- console.log(` [exists] ${path.relative(process.cwd(), dest)} skipped`);
145
+ console.log(` [exists] ${path.relative(cwd, dest)} - skipped`);
146
146
  }
147
147
  }
148
148
 
@@ -152,7 +152,7 @@ for (const mod of modules) {
152
152
  const specTs = path.join(e2eDir, `${subKey}.spec.ts`);
153
153
  if (!fs.existsSync(specTs)) {
154
154
  fs.writeFileSync(specTs, specScaffold(mod.name, sub.name, moduleKey, subKey), 'utf8');
155
- console.log(` [created] ${path.relative(process.cwd(), specTs)}`);
155
+ console.log(` [created] ${path.relative(cwd, specTs)}`);
156
156
  }
157
157
  }
158
158
  }
@@ -164,7 +164,7 @@ for (const file of ['playwright.config.ts', 'global-setup.ts', '.env.example', '
164
164
  const dest = path.join(automationDir, file);
165
165
  if (!fs.existsSync(dest)) {
166
166
  fs.copyFileSync(path.join(scaffoldSrc, file), dest);
167
- console.log(` [created] ${path.relative(process.cwd(), dest)}`);
167
+ console.log(` [created] ${path.relative(cwd, dest)}`);
168
168
  }
169
169
  }
170
170
  const fixturesDir = path.join(automationDir, 'fixtures');
@@ -173,7 +173,7 @@ for (const file of ['auth.ts', 'test-helpers.ts']) {
173
173
  const dest = path.join(fixturesDir, file);
174
174
  if (!fs.existsSync(dest)) {
175
175
  fs.copyFileSync(path.join(scaffoldSrc, 'fixtures', file), dest);
176
- console.log(` [created] ${path.relative(process.cwd(), dest)}`);
176
+ console.log(` [created] ${path.relative(cwd , dest)}`);
177
177
  }
178
178
  }
179
179
 
@@ -247,9 +247,10 @@ This project uses \`@keber/qa-framework\` v${config.frameworkVersion ?? '1.0.0'}
247
247
 
248
248
  ## Agent behavior rules
249
249
 
250
+ 0. **On every conversation start:** check if \`qa/AGENT-NEXT-STEPS.md\` exists. If it does, read it and complete its steps before anything else.
250
251
  1. Before performing any QA task, read the relevant instruction file from \`qa/00-guides/\`
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
252
+ 2. Always save artifacts in the correct \`qa/\` subfolder - refer to \`qa/QA-STRUCTURE-GUIDE.md\`
253
+ 3. Never hardcode credentials - always use env vars and \`<PLACEHOLDER>\` in documentation
253
254
  4. Follow the naming conventions in \`qa/00-standards/naming-conventions.md\`
254
255
  5. Project QA config is at \`qa/qa-framework.config.json\`
255
256
 
@@ -268,12 +269,42 @@ This project uses \`@keber/qa-framework\` v${config.frameworkVersion ?? '1.0.0'}
268
269
  `;
269
270
  writeIfMissing(copilotInstrPath, copilotInstrContent);
270
271
 
271
- console.log('\n[qa-framework/init] Done!\n');
272
- console.log('Next steps:');
273
- console.log(' 1. Copy qa/07-automation/.env.example to qa/07-automation/.env and fill in credentials');
274
- console.log(' 2. Add qa/07-automation/.env and qa/07-automation/.auth/ to .gitignore');
275
- console.log(' 3. Run: cd qa/07-automation && npm install && npx playwright install chromium');
276
- console.log(' 4. Start filling in spec files with your module\'s real data');
272
+ // --- AGENT-NEXT-STEPS.md — readable by the agent after install ---
273
+ const nextStepsContent = `# ✅ @keber/qa-framework installed successfully
274
+
275
+ > This file was generated automatically by the postinstall script.
276
+ > Read it and follow the steps below, then delete this file.
277
+
278
+ ## What was scaffolded
279
+
280
+ - \`qa/\` folder structure with spec templates and agent instructions
281
+ - \`.github/copilot-instructions.md\` with QA agent behavior rules
282
+
283
+ ## Required next steps
284
+
285
+ ### 1. Configure your project modules
286
+ Edit \`qa/qa-framework.config.json\` and add your project modules under the \`"modules"\` array.
287
+
288
+ ### 2. Optional integrations
289
+
290
+ **Azure DevOps integration:**
291
+ \`\`\`bash
292
+ npm install @keber/ado-qa
293
+ \`\`\`
294
+
295
+ **Playwright automation:**
296
+ \`\`\`bash
297
+ npm install @playwright/test
298
+ cd qa/07-automation && npm install && npx playwright install chromium
299
+ \`\`\`
300
+
301
+ ### 3. Credentials
302
+ - Copy \`qa/07-automation/.env.example\` → \`qa/07-automation/.env\` and fill in credentials
303
+ - Add \`qa/07-automation/.env\` and \`qa/07-automation/.auth/\` to \`.gitignore\`
304
+ `;
305
+ const nextStepsPath = path.join(qaRoot, 'AGENT-NEXT-STEPS.md');
306
+ fs.writeFileSync(nextStepsPath, nextStepsContent, 'utf8');
307
+ console.log(` [created] ${path.relative(cwd, nextStepsPath)}`);
277
308
 
278
309
  // -----------------------------------------------------------------------
279
310
  // Helpers
@@ -282,7 +313,7 @@ function writeIfMissing(filePath, content) {
282
313
  if (!fs.existsSync(filePath)) {
283
314
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
284
315
  fs.writeFileSync(filePath, content, 'utf8');
285
- console.log(` [created] ${path.relative(process.cwd(), filePath)}`);
316
+ console.log(` [created] ${path.relative(cwd, filePath)}`);
286
317
  }
287
318
  }
288
319