@keber/qa-framework 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 (51) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +233 -0
  3. package/agent-instructions/00-module-analysis.md +263 -0
  4. package/agent-instructions/01-spec-generation.md +278 -0
  5. package/agent-instructions/02-test-plan-generation.md +202 -0
  6. package/agent-instructions/03-test-case-generation.md +147 -0
  7. package/agent-instructions/04-automation-generation.md +310 -0
  8. package/agent-instructions/04b-test-stabilization.md +306 -0
  9. package/agent-instructions/05-ado-integration.md +244 -0
  10. package/agent-instructions/06-maintenance.md +125 -0
  11. package/docs/architecture.md +227 -0
  12. package/docs/comparison-matrix.md +131 -0
  13. package/docs/final-report.md +279 -0
  14. package/docs/folder-structure-guide.md +291 -0
  15. package/docs/generalization-decisions.md +203 -0
  16. package/docs/installation.md +239 -0
  17. package/docs/spec-driven-philosophy.md +170 -0
  18. package/docs/usage-with-agent.md +203 -0
  19. package/examples/module-example/README.md +34 -0
  20. package/examples/module-example/suppliers/00-inventory.md +56 -0
  21. package/examples/module-example/suppliers/suppliers-create.spec.ts +148 -0
  22. package/integrations/ado-powershell/README.md +75 -0
  23. package/integrations/ado-powershell/pipelines/azure-pipeline-qa.yml +133 -0
  24. package/integrations/ado-powershell/scripts/create-testplan-from-mapping.ps1 +114 -0
  25. package/integrations/ado-powershell/scripts/inject-ado-ids.ps1 +96 -0
  26. package/integrations/ado-powershell/scripts/sync-ado-titles.ps1 +93 -0
  27. package/integrations/playwright/README.md +68 -0
  28. package/integrations/playwright-azure-reporter/README.md +88 -0
  29. package/package.json +57 -0
  30. package/qa-framework.config.json +87 -0
  31. package/scripts/cli.js +74 -0
  32. package/scripts/generate.js +92 -0
  33. package/scripts/init.js +322 -0
  34. package/scripts/validate.js +184 -0
  35. package/templates/automation-scaffold/.env.example +56 -0
  36. package/templates/automation-scaffold/fixtures/auth.ts +77 -0
  37. package/templates/automation-scaffold/fixtures/test-helpers.ts +85 -0
  38. package/templates/automation-scaffold/global-setup.ts +106 -0
  39. package/templates/automation-scaffold/package.json +24 -0
  40. package/templates/automation-scaffold/playwright.config.ts +85 -0
  41. package/templates/defect-report.md +101 -0
  42. package/templates/execution-report.md +116 -0
  43. package/templates/session-summary.md +73 -0
  44. package/templates/specification/00-inventory.md +81 -0
  45. package/templates/specification/01-business-rules.md +90 -0
  46. package/templates/specification/02-workflows.md +114 -0
  47. package/templates/specification/03-roles-permissions.md +49 -0
  48. package/templates/specification/04-test-data.md +104 -0
  49. package/templates/specification/05-test-scenarios.md +226 -0
  50. package/templates/test-case.md +81 -0
  51. package/templates/test-plan.md +130 -0
