@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.
- package/CHANGELOG.md +53 -0
- package/README.md +233 -0
- package/agent-instructions/00-module-analysis.md +263 -0
- package/agent-instructions/01-spec-generation.md +278 -0
- package/agent-instructions/02-test-plan-generation.md +202 -0
- package/agent-instructions/03-test-case-generation.md +147 -0
- package/agent-instructions/04-automation-generation.md +310 -0
- package/agent-instructions/04b-test-stabilization.md +306 -0
- package/agent-instructions/05-ado-integration.md +244 -0
- package/agent-instructions/06-maintenance.md +125 -0
- package/docs/architecture.md +227 -0
- package/docs/comparison-matrix.md +131 -0
- package/docs/final-report.md +279 -0
- package/docs/folder-structure-guide.md +291 -0
- package/docs/generalization-decisions.md +203 -0
- package/docs/installation.md +239 -0
- package/docs/spec-driven-philosophy.md +170 -0
- package/docs/usage-with-agent.md +203 -0
- package/examples/module-example/README.md +34 -0
- package/examples/module-example/suppliers/00-inventory.md +56 -0
- package/examples/module-example/suppliers/suppliers-create.spec.ts +148 -0
- package/integrations/ado-powershell/README.md +75 -0
- package/integrations/ado-powershell/pipelines/azure-pipeline-qa.yml +133 -0
- package/integrations/ado-powershell/scripts/create-testplan-from-mapping.ps1 +114 -0
- package/integrations/ado-powershell/scripts/inject-ado-ids.ps1 +96 -0
- package/integrations/ado-powershell/scripts/sync-ado-titles.ps1 +93 -0
- package/integrations/playwright/README.md +68 -0
- package/integrations/playwright-azure-reporter/README.md +88 -0
- package/package.json +57 -0
- package/qa-framework.config.json +87 -0
- package/scripts/cli.js +74 -0
- package/scripts/generate.js +92 -0
- package/scripts/init.js +322 -0
- package/scripts/validate.js +184 -0
- package/templates/automation-scaffold/.env.example +56 -0
- package/templates/automation-scaffold/fixtures/auth.ts +77 -0
- package/templates/automation-scaffold/fixtures/test-helpers.ts +85 -0
- package/templates/automation-scaffold/global-setup.ts +106 -0
- package/templates/automation-scaffold/package.json +24 -0
- package/templates/automation-scaffold/playwright.config.ts +85 -0
- package/templates/defect-report.md +101 -0
- package/templates/execution-report.md +116 -0
- package/templates/session-summary.md +73 -0
- package/templates/specification/00-inventory.md +81 -0
- package/templates/specification/01-business-rules.md +90 -0
- package/templates/specification/02-workflows.md +114 -0
- package/templates/specification/03-roles-permissions.md +49 -0
- package/templates/specification/04-test-data.md +104 -0
- package/templates/specification/05-test-scenarios.md +226 -0
- package/templates/test-case.md +81 -0
- 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
|
+
}
|