@keber/qa-framework 1.8.0 → 1.9.0
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 +31 -0
- package/README.md +1 -1
- package/integrations/ado-powershell/README.md +34 -9
- package/integrations/ado-powershell/scripts/create-testplan-from-mapping.ps1 +24 -39
- package/package.json +1 -1
- package/scripts/init.js +34 -0
- package/templates/automation-scaffold/package.json +1 -1
- package/templates/temp-script.ps1 +74 -0
package/CHANGELOG.md
CHANGED
|
@@ -33,6 +33,37 @@ has been removed or parameterized. See `docs/comparison-matrix.md` and `docs/gen
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
+
## [1.9.0] - 2026-05-15
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **`create-testplan-from-mapping.ps1` refactored** — removed all ADO-specific logic (auth headers,
|
|
41
|
+
`Invoke-RestMethod` calls, XML step construction). The script now delegates to `New-AdoTestCase`
|
|
42
|
+
and `Add-AdoTestCaseToSuite` from `@keber/ado-powershell`, keeping `qa-framework` free of
|
|
43
|
+
ADO implementation details. Requires `@keber/ado-powershell` ≥ 1.3.0.
|
|
44
|
+
- **Script parameters simplified** — `-OrgUrl`, `-ProjectName`, and `-Token` removed from
|
|
45
|
+
`create-testplan-from-mapping.ps1`. Caller is responsible for loading the ADO session via
|
|
46
|
+
`. .github/skills/ado-powershell/load.ps1` before invoking the script.
|
|
47
|
+
- **`tc-mapping.json` schema extended** — added optional `steps` (string array) and
|
|
48
|
+
`expectedResult` (string) fields per test case. When present, steps are sent to ADO as
|
|
49
|
+
`Microsoft.VSTS.TCM.Steps`; all steps except the last are `ActionStep`, the last is
|
|
50
|
+
`ValidateStep` with `expectedResult`.
|
|
51
|
+
- **`qa-ado-integration` SKILL.md updated** — Step 3 now specifies exactly how to parse the
|
|
52
|
+
Tabla de Pruebas columns (`Steps` split on `<br>`, strip numbering prefix) to produce
|
|
53
|
+
`tc-mapping.json` with steps.
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- **Guard in `create-testplan-from-mapping.ps1`** — fails fast with a clear message if
|
|
58
|
+
`New-AdoTestCase` is not available (ADO session not loaded).
|
|
59
|
+
|
|
60
|
+
### Requires
|
|
61
|
+
|
|
62
|
+
- `@keber/ado-powershell` ≥ **1.3.0** — adds `$ExpectedResult` parameter to `New-AdoTestCase`
|
|
63
|
+
and `ValidateStep` support in the generated TCM steps XML.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
36
67
|
## [1.8.0] - 2026-05-07
|
|
37
68
|
|
|
38
69
|
### Changed
|
package/README.md
CHANGED
|
@@ -15,19 +15,20 @@ All scripts are parameterized and project-agnostic.
|
|
|
15
15
|
## Prerequisites
|
|
16
16
|
|
|
17
17
|
- PowerShell 7+ (recommended) or Windows PowerShell 5.1
|
|
18
|
-
-
|
|
19
|
-
- PAT
|
|
18
|
+
- `@keber/ado-powershell` skill installed and loaded (provides `New-AdoTestCase`, `Add-AdoTestCaseToSuite`, etc.)
|
|
19
|
+
- Azure DevOps Personal Access Token (PAT) with `Work Items: Read & Write` and `Test Management: Read & Write` scopes
|
|
20
|
+
- PAT and org/project set as env vars: `ADO_PAT`, `ADO_ORG`, `ADO_PROJECT`
|
|
20
21
|
|
|
21
22
|
## Quick start
|
|
22
23
|
|
|
23
24
|
```powershell
|
|
24
|
-
#
|
|
25
|
+
# 0. Load the ADO skill (initialises session from env vars)
|
|
26
|
+
. .github/skills/ado-powershell/load.ps1
|
|
27
|
+
|
|
28
|
+
# 1. Create Test Cases in ADO from tc-mapping.json
|
|
25
29
|
.\scripts\create-testplan-from-mapping.ps1 `
|
|
26
|
-
-OrgUrl "https://dev.azure.com/your-org" `
|
|
27
|
-
-ProjectName "YourProject" `
|
|
28
30
|
-PlanId 22304 `
|
|
29
|
-
-MappingFile "qa/08-azure-integration/tc-mapping.json"
|
|
30
|
-
-Token $env:AZURE_TOKEN
|
|
31
|
+
-MappingFile "qa/08-azure-integration/tc-mapping.json"
|
|
31
32
|
|
|
32
33
|
# 2. Inject ADO IDs into spec files (idempotent)
|
|
33
34
|
.\scripts\inject-ado-ids.ps1 `
|
|
@@ -59,12 +60,36 @@ npx playwright test
|
|
|
59
60
|
"planId": 22304,
|
|
60
61
|
"suiteId": 22305,
|
|
61
62
|
"testCases": [
|
|
62
|
-
{
|
|
63
|
-
|
|
63
|
+
{
|
|
64
|
+
"localId": "TC-SUP-CR-001",
|
|
65
|
+
"title": "Create supplier @P0",
|
|
66
|
+
"specFile": "suppliers/create.spec.ts",
|
|
67
|
+
"steps": [
|
|
68
|
+
"Navigate to /suppliers/new",
|
|
69
|
+
"Fill in required fields: Name, RUT, Email",
|
|
70
|
+
"Click 'Save'"
|
|
71
|
+
],
|
|
72
|
+
"expectedResult": "Supplier is created and appears in the list with status Active"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"localId": "TC-SUP-CR-002",
|
|
76
|
+
"title": "Create supplier - required fields @P0",
|
|
77
|
+
"specFile": "suppliers/create.spec.ts",
|
|
78
|
+
"steps": [
|
|
79
|
+
"Navigate to /suppliers/new",
|
|
80
|
+
"Leave required fields empty",
|
|
81
|
+
"Click 'Save'"
|
|
82
|
+
],
|
|
83
|
+
"expectedResult": "Validation errors appear for each required field; record is not saved"
|
|
84
|
+
}
|
|
64
85
|
]
|
|
65
86
|
}
|
|
66
87
|
```
|
|
67
88
|
|
|
89
|
+
> **`steps`** (optional): Array of step strings. Each entry becomes one ADO step. All steps except the last are `ActionStep`; the last is `ValidateStep` and receives `expectedResult`.
|
|
90
|
+
> **`expectedResult`** (optional): Overall expected result, applied to the last step. If omitted, the last step has an empty expected result.
|
|
91
|
+
> If `steps` is absent or empty, the Test Case is created with title only (no steps).
|
|
92
|
+
|
|
68
93
|
## File: ado-ids.json (output after create-testplan)
|
|
69
94
|
|
|
70
95
|
```json
|
|
@@ -7,17 +7,16 @@
|
|
|
7
7
|
corresponding Test Case Work Items in a specified ADO Test Plan/Suite.
|
|
8
8
|
Outputs ado-ids.json with the resulting WI IDs for use by inject-ado-ids.ps1.
|
|
9
9
|
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.
|
|
14
|
-
ADO project name.
|
|
10
|
+
Requires an active ADO session. Call:
|
|
11
|
+
. .github/skills/ado-powershell/load.ps1
|
|
12
|
+
before running this script. The session is initialised automatically by
|
|
13
|
+
load.ps1 when ADO_ORG, ADO_PROJECT and ADO_PAT env vars are set.
|
|
15
14
|
|
|
16
15
|
.PARAMETER PlanId
|
|
17
16
|
ADO Test Plan ID.
|
|
18
17
|
|
|
19
18
|
.PARAMETER SuiteId
|
|
20
|
-
ADO Test Suite ID. If omitted, uses the
|
|
19
|
+
ADO Test Suite ID. If omitted, uses the suiteId from tc-mapping.json.
|
|
21
20
|
|
|
22
21
|
.PARAMETER MappingFile
|
|
23
22
|
Path to tc-mapping.json input file.
|
|
@@ -25,43 +24,33 @@
|
|
|
25
24
|
.PARAMETER OutputFile
|
|
26
25
|
Path to write ado-ids.json output. Default: ado-ids.json in same dir as MappingFile.
|
|
27
26
|
|
|
28
|
-
.PARAMETER Token
|
|
29
|
-
ADO Personal Access Token. Prefer passing via $env:AZURE_TOKEN.
|
|
30
|
-
|
|
31
27
|
.EXAMPLE
|
|
28
|
+
. .github/skills/ado-powershell/load.ps1
|
|
32
29
|
.\create-testplan-from-mapping.ps1 `
|
|
33
|
-
-OrgUrl "https://dev.azure.com/your-org" `
|
|
34
|
-
-ProjectName "YourProject" `
|
|
35
30
|
-PlanId 22304 `
|
|
36
|
-
-MappingFile "qa/08-azure-integration/tc-mapping.json"
|
|
37
|
-
-Token $env:AZURE_TOKEN
|
|
31
|
+
-MappingFile "qa/08-azure-integration/tc-mapping.json"
|
|
38
32
|
#>
|
|
39
33
|
[CmdletBinding(SupportsShouldProcess)]
|
|
40
34
|
param(
|
|
41
|
-
[Parameter(Mandatory)] [string] $OrgUrl,
|
|
42
|
-
[Parameter(Mandatory)] [string] $ProjectName,
|
|
43
35
|
[Parameter(Mandatory)] [int] $PlanId,
|
|
44
36
|
[int] $SuiteId = 0,
|
|
45
37
|
[Parameter(Mandatory)] [string] $MappingFile,
|
|
46
|
-
[string] $OutputFile = ''
|
|
47
|
-
[Parameter(Mandatory)] [string] $Token
|
|
38
|
+
[string] $OutputFile = ''
|
|
48
39
|
)
|
|
49
40
|
|
|
50
41
|
Set-StrictMode -Version Latest
|
|
51
42
|
$ErrorActionPreference = 'Stop'
|
|
52
43
|
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
'Content-Type' = 'application/json'
|
|
44
|
+
# Verify ADO session is available
|
|
45
|
+
if (-not (Get-Command 'New-AdoTestCase' -ErrorAction SilentlyContinue)) {
|
|
46
|
+
Write-Error "ADO session not loaded. Run: . .github/skills/ado-powershell/load.ps1"
|
|
47
|
+
exit 1
|
|
58
48
|
}
|
|
59
49
|
|
|
60
50
|
# Load mapping
|
|
61
51
|
if (-not (Test-Path $MappingFile)) { Write-Error "Not found: $MappingFile"; exit 1 }
|
|
62
52
|
$mapping = Get-Content $MappingFile -Raw | ConvertFrom-Json
|
|
63
53
|
|
|
64
|
-
$apiBase = "$OrgUrl/$ProjectName/_apis"
|
|
65
54
|
$suiteId = if ($SuiteId -gt 0) { $SuiteId } else { $mapping.suiteId }
|
|
66
55
|
|
|
67
56
|
Write-Host "[create-testplan] Creating $($mapping.testCases.Count) test cases in Plan $PlanId / Suite $suiteId"
|
|
@@ -69,29 +58,25 @@ Write-Host "[create-testplan] Creating $($mapping.testCases.Count) test cases in
|
|
|
69
58
|
$results = @()
|
|
70
59
|
|
|
71
60
|
foreach ($tc in $mapping.testCases) {
|
|
72
|
-
$
|
|
73
|
-
|
|
74
|
-
path = '/fields/System.Title'
|
|
75
|
-
value = "[$($tc.localId)] $($tc.title)"
|
|
76
|
-
} | ConvertTo-Json -AsArray
|
|
77
|
-
|
|
78
|
-
$createUrl = "$apiBase/wit/workitems/`$Test Case?api-version=7.1"
|
|
61
|
+
$steps = if ($tc.PSObject.Properties['steps']) { $tc.steps } else { @() }
|
|
62
|
+
$expectedResult = if ($tc.PSObject.Properties['expectedResult']) { $tc.expectedResult } else { '' }
|
|
79
63
|
|
|
80
64
|
if ($PSCmdlet.ShouldProcess($tc.localId, "Create ADO Test Case")) {
|
|
81
65
|
try {
|
|
82
|
-
$
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
$splatArgs = @{
|
|
67
|
+
Title = "[$($tc.localId)] $($tc.title)"
|
|
68
|
+
Confirm = $false
|
|
69
|
+
}
|
|
70
|
+
if ($steps.Count -gt 0) {
|
|
71
|
+
$splatArgs.Steps = $steps
|
|
72
|
+
$splatArgs.ExpectedResult = $expectedResult
|
|
73
|
+
}
|
|
87
74
|
|
|
75
|
+
$wi = New-AdoTestCase @splatArgs
|
|
88
76
|
$wiId = $wi.id
|
|
89
77
|
Write-Host " [CREATED] $($tc.localId) → WI #$wiId"
|
|
90
78
|
|
|
91
|
-
|
|
92
|
-
$suiteUrl = "$apiBase/testplan/Plans/$PlanId/Suites/$suiteId/TestCase?api-version=7.1"
|
|
93
|
-
$suiteBody = @(@{ workItem = @{ id = $wiId } }) | ConvertTo-Json
|
|
94
|
-
Invoke-RestMethod -Method Post -Uri $suiteUrl -Headers $headers -Body $suiteBody | Out-Null
|
|
79
|
+
Add-AdoTestCaseToSuite -PlanId $PlanId -SuiteId $suiteId -TestCaseIds @($wiId) -Confirm:$false
|
|
95
80
|
|
|
96
81
|
$results += [PSCustomObject]@{
|
|
97
82
|
localId = $tc.localId
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keber/qa-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.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
5
|
"keywords": [
|
|
6
6
|
"qa",
|
package/scripts/init.js
CHANGED
|
@@ -341,6 +341,40 @@ cd qa/07-automation/e2e && npm install && npx playwright install chromium
|
|
|
341
341
|
const nextStepsPath = path.join(qaRoot, 'AGENT-NEXT-STEPS.md');
|
|
342
342
|
writeIfMissing(nextStepsPath, nextStepsContent);
|
|
343
343
|
|
|
344
|
+
// --- Print post-install summary ---
|
|
345
|
+
const playwrightInstalled = fs.existsSync(path.join(cwd, 'node_modules', '@playwright', 'test'));
|
|
346
|
+
const adoQaInstalledFinal = fs.existsSync(path.join(cwd, 'node_modules', '@keber', 'ado-qa'));
|
|
347
|
+
const azureReporterInstalled = fs.existsSync(path.join(cwd, 'node_modules', '@alex_neo', 'playwright-azure-reporter'));
|
|
348
|
+
|
|
349
|
+
console.log('');
|
|
350
|
+
console.log(' @keber/qa-framework — scaffold complete');
|
|
351
|
+
console.log(' ----------------------------------------');
|
|
352
|
+
console.log(' Installed:');
|
|
353
|
+
console.log(' qa/ QA directory structure + spec templates');
|
|
354
|
+
console.log(' .github/skills/ QA agent skills (8 stages)');
|
|
355
|
+
console.log(' .github/instructions/ qa-framework.instructions.md');
|
|
356
|
+
console.log('');
|
|
357
|
+
console.log(' Optional integrations:');
|
|
358
|
+
if (playwrightInstalled) {
|
|
359
|
+
console.log(' [ok] Playwright @playwright/test');
|
|
360
|
+
} else {
|
|
361
|
+
console.log(' [ ] Playwright npm install @playwright/test');
|
|
362
|
+
console.log(' cd qa/07-automation/e2e && npm install && npx playwright install chromium');
|
|
363
|
+
}
|
|
364
|
+
if (adoQaInstalledFinal) {
|
|
365
|
+
console.log(' [ok] ADO integration @keber/ado-qa');
|
|
366
|
+
} else {
|
|
367
|
+
console.log(' [ ] ADO integration npm install @keber/ado-qa');
|
|
368
|
+
}
|
|
369
|
+
if (azureReporterInstalled) {
|
|
370
|
+
console.log(' [ok] ADO Playwright reporter (installed)');
|
|
371
|
+
} else {
|
|
372
|
+
console.log(' [ ] ADO Playwright reporter npm install @alex_neo/playwright-azure-reporter');
|
|
373
|
+
}
|
|
374
|
+
console.log('');
|
|
375
|
+
console.log(' Next: edit qa/qa-framework.config.json, then read qa/AGENT-NEXT-STEPS.md');
|
|
376
|
+
console.log('');
|
|
377
|
+
|
|
344
378
|
// -----------------------------------------------------------------------
|
|
345
379
|
// Helpers
|
|
346
380
|
// -----------------------------------------------------------------------
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function New-AdoTestCase {
|
|
2
|
+
<#
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
Creates a Test Case work item with optional steps.
|
|
5
|
+
Wraps New-AdoWorkItem -Type 'Test Case' and handles TCM-specific fields.
|
|
6
|
+
|
|
7
|
+
.PARAMETER Title Title of the Test Case (mandatory).
|
|
8
|
+
.PARAMETER Steps Ordered array of plain-text action strings.
|
|
9
|
+
Encoded as the XML format required by Microsoft.VSTS.TCM.Steps.
|
|
10
|
+
.PARAMETER Priority 1 (Critical) | 2 (High) | 3 (Medium) | 4 (Low).
|
|
11
|
+
.PARAMETER ExtraFields Hashtable of additional TCM or custom fields.
|
|
12
|
+
|
|
13
|
+
.EXAMPLE
|
|
14
|
+
New-AdoTestCase -Title 'Verify login with valid credentials' `
|
|
15
|
+
-Steps @('Navigate to /login', 'Enter username and password', 'Click Sign In') `
|
|
16
|
+
-Priority '2' -AssignedTo 'qa@contoso.com' -Tags 'login; smoke'
|
|
17
|
+
#>
|
|
18
|
+
[CmdletBinding(SupportsShouldProcess, ConfirmImpact='Low')]
|
|
19
|
+
param(
|
|
20
|
+
[Parameter(Mandatory)][string]$Title,
|
|
21
|
+
[string]$Description,
|
|
22
|
+
[string]$AssignedTo,
|
|
23
|
+
[string]$AreaPath,
|
|
24
|
+
[string]$IterationPath,
|
|
25
|
+
[string]$Tags,
|
|
26
|
+
[ValidateSet('Design','Ready','Closed')]
|
|
27
|
+
[string]$State,
|
|
28
|
+
[string[]]$Steps,
|
|
29
|
+
[ValidateSet('1','2','3','4')]
|
|
30
|
+
[string]$Priority,
|
|
31
|
+
[hashtable]$ExtraFields = @{},
|
|
32
|
+
[string]$Org = $script:AdoSession.Org,
|
|
33
|
+
[string]$Project = $script:AdoSession.Project,
|
|
34
|
+
[string]$ApiV = $script:AdoSession.ApiV,
|
|
35
|
+
[hashtable]$Headers = $script:AdoSession.Headers
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
$extra = $ExtraFields.Clone()
|
|
39
|
+
|
|
40
|
+
if ($Priority) {
|
|
41
|
+
$extra['Microsoft.VSTS.Common.Priority'] = $Priority
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ($Steps -and $Steps.Count -gt 0) {
|
|
45
|
+
$stepsXml = '<steps id="0" last="{0}">' -f $Steps.Count
|
|
46
|
+
$stepIndex = 1
|
|
47
|
+
foreach ($action in $Steps) {
|
|
48
|
+
$escaped = [System.Security.SecurityElement]::Escape($action)
|
|
49
|
+
$stepsXml += '<step id="{0}" type="ActionStep"><parameterizedString isformatted="true">{1}</parameterizedString><parameterizedString isformatted="true"/></step>' -f $stepIndex, $escaped
|
|
50
|
+
$stepIndex++
|
|
51
|
+
}
|
|
52
|
+
$stepsXml += '</steps>'
|
|
53
|
+
$extra['Microsoft.VSTS.TCM.Steps'] = $stepsXml
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
$splatArgs = @{
|
|
57
|
+
Type = 'Test Case'
|
|
58
|
+
Title = $Title
|
|
59
|
+
ExtraFields = $extra
|
|
60
|
+
Org = $Org
|
|
61
|
+
Project = $Project
|
|
62
|
+
ApiV = $ApiV
|
|
63
|
+
Headers = $Headers
|
|
64
|
+
}
|
|
65
|
+
if ($Description) { $splatArgs.Description = $Description }
|
|
66
|
+
if ($AssignedTo) { $splatArgs.AssignedTo = $AssignedTo }
|
|
67
|
+
if ($AreaPath) { $splatArgs.AreaPath = $AreaPath }
|
|
68
|
+
if ($IterationPath) { $splatArgs.IterationPath = $IterationPath }
|
|
69
|
+
if ($Tags) { $splatArgs.Tags = $Tags }
|
|
70
|
+
if ($State) { $splatArgs.State = $State }
|
|
71
|
+
|
|
72
|
+
# WhatIf / Confirm propagate automatically via $WhatIfPreference / $ConfirmPreference
|
|
73
|
+
return New-AdoWorkItem @splatArgs
|
|
74
|
+
}
|