@@ -0,0 +1,68 @@
1
+ # Integration — Playwright
2
+
3
+ This directory documents how `@playwright/test` is configured within the
4
+ `keber/qa-framework` opinionated setup.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ npm install --save-dev @playwright/test
10
+ npx playwright install chromium
11
+ ```
12
+
13
+ ## Recommended version
14
+
15
+ Peer dependency: `@playwright/test >= 1.40.0`
16
+
17
+ ## Configuration
18
+
19
+ Copy `templates/automation-scaffold/playwright.config.ts` into your project's
20
+ `qa/07-automation/` directory and replace all `{{PLACEHOLDER}}` values.
21
+
22
+ ## Key conventions
23
+
24
+ | Convention | Value |
25
+ |------------|-------|
26
+ | `fullyParallel` | `false` (tests share auth storageState) |
27
+ | `workers` | `1` (sequential by default; increase only when tests are fully isolated) |
28
+ | `retries` | `0` locally, `1` in CI |
29
+ | Auth persistence | `.auth/user-{role}.json` (via `global-setup.ts`) |
30
+ | Selectors | CSS preferred; use `data-testid` when available |
31
+ | Timeouts | `actionTimeout: 15_000`, `navigationTimeout: 30_000` |
32
+
33
+ ## Auth state management
34
+
35
+ The `global-setup.ts` template saves `storageState` to `.auth/` once before
36
+ all tests. Tests reuse this state, so the login flow runs exactly once per
37
+ suite execution.
38
+
39
+ `.auth/` must be in `.gitignore`.
40
+
41
+ ## Debugging checklist
42
+
43
+ 1. `PWDEBUG=1 npx playwright test` — step through in inspector
44
+ 2. `--headed` — watch the browser
45
+ 3. `--trace on` — record full trace; open with `npx playwright show-trace`
46
+ 4. Increase `actionTimeout` if the app has slow server-side rendering
47
+ 5. Add `await page.waitForLoadState('networkidle')` before assertions on
48
+ dynamically loaded content
49
+
50
+ ## Spec file minimal template
51
+
52
+ ```typescript
53
+ import { test, expect } from '@playwright/test';
54
+
55
+ const EXEC_IDX = Math.floor(Date.now() / 60_000) % 100_000;
56
+
57
+ test.describe('[TC-M-S-NNN] Module > Submodule @P0', () => {
58
+ test('[TC-M-S-001] Should ...', async ({ page }) => {
59
+ // Arrange
60
+ await page.goto('/your-module-path');
61
+ // Act
62
+ await page.locator('#some-input').fill(`QA-Test-${EXEC_IDX}`);
63
+ await page.locator('#submit').click();
64
+ // Assert
65
+ await expect(page.locator('.success-notification')).toBeVisible();
66
+ });
67
+ });
68
+ ```
@@ -0,0 +1,88 @@
1
+ # Integration — playwright-azure-reporter
2
+
3
+ Connects Playwright test results to Azure DevOps Test Plans automatically.
4
+
5
+ ## Package
6
+
7
+ ```bash
8
+ npm install --save-dev @alex_neo/playwright-azure-reporter
9
+ ```
10
+
11
+ ## Required environment variables
12
+
13
+ ```
14
+ ADO_ORG_URL=https://dev.azure.com/your-org
15
+ ADO_PROJECT_NAME=YourProject
16
+ ADO_PLAN_ID=<plan-id>
17
+ AZURE_TOKEN=<personal-access-token>
18
+ ```
19
+
20
+ > These variables MUST be injected via CI secrets (Azure Pipeline Library Variable Group).
21
+ > NEVER store tokens in `.env` files committed to source control.
22
+
23
+ ## playwright.config.ts snippet
24
+
25
+ ```typescript
26
+ import type { PlaywrightTestConfig } from '@playwright/test';
27
+
28
+ const config: PlaywrightTestConfig = {
29
+ reporter: [
30
+ ['list'],
31
+ ['html', { open: 'never' }],
32
+ ['@alex_neo/playwright-azure-reporter', {
33
+ token: process.env.AZURE_TOKEN!,
34
+ planId: Number(process.env.ADO_PLAN_ID),
35
+ projectName: process.env.ADO_PROJECT_NAME!,
36
+ orgUrl: process.env.ADO_ORG_URL!,
37
+ testRunTitle: `[Automated] ${new Date().toISOString().slice(0, 10)}`,
38
+ publishResultsOnFailure: true,
39
+ isDisabled: process.env.ADO_SYNC_DISABLED === 'true',
40
+ }],
41
+ ],
42
+ };
43
+
44
+ export default config;
45
+ ```
46
+
47
+ ## Test case title format (required for ADO sync)
48
+
49
+ The reporter matches test titles to ADO Work Items by the numeric prefix.
50
+ After running `inject-ado-ids.ps1`, each test title will be prepended with
51
+ the ADO WI ID wrapped in square brackets:
52
+
53
+ ```
54
+ [22957] [TC-MOD-SUB-001] Create supplier @P0
55
+ ```
56
+
57
+ The reporter extracts `22957` and publishes results to WI #22957 in ADO.
58
+
59
+ ## Module registry
60
+
61
+ The file `qa/08-azure-integration/module-registry.json` maps each spec
62
+ file/describe block to its ADO Test Suite. Example:
63
+
64
+ ```json
65
+ {
66
+ "modules": [
67
+ {
68
+ "name": "Suppliers",
69
+ "specPattern": "suppliers/**/*.spec.ts",
70
+ "adoSuiteId": 22794
71
+ }
72
+ ]
73
+ }
74
+ ```
75
+
76
+ ## Disabling ADO sync locally
77
+
78
+ Set `ADO_SYNC_DISABLED=true` in your `.env` to skip reporting while running
79
+ tests locally.
80
+
81
+ ## Troubleshooting
82
+
83
+ | Symptom | Cause | Fix |
84
+ |---------|-------|-----|
85
+ | `401 Unauthorized` | Expired PAT | Regenerate PAT in ADO → User Settings |
86
+ | `Test case not found` | WI ID mismatch | Re-run `inject-ado-ids.ps1` |
87
+ | Results not published | `isDisabled: true` | Remove or set to `false` |
88
+ | Duplicate test runs | Reporter called twice | Check for duplicate reporter arrays |
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@keber/qa-framework",
3
+ "version": "1.0.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
+ "keywords": [
6
+ "qa",
7
+ "testing",
8
+ "playwright",
9
+ "spec-driven",
10
+ "azure-devops",
11
+ "agent",
12
+ "copilot",
13
+ "framework"
14
+ ],
15
+ "license": "MIT",
16
+ "main": "scripts/index.js",
17
+ "bin": {
18
+ "qa-framework": "scripts/cli.js"
19
+ },
20
+ "scripts": {
21
+ "postinstall": "node scripts/init.js --skip-if-exists",
22
+ "init": "node scripts/cli.js init",
23
+ "generate": "node scripts/cli.js generate",
24
+ "validate": "node scripts/cli.js validate"
25
+ },
26
+ "files": [
27
+ "agent-instructions/",
28
+ "templates/",
29
+ "docs/",
30
+ "examples/",
31
+ "integrations/",
32
+ "scripts/",
33
+ "README.md",
34
+ "CHANGELOG.md",
35
+ "qa-framework.config.json"
36
+ ],
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "devDependencies": {},
41
+ "peerDependencies": {
42
+ "@playwright/test": ">=1.40.0",
43
+ "@keber/ado-qa": ">=1.0.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "@playwright/test": {
47
+ "optional": true
48
+ },
49
+ "@keber/ado-qa": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/keber/qa-framework.git"
56
+ }
57
+ }
@@ -0,0 +1,87 @@
1
+ {
2
+ "$schema": "./qa-framework.config.schema.json",
3
+ "frameworkVersion": "1.0.0",
4
+
5
+ "project": {
6
+ "name": "{{PROJECT_NAME}}",
7
+ "displayName": "{{PROJECT_DISPLAY_NAME}}",
8
+ "description": "{{PROJECT_DESCRIPTION}}",
9
+ "qaBaseUrl": "{{QA_BASE_URL}}",
10
+ "techStack": "{{TECH_STACK}}",
11
+ "loginPath": "{{LOGIN_PATH}}"
12
+ },
13
+
14
+ "modules": [
15
+ {
16
+ "code": "{{MODULE_CODE}}",
17
+ "name": "{{MODULE_NAME}}",
18
+ "description": "{{MODULE_DESCRIPTION}}",
19
+ "specPath": "qa/01-specifications/module-{{module-name}}",
20
+ "automationPath": "qa/07-automation/e2e/tests/{{module-name}}"
21
+ }
22
+ ],
23
+
24
+ "conventions": {
25
+ "language": "es",
26
+ "locale": "es-CL",
27
+ "testCaseIdPattern": "TC-{MODULE}-{SUBMODULE}-{NUM}",
28
+ "businessRuleIdPattern": "RN-{MODULE}-{NUM}",
29
+ "workflowIdPattern": "FL-{MODULE}-{NUM}",
30
+ "defectIdPattern": "DEF-{NUM}",
31
+ "testNamingPattern": "[{ID}] {title} @{priority}",
32
+ "timestampFormat": "YYYY-MM-DD_HH-MM-SS",
33
+ "tcPriorityLevels": ["P0", "P1", "P2", "P3"]
34
+ },
35
+
36
+ "testUsers": [
37
+ {
38
+ "role": "{{ROLE_NAME}}",
39
+ "envVarEmail": "QA_USER_{{ROLE_UPPER}}_EMAIL",
40
+ "envVarPassword": "QA_USER_{{ROLE_UPPER}}_PASSWORD",
41
+ "description": "{{ROLE_DESCRIPTION}}"
42
+ }
43
+ ],
44
+
45
+ "integrations": {
46
+ "playwright": {
47
+ "enabled": false,
48
+ "automationRoot": "qa/07-automation/e2e",
49
+ "workers": {
50
+ "local": 2,
51
+ "ci": 1
52
+ },
53
+ "timeout": 30000,
54
+ "navigationTimeout": 60000,
55
+ "actionTimeout": 10000,
56
+ "retries": {
57
+ "local": 0,
58
+ "ci": 2
59
+ },
60
+ "browsers": ["chromium"]
61
+ },
62
+
63
+ "azureDevOps": {
64
+ "enabled": false,
65
+ "organization": "{{ADO_ORG}}",
66
+ "project": "{{ADO_PROJECT}}",
67
+ "testPlanId": null,
68
+ "suiteId": null,
69
+ "variableGroup": "{{ADO_VARIABLE_GROUP}}",
70
+ "pipelineFile": "qa/08-azure-integration/pipelines/azure-pipeline-qa.yml",
71
+ "moduleRegistry": "qa/08-azure-integration/module-registry.json",
72
+ "reporterPackage": "@alex_neo/playwright-azure-reporter"
73
+ }
74
+ },
75
+
76
+ "agentSettings": {
77
+ "instructionsPath": "qa/00-guides",
78
+ "credentialPolicy": "env-vars-only",
79
+ "credentialPlaceholder": "<PLACEHOLDER>",
80
+ "screenshotPath": "qa/07-automation/e2e/diagnosis",
81
+ "sessionSummaryLocation": "qa/",
82
+ "tc_per_submodule_target": {
83
+ "min": 50,
84
+ "max": 85
85
+ }
86
+ }
87
+ }
package/scripts/cli.js ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/cli.js — keber/qa-framework CLI entry point
4
+ *
5
+ * Usage:
6
+ * npx keber/qa-framework <command> [options]
7
+ * qa-framework <command> [options]
8
+ *
9
+ * Commands:
10
+ * init Scaffold a qa/ folder structure from qa-framework.config.json
11
+ * generate Generate an artifact (spec template, test plan, etc.)
12
+ * validate Validate qa/ folder structure and conventions
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ const { spawnSync } = require('child_process');
18
+ const path = require('path');
19
+
20
+ const [, , command, ...args] = process.argv;
21
+
22
+ const commands = {
23
+ init: 'init.js',
24
+ generate: 'generate.js',
25
+ validate: 'validate.js',
26
+ };
27
+
28
+ if (!command || command === '--help' || command === '-h') {
29
+ printHelp();
30
+ process.exit(0);
31
+ }
32
+
33
+ if (!commands[command]) {
34
+ console.error(`[qa-framework] Unknown command: "${command}"`);
35
+ printHelp();
36
+ process.exit(1);
37
+ }
38
+
39
+ const scriptPath = path.join(__dirname, commands[command]);
40
+ const result = spawnSync(
41
+ process.execPath,
42
+ [scriptPath, ...args],
43
+ { stdio: 'inherit', cwd: process.cwd() }
44
+ );
45
+
46
+ process.exit(result.status ?? 0);
47
+
48
+ function printHelp() {
49
+ console.log(`
50
+ keber/qa-framework
51
+
52
+ Usage:
53
+ qa-framework <command> [options]
54
+
55
+ Commands:
56
+ init [--config <path>] Scaffold qa/ structure from config file
57
+ generate <artifact> Generate from template
58
+ artifact: spec | test-plan | test-case |
59
+ execution-report | defect-report |
60
+ session-summary
61
+ validate [--strict] Validate qa/ structure and naming conventions
62
+
63
+ Options:
64
+ --help, -h Show help
65
+ --version, -v Show version
66
+
67
+ Examples:
68
+ qa-framework init
69
+ qa-framework init --config ./my-project.config.json
70
+ qa-framework generate spec --module suppliers --submodule create
71
+ qa-framework validate
72
+ qa-framework validate --strict
73
+ `);
74
+ }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/generate.js — Generate a qa artifact from a template
4
+ *
5
+ * Usage:
6
+ * qa-framework generate <artifact> [options]
7
+ *
8
+ * Artifacts:
9
+ * spec 6-file submodule spec set
10
+ * test-plan Test plan document
11
+ * test-case Individual test case document
12
+ * execution-report Execution report document
13
+ * defect-report Defect / bug report
14
+ * session-summary Session summary
15
+ *
16
+ * Options:
17
+ * --module <name> Module name (used for file naming and headers)
18
+ * --submodule <name> Submodule name (for spec artifact)
19
+ * --output <dir> Output directory (default: current working directory)
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+
27
+ const args = process.argv.slice(2);
28
+ const artifact = args[0];
29
+
30
+ const getArg = (flag) => {
31
+ const i = args.indexOf(flag);
32
+ return i !== -1 ? args[i + 1] : null;
33
+ };
34
+
35
+ const moduleName = getArg('--module') ?? 'MyModule';
36
+ const submoduleName = getArg('--submodule') ?? 'MySubmodule';
37
+ const outputDir = getArg('--output') ? path.resolve(process.cwd(), getArg('--output')) : process.cwd();
38
+
39
+ const templateDir = path.resolve(__dirname, '..', 'templates');
40
+
41
+ const ARTIFACTS = {
42
+ spec: null, // special — copies all 6 files
43
+ 'test-plan': path.join(templateDir, 'test-plan.md'),
44
+ 'test-case': path.join(templateDir, 'test-case.md'),
45
+ 'execution-report': path.join(templateDir, 'execution-report.md'),
46
+ 'defect-report': path.join(templateDir, 'defect-report.md'),
47
+ 'session-summary': path.join(templateDir, 'session-summary.md'),
48
+ };
49
+
50
+ if (!artifact || !ARTIFACTS.hasOwnProperty(artifact)) {
51
+ console.error(`[qa-framework/generate] Unknown artifact: "${artifact}"`);
52
+ console.error(`Available artifacts: ${Object.keys(ARTIFACTS).join(', ')}`);
53
+ process.exit(1);
54
+ }
55
+
56
+ const moduleKey = moduleName.toLowerCase().replace(/\s+/g, '-');
57
+ const subKey = submoduleName.toLowerCase().replace(/\s+/g, '-');
58
+
59
+ if (artifact === 'spec') {
60
+ // Generate all 6 spec files into outputDir/moduleKey/subKey/
61
+ const specDir = path.join(outputDir, moduleKey, subKey);
62
+ fs.mkdirSync(specDir, { recursive: true });
63
+
64
+ const specTemplateDir = path.join(templateDir, 'specification');
65
+ const files = fs.readdirSync(specTemplateDir).filter(f => f.endsWith('.md'));
66
+
67
+ for (const file of files) {
68
+ const dest = path.join(specDir, file);
69
+ let content = fs.readFileSync(path.join(specTemplateDir, file), 'utf8');
70
+ content = applyReplacements(content, moduleKey, subKey, moduleName, submoduleName);
71
+ fs.writeFileSync(dest, content, 'utf8');
72
+ console.log(`[generate] Created: ${path.relative(process.cwd(), dest)}`);
73
+ }
74
+ } else {
75
+ // Single file artifact
76
+ const src = ARTIFACTS[artifact];
77
+ const slug = artifact === 'defect-report' ? 'DEF-NNN' : `${moduleKey}-${artifact}`;
78
+ const dest = path.join(outputDir, `${slug}.md`);
79
+
80
+ let content = fs.readFileSync(src, 'utf8');
81
+ content = applyReplacements(content, moduleKey, subKey, moduleName, submoduleName);
82
+ fs.writeFileSync(dest, content, 'utf8');
83
+ console.log(`[generate] Created: ${path.relative(process.cwd(), dest)}`);
84
+ }
85
+
86
+ function applyReplacements(content, moduleKey, subKey, moduleName, submoduleName) {
87
+ return content
88
+ .replace(/\{\{MODULE_NAME\}\}/g, moduleName)
89
+ .replace(/\{\{SUBMODULE_NAME\}\}/g, submoduleName)
90
+ .replace(/\{\{MODULE\}\}/g, moduleKey.toUpperCase())
91
+ .replace(/\{\{SUB\}\}/g, subKey.toUpperCase());
92
+ }