@keber/qa-framework 1.9.1 → 1.11.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/CHANGELOG.md CHANGED
@@ -7,29 +7,101 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
- ## [1.0.0] - 2026-03-04
10
+ ## [1.11.0] - 2026-06-24
11
11
 
12
12
  ### Added
13
13
 
14
- - **Framework scaffold** — initial `qa/` directory tree with 9 numbered folders (00–08)
15
- - **6-file submodule template set** — `00-inventory` through `05-test-scenarios`
16
- - **Agent instructions** — 7 purpose-specific Markdown instruction files for IDE agents
17
- - **Standards** — naming conventions, bug report template, test case template, test data guidelines
18
- - **Automation scaffold** — generalized Playwright `playwright.config.ts`, `global-setup.ts`, `.env.example`, `fixtures/auth.ts`
19
- - **Optional integrations** — stubs and READMEs for Playwright, `playwright-azure-reporter`, and ADO PowerShell
20
- - **CLI entry point** — `qa-framework init`, `generate`, `validate` commands
21
- - **Documentation** — architecture, comparison matrix, generalization decisions, installation guide, usage-with-agent guide, spec-driven philosophy, folder structure guide
22
- - **Migration notes** — `MIGRATION-NOTES.md` for projects moving from embedded to package-based framework
14
+ - **`templates/automation-scaffold/fixtures/base.ts`** — new fixture with TTL-aware session
15
+ refresh. Replaces the plain `@playwright/test` import in long-running suites where the
16
+ server-side session may expire before the suite finishes.
17
+ - **`templates/automation-scaffold/global-setup.ts`** — hardened login flow:
18
+ - `resolveVar()` with source logging (`param` / `env:KEY` / `default`)
19
+ - Login retry loop (up to 3 attempts) with crash-page detection and recovery
20
+ - `resolveAuthUsers()` — derives which users to authenticate from `QA_AUTH_USER` env var
21
+ or from configured `storageState` paths in `playwright.config.ts`
22
+ - `dismissOnboardingFlow()` — configurable via `QA_DISMISS_ONBOARDING_LABELS`
23
+ (comma-separated button labels); no-op by default
24
+ - Support for a second test user (`.auth/user-2.json`) via `QA_USER2_EMAIL` /
25
+ `QA_USER2_PASSWORD`
26
+ - **`templates/automation-scaffold/playwright.config.ts`** — exports `SESSION_TTL_MS`
27
+ (default 2 h, overridable via `QA_SESSION_TTL_MS`); commented-out parallel 2-user variant
28
+ (`chromium-user1` / `chromium-user2`).
29
+ - **`templates/automation-scaffold/.env.example`** — new variables: `QA_SESSION_TTL_MS`,
30
+ `QA_AUTH_USER`, `QA_USER2_EMAIL`, `QA_USER2_PASSWORD`, `QA_DISMISS_ONBOARDING_LABELS`,
31
+ `PLAYWRIGHT_SERVICE_URL`.
32
+ - **`templates/integration-scaffold/`** — new scaffold for API testing with Playwright
33
+ `APIRequestContext`. Includes `package.json`, `playwright.config.ts`, `global-setup.ts`
34
+ (token-based or browser-login auth), `tests/example.spec.ts`, `README.md`, `.env.example`.
35
+ Deployed to `qa/07-automation/integration/` on `init` and `upgrade`.
36
+ - **`templates/memory/`** — three semi-guided operational memory templates:
37
+ `ci-pipeline-findings.md`, `e2e-stabilization-patterns.md`, `data-volatility-strategies.md`.
38
+ Seeded into `qa/memory/` on `init` and `upgrade`.
39
+ - **`qa/06-defects/disputed/`** — third defect state for cases where QA has evidence but the
40
+ business or dev team disputes the expected behavior. Created on `init` and `upgrade`.
41
+ - **`integrations/ado-powershell/pipelines/azure-pipeline-qa.yml`** — operational hardening:
42
+ - `suiteFilter` pipeline parameter (default `all`); auto-overridden to `all` on scheduled runs
43
+ - Bash array (`GREP_ARGS`) for safe grep pattern expansion with bracket characters
44
+ - `PublishTestResults@2` scoped to exact XML path instead of `**/*.xml`
45
+ - `publishRunAttachments: false` on both E2E and API stages
46
+ - Artifact names suffixed with `$(System.JobAttempt)` to prevent collision on retries
47
+ - `QA_AUTH_USER` documented as commented example for the 2-job parallel model
48
+ - **`integrations/playwright/README.md`** — new section: Visual AI helper optional pattern.
49
+ - **`templates/qa-readme.md`** — new fields: `ADO Project`, `Last Run` summary table,
50
+ `Flaky Tests` inline annotation convention.
51
+
52
+ ### Changed
53
+
54
+ - **`scripts/init.js`** — `fixtures/base.ts` added to e2e scaffold copy list; integration
55
+ scaffold replaces the `integration/README.md` placeholder; memory template files seeded
56
+ from `templates/memory/` via `fs.readFileSync`.
57
+ - **`scripts/upgrade.js`** — integration scaffold, `disputed/` defect folder, and memory
58
+ templates are all seeded idempotently on upgrade for existing projects.
59
+ - **`docs/folder-structure-guide.md`** — `06-defects/` updated to document `disputed/`.
60
+ - **`templates/defect-report.md`** — `Status` field extended with `Disputed` value.
61
+ - **`qa/memory/INDEX.md`** template updated to pre-populate rows for the three new memory
62
+ template files.
23
63
 
24
- ### Source repositories
64
+ ---
65
+
66
+ ## [1.10.0] - 2026-05-19
25
67
 
26
- This version was bootstrapped from analysis of two existing embedded QA implementations:
68
+ ### Added
27
69
 
28
- - `redacted-repo` (Repo A) — ASP.NET MVC 5 + jQuery + toastr + Sprint-based E2E
29
- - `redacted-repo` (Repo B) — Blazor WebAssembly + Radzen + full ADO pipeline integration
70
+ - **`integrations/ado-powershell/pipelines/azure-pipeline-qa.yml`** — pipeline template
71
+ significantly expanded:
72
+ - New **Stage 3: API Integration Tests** — separate stage for `qa/07-automation/integration`,
73
+ with its own `PublishTestResults` and `PublishPipelineArtifact` tasks.
74
+ - **Cross-project repository checkout** via `resources.repositories` block; each stage
75
+ now performs an explicit `checkout: source`.
76
+ - **Smoke test step** in the E2E stage — validates `QA_BASE_URL` is reachable via `curl`
77
+ before running the suite.
78
+ - **Commented placeholder** for `AzureCLI@2` login task (Playwright Workspaces / Entra ID)
79
+ in both E2E and API stages, with `PLAYWRIGHT_SERVICE_URL` env var placeholder.
80
+ - Optional nightly schedule block (commented out).
81
+ - `PublishPipelineArtifact` tasks for HTML report and trace artifacts in both stages.
82
+ - **`integrations/playwright-azure-reporter/README.md`** — fully rewritten:
83
+ - Variables split into local (PAT) vs CI/CD (`SYSTEM_ACCESSTOKEN`) sections.
84
+ - Config snippet updated to use `ADO_ORG`, `ADO_PROJECT`, `orgUrl` constructed from
85
+ `ADO_ORG`, and `SYSTEM_ACCESSTOKEN ?? AZURE_TOKEN` token fallback.
86
+ - New **Playwright Workspaces reporter** section (`@azure/playwright` +
87
+ `playwright.service.config.ts` + Entra ID authentication notes).
88
+ - Troubleshooting table expanded with pipeline-specific `401` scenario.
30
89
 
31
- All project-specific content (URLs, ADO IDs, user credentials, module names, form selectors)
32
- has been removed or parameterized. See `docs/comparison-matrix.md` and `docs/generalization-decisions.md`.
90
+ ### Changed
91
+
92
+ - **`azure-pipeline-qa.yml`** — variable names aligned with current conventions:
93
+ `AZURE_TOKEN` / `ADO_ORG_URL` / `ADO_PROJECT_NAME` replaced by `ADO_ORG` / `ADO_PROJECT`;
94
+ `ADO_PLAN_ID` split into `ADO_E2E_PLAN_ID` / `ADO_API_PLAN_ID`; `SYSTEM_ACCESSTOKEN`
95
+ replaces PAT for ADO reporter authentication.
96
+ - **`azure-pipeline-qa.yml`** — E2E job `timeoutInMinutes` increased from 60 to 90.
97
+ - **`azure-pipeline-qa.yml`** — trigger reduced to `main` only (removed `qa` and
98
+ `release/*` branches); trigger rationale documented in comments.
99
+ - **`azure-pipeline-qa.yml`** — E2E test run consolidated from two `@grep`-tag steps
100
+ (P0 + P1/P2) into a single `--grep-invert "_inspect|_diag"` run with `continueOnError: true`.
101
+ - **`azure-pipeline-qa.yml`** — cache target changed from `~/.cache/ms-playwright` to
102
+ `node_modules` per workspace; `cacheHitVar` added to both cache tasks.
103
+ - **`azure-pipeline-qa.yml`** — `pool` block moved above `variables` for readability;
104
+ `ADO_SYNC_DISABLED` variable removed.
33
105
 
34
106
  ---
35
107
 
@@ -258,3 +330,18 @@ See `MIGRATION-NOTES.md` — section "Upgrading from a version that used `.githu
258
330
 
259
331
  ---
260
332
 
333
+ ## [1.0.0] - 2026-03-04
334
+
335
+ ### Added
336
+
337
+ - **Framework scaffold** — initial `qa/` directory tree with 9 numbered folders (00–08)
338
+ - **6-file submodule template set** — `00-inventory` through `05-test-scenarios`
339
+ - **Agent instructions** — 7 purpose-specific Markdown instruction files for IDE agents
340
+ - **Standards** — naming conventions, bug report template, test case template, test data guidelines
341
+ - **Automation scaffold** — generalized Playwright `playwright.config.ts`, `global-setup.ts`, `.env.example`, `fixtures/auth.ts`
342
+ - **Optional integrations** — stubs and READMEs for Playwright, `playwright-azure-reporter`, and ADO PowerShell
343
+ - **CLI entry point** — `qa-framework init`, `generate`, `validate` commands
344
+ - **Documentation** — architecture, comparison matrix, generalization decisions, installation guide, usage-with-agent guide, spec-driven philosophy, folder structure guide
345
+ - **Migration notes** — `MIGRATION-NOTES.md` for projects moving from embedded to package-based framework
346
+
347
+ ---
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # qa-framework
2
2
 
3
3
  > Reusable, installable, agent-oriented QA framework for spec-driven automated testing.
4
- > Current version: **v1.9.0**
4
+ > Current version: **v1.10.0**
5
5
 
6
6
  ---
7
7
 
@@ -260,10 +260,16 @@ Each skill folder contains:
260
260
  ├── README.md
261
261
  ├── open/
262
262
  │ └── DEF-{NNN}-{slug}.md
263
+ ├── disputed/
264
+ │ └── DEF-{NNN}-{slug}.md
263
265
  └── resolved/
264
266
  └── DEF-{NNN}-{slug}.md
265
267
  ```
266
268
 
269
+ - `open/` - confirmed defect, fix pending
270
+ - `disputed/` - QA has evidence but business or dev team disputes the expected behavior; pending functional decision
271
+ - `resolved/` - closed by fix or formal decision
272
+
267
273
  **Decision guide**:
268
274
  - ADO enabled → use ADO Work Items. `06-defects/` contains lightweight references only
269
275
  - ADO disabled → use this folder as primary defect tracker
@@ -1,133 +1,345 @@
1
1
  # -----------------------------------------------------------------------
2
- # keber/qa-framework — Azure Pipeline QA Template
2
+ # keber/qa-framework - Azure Pipeline QA Template
3
3
  # -----------------------------------------------------------------------
4
- # Parameterized CI pipeline for running Playwright E2E tests and
5
- # optionally syncing results to Azure DevOps Test Plans.
4
+ # Parameterized CI pipeline for running Playwright E2E and API tests and
5
+ # syncing results to Azure DevOps Test Plans via SYSTEM_ACCESSTOKEN.
6
+ #
7
+ # Cross-project repository: the test repo lives in a different ADO project.
8
+ # Update 'resources.repositories.name' to match your org/project/repo.
6
9
  #
7
10
  # Required Pipeline Library Variable Group: "QA-Variables"
8
- # QA_BASE_URL — Target application URL for QA environment
9
- # QA_USER_EMAIL — Default test user email
10
- # QA_USER_PASSWORD — Default test user password (secret)
11
- # AZURE_TOKEN — ADO Personal Access Token (secret)
12
- # ADO_ORG_URL — https://dev.azure.com/your-org
13
- # ADO_PROJECT_NAME — ADO project name
14
- # ADO_PLAN_ID — Test Plan ID
11
+ # Create this group in ADO -> Pipelines -> Library and add the following:
12
+ #
13
+ # QA_BASE_URL - Target application URL (e.g. https://app-qa.example.com)
14
+ # QA_USER_EMAIL - Test user email / RUT
15
+ # QA_USER_PASSWORD - Test user password [secret]
16
+ # ADO_ORG - ADO organization slug (e.g. my-org)
17
+ # ADO_PROJECT - ADO project name (e.g. my-project)
18
+ # ADO_E2E_PLAN_ID - Test Plan ID for the E2E suite
19
+ # ADO_API_PLAN_ID - Test Plan ID for the API/integration suite
20
+ #
21
+ # NOTE on multiple Plan IDs: ADO variable groups store plain strings - there
22
+ # is no array type. Use one variable per suite (ADO_E2E_PLAN_ID / ADO_API_PLAN_ID).
23
+ # If the project has only one suite, a single ADO_PLAN_ID variable is enough.
24
+ # Results are reported to ADO via System.AccessToken (OAuth); no PAT required.
15
25
  # -----------------------------------------------------------------------
16
26
 
27
+ # Cross-project repository - update <ADO_SOURCE_PROJECT>/<REPO_NAME> as needed
28
+ resources:
29
+ repositories:
30
+ - repository: source
31
+ type: git
32
+ name: <ADO_SOURCE_PROJECT>/<REPO_NAME> # e.g. my-qa-project/my-repo
33
+ ref: refs/heads/main
34
+
35
+ # Trigger: push and PR to main.
36
+ # The test repo is decoupled from the app repo, so branch triggers are minimal.
17
37
  trigger:
18
38
  branches:
19
39
  include:
20
40
  - main
21
- - qa
22
- - release/*
23
41
 
24
42
  pr:
25
43
  branches:
26
44
  include:
27
45
  - main
28
46
 
47
+ # Optional scheduled run - uncomment and adjust if a nightly regression is needed:
48
+ # schedules:
49
+ # - cron: '0 6 * * 1-5' # 06:00 UTC Mon-Fri (03:00 CLT / 02:00 CLST)
50
+ # displayName: Nightly regression
51
+ # branches:
52
+ # include:
53
+ # - main
54
+ # always: true
55
+
56
+ # -----------------------------------------------------------------------
57
+ # Pipeline parameters
58
+ # -----------------------------------------------------------------------
59
+ # suiteFilter controls which tests run when the pipeline is triggered manually
60
+ # or from a PR. Scheduled runs always override this to 'all' automatically
61
+ # (see the "Resolve suite filter" step in each test job).
62
+ #
63
+ # Default is 'all' so a plain manual run executes the full suite.
64
+ # Override at queue time to run a subset (e.g. 'smoke', '[P0]', 'login').
65
+ #
66
+ # The value is passed to Playwright via --grep. Special regex characters such
67
+ # as '[' and ']' are escaped by the bash array pattern in the run step, so
68
+ # values like '[P0]' are safe.
69
+ parameters:
70
+ - name: suiteFilter
71
+ displayName: 'Test suite filter (grep pattern, or "all" to skip filtering)'
72
+ type: string
73
+ default: 'all'
74
+
75
+ pool:
76
+ vmImage: 'ubuntu-latest'
77
+
29
78
  variables:
30
79
  - group: QA-Variables
31
80
  - name: NODE_VERSION
32
81
  value: '20.x'
33
- - name: QA_DIR
82
+ - name: E2E_DIR
34
83
  value: 'qa/07-automation/e2e'
35
- - name: ADO_SYNC_DISABLED
36
- value: 'false'
37
-
38
- pool:
39
- vmImage: 'ubuntu-latest'
84
+ - name: API_DIR
85
+ value: 'qa/07-automation/integration'
40
86
 
41
87
  stages:
42
88
  # -----------------------------------------------------------------------
43
- # Stage 1: Install & Setup
89
+ # Stage 1: Install & cache dependencies
44
90
  # -----------------------------------------------------------------------
45
91
  - stage: Setup
46
92
  displayName: 'Install Dependencies'
47
93
  jobs:
48
94
  - job: Install
49
- displayName: 'npm install + Playwright browsers'
95
+ displayName: 'npm ci + Playwright browsers'
50
96
  steps:
97
+ - checkout: source
98
+ displayName: 'Checkout source repo'
99
+
51
100
  - task: NodeTool@0
52
101
  inputs:
53
102
  versionSpec: $(NODE_VERSION)
54
103
  displayName: 'Use Node.js $(NODE_VERSION)'
55
104
 
56
105
  - script: |
57
- cd $(QA_DIR)
106
+ cd $(E2E_DIR)
58
107
  npm ci
59
108
  npx playwright install chromium --with-deps
60
- displayName: 'Install npm deps and Playwright Chromium'
109
+ displayName: 'Install E2E deps and Playwright Chromium'
110
+
111
+ - task: CacheBeta@1
112
+ inputs:
113
+ key: 'e2e | "$(Agent.OS)" | $(E2E_DIR)/package-lock.json'
114
+ path: '$(E2E_DIR)/node_modules'
115
+ cacheHitVar: 'CACHE_RESTORED_E2E'
116
+ displayName: 'Cache E2E node_modules'
117
+
118
+ - script: |
119
+ cd $(API_DIR)
120
+ npm ci
121
+ displayName: 'Install API deps'
61
122
 
62
123
  - task: CacheBeta@1
63
124
  inputs:
64
- key: 'playwright | "$(Agent.OS)" | $(QA_DIR)/package-lock.json'
65
- path: '~/.cache/ms-playwright'
66
- displayName: 'Cache Playwright browsers'
125
+ key: 'api | "$(Agent.OS)" | $(API_DIR)/package-lock.json'
126
+ path: '$(API_DIR)/node_modules'
127
+ cacheHitVar: 'CACHE_RESTORED_API'
128
+ displayName: 'Cache API node_modules'
67
129
 
68
130
  # -----------------------------------------------------------------------
69
- # Stage 2: E2E Tests
131
+ # Stage 2: E2E Tests (Playwright/Chromium)
132
+ # -----------------------------------------------------------------------
133
+ # Single-job configuration. For parallel execution with two test users,
134
+ # split this into two jobs and set QA_AUTH_USER per job:
135
+ #
136
+ # - job: E2E_User1
137
+ # variables:
138
+ # QA_AUTH_USER: '1'
139
+ # ...
140
+ # - job: E2E_User2
141
+ # variables:
142
+ # QA_AUTH_USER: '2'
143
+ # ...
144
+ #
145
+ # Each job must use a distinct Playwright project (--project=chromium-user1 /
146
+ # --project=chromium-user2) to avoid session conflicts between parallel users.
70
147
  # -----------------------------------------------------------------------
71
148
  - stage: E2E
72
- displayName: 'E2E Tests'
149
+ displayName: 'E2E Tests (Playwright/Chromium)'
73
150
  dependsOn: Setup
74
151
  jobs:
75
- - job: PlaywrightTests
76
- displayName: 'Run Playwright suite'
77
- timeoutInMinutes: 60
152
+ - job: PlaywrightE2E
153
+ displayName: 'Run E2E suite'
154
+ timeoutInMinutes: 90
78
155
  steps:
156
+ - checkout: source
157
+ displayName: 'Checkout source repo'
158
+
79
159
  - task: NodeTool@0
80
160
  inputs:
81
161
  versionSpec: $(NODE_VERSION)
162
+ displayName: 'Use Node.js $(NODE_VERSION)'
82
163
 
83
164
  - script: |
84
- cd $(QA_DIR)
165
+ cd $(E2E_DIR)
85
166
  npm ci
86
167
  npx playwright install chromium --with-deps
87
- displayName: 'Restore dependencies'
168
+ displayName: 'Restore E2E dependencies'
169
+
170
+ - script: |
171
+ echo "QA_BASE_URL = $(QA_BASE_URL)"
172
+ HTTP_CODE=$(curl -o /dev/null -s -w "%{http_code}" --max-time 30 "$(QA_BASE_URL)")
173
+ echo "HTTP response: $HTTP_CODE"
174
+ if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 400 ]; then
175
+ echo "##[error]Smoke test failed - $(QA_BASE_URL) returned HTTP $HTTP_CODE"
176
+ exit 1
177
+ fi
178
+ echo "Smoke test passed (HTTP $HTTP_CODE)"
179
+ displayName: 'Smoke test - verify QA_BASE_URL is reachable'
180
+
181
+ # ---------------------------------------------------------------
182
+ # Playwright Workspaces (Azure App Testing)
183
+ # Enable once the ADO service connection is configured.
184
+ # Prerequisite: the service connection must have the Contributor
185
+ # role on the workspace in Azure Portal (Access control IAM).
186
+ # ---------------------------------------------------------------
187
+ # - task: AzureCLI@2
188
+ # displayName: 'Login to Azure (Playwright Workspaces)'
189
+ # inputs:
190
+ # azureSubscription: '<AZURE_SERVICE_CONNECTION_NAME>'
191
+ # scriptType: bash
192
+ # scriptLocation: inlineScript
193
+ # inlineScript: echo "Authenticated via Entra ID"
88
194
 
89
195
  - script: |
90
- cd $(QA_DIR)
91
- npx playwright test --grep @P0
92
- displayName: 'Run P0 smoke suite'
196
+ # Scheduled runs always execute the full suite, regardless of the
197
+ # suiteFilter parameter. This prevents accidental partial runs in
198
+ # nightly regressions when the parameter was changed by a prior
199
+ # manual queue.
200
+ SUITE_FILTER="${{ parameters.suiteFilter }}"
201
+ if [ "$(Build.Reason)" = "Schedule" ]; then
202
+ SUITE_FILTER="all"
203
+ echo "Scheduled run detected - overriding suiteFilter to 'all'"
204
+ fi
205
+ echo "Effective suiteFilter: $SUITE_FILTER"
206
+
207
+ # Build --grep args as a bash array to safely handle patterns that
208
+ # contain special regex characters such as '[' and ']'. Inline
209
+ # string interpolation would break those patterns at the shell level.
210
+ GREP_ARGS=()
211
+ if [ "$SUITE_FILTER" != "all" ]; then
212
+ GREP_ARGS=(--grep "$SUITE_FILTER")
213
+ fi
214
+
215
+ cd $(E2E_DIR)
216
+ npx playwright test --project=chromium --ignore-snapshots \
217
+ --grep-invert "_inspect|_diag" "${GREP_ARGS[@]}"
218
+ displayName: 'Run E2E tests'
219
+ continueOnError: true
93
220
  env:
94
- QA_BASE_URL: $(QA_BASE_URL)
95
- QA_USER_EMAIL: $(QA_USER_EMAIL)
96
- QA_USER_PASSWORD: $(QA_USER_PASSWORD)
97
- AZURE_TOKEN: $(AZURE_TOKEN)
98
- ADO_ORG_URL: $(ADO_ORG_URL)
99
- ADO_PROJECT_NAME: $(ADO_PROJECT_NAME)
100
- ADO_PLAN_ID: $(ADO_PLAN_ID)
101
- ADO_SYNC_DISABLED: $(ADO_SYNC_DISABLED)
102
- CI: 'true'
221
+ QA_BASE_URL: $(QA_BASE_URL)
222
+ QA_USER_EMAIL: $(QA_USER_EMAIL)
223
+ QA_USER_PASSWORD: $(QA_USER_PASSWORD)
224
+ ADO_ORG: $(ADO_ORG)
225
+ ADO_PROJECT: $(ADO_PROJECT)
226
+ ADO_PLAN_ID: $(ADO_E2E_PLAN_ID)
227
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
228
+ CI: 'true'
229
+ # QA_AUTH_USER: '1' # Set explicitly when running parallel jobs (user-1 / user-2 model)
230
+ # PLAYWRIGHT_SERVICE_URL: $(PLAYWRIGHT_SERVICE_URL) # Playwright Workspaces endpoint - enable together with the login task
231
+
232
+ # publishRunAttachments is false because screenshots and traces are
233
+ # already uploaded as pipeline artifacts below. Setting it to true
234
+ # would double-publish the same files.
235
+ - task: PublishTestResults@2
236
+ condition: always()
237
+ inputs:
238
+ testResultsFormat: 'JUnit'
239
+ testResultsFiles: 'test-results/junit-results.xml'
240
+ searchFolder: $(E2E_DIR)
241
+ mergeTestResults: true
242
+ publishRunAttachments: false
243
+ failTaskOnFailedTests: true
244
+ testRunTitle: '[Auto E2E] $(Build.BuildNumber)'
245
+ displayName: 'Publish E2E test results (JUnit)'
246
+
247
+ # Artifact names include $(System.JobAttempt) to avoid name collisions
248
+ # when the job is retried. ADO rejects duplicate artifact names within
249
+ # the same pipeline run, so without the suffix a retry always fails at
250
+ # the publish step.
251
+ - task: PublishPipelineArtifact@1
252
+ condition: always()
253
+ inputs:
254
+ targetPath: '$(E2E_DIR)/playwright-report'
255
+ artifact: 'e2e-playwright-report-attempt-$(System.JobAttempt)'
256
+ displayName: 'Publish E2E HTML report'
257
+
258
+ - task: PublishPipelineArtifact@1
259
+ condition: always()
260
+ inputs:
261
+ targetPath: '$(E2E_DIR)/test-results'
262
+ artifact: 'e2e-test-results-attempt-$(System.JobAttempt)'
263
+ displayName: 'Publish E2E trace artifacts'
264
+
265
+ # -----------------------------------------------------------------------
266
+ # Stage 3: API Integration Tests
267
+ # -----------------------------------------------------------------------
268
+ - stage: API
269
+ displayName: 'API Integration Tests'
270
+ dependsOn: E2E
271
+ jobs:
272
+ - job: PlaywrightAPI
273
+ displayName: 'Run API suite'
274
+ timeoutInMinutes: 30
275
+ steps:
276
+ - checkout: source
277
+ displayName: 'Checkout source repo'
278
+
279
+ - task: NodeTool@0
280
+ inputs:
281
+ versionSpec: $(NODE_VERSION)
282
+ displayName: 'Use Node.js $(NODE_VERSION)'
103
283
 
104
284
  - script: |
105
- cd $(QA_DIR)
106
- npx playwright test --grep "@P1|@P2"
107
- displayName: 'Run P1/P2 regression suite'
108
- condition: succeededOrFailed()
285
+ cd $(API_DIR)
286
+ npm ci
287
+ displayName: 'Restore API dependencies'
288
+
289
+ # ---------------------------------------------------------------
290
+ # Playwright Workspaces (Azure App Testing)
291
+ # Enable once the ADO service connection is configured.
292
+ # ---------------------------------------------------------------
293
+ # - task: AzureCLI@2
294
+ # displayName: 'Login to Azure (Playwright Workspaces)'
295
+ # inputs:
296
+ # azureSubscription: '<AZURE_SERVICE_CONNECTION_NAME>'
297
+ # scriptType: bash
298
+ # scriptLocation: inlineScript
299
+ # inlineScript: echo "Authenticated via Entra ID"
300
+
301
+ - script: |
302
+ # API integration tests do not use suite tags - always run all.
303
+ cd $(API_DIR)
304
+ npx playwright test --grep-invert "_inspect|_diag"
305
+ displayName: 'Run API integration tests'
306
+ continueOnError: true
109
307
  env:
110
- QA_BASE_URL: $(QA_BASE_URL)
111
- QA_USER_EMAIL: $(QA_USER_EMAIL)
112
- QA_USER_PASSWORD: $(QA_USER_PASSWORD)
113
- AZURE_TOKEN: $(AZURE_TOKEN)
114
- ADO_ORG_URL: $(ADO_ORG_URL)
115
- ADO_PROJECT_NAME: $(ADO_PROJECT_NAME)
116
- ADO_PLAN_ID: $(ADO_PLAN_ID)
117
- CI: 'true'
308
+ QA_BASE_URL: $(QA_BASE_URL)
309
+ QA_USER_EMAIL: $(QA_USER_EMAIL)
310
+ QA_USER_PASSWORD: $(QA_USER_PASSWORD)
311
+ ADO_ORG: $(ADO_ORG)
312
+ ADO_PROJECT: $(ADO_PROJECT)
313
+ ADO_PLAN_ID: $(ADO_API_PLAN_ID)
314
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
315
+ CI: 'true'
316
+ # PLAYWRIGHT_SERVICE_URL: $(PLAYWRIGHT_SERVICE_URL) # Playwright Workspaces endpoint - enable together with the login task
118
317
 
318
+ # publishRunAttachments is false because trace artifacts are already
319
+ # uploaded as pipeline artifacts below.
119
320
  - task: PublishTestResults@2
120
321
  condition: always()
121
322
  inputs:
122
- testResultsFormat: 'JUnit'
123
- testResultsFiles: '$(QA_DIR)/test-results/junit*.xml'
124
- mergeTestResults: true
125
- testRunTitle: 'Playwright E2E — $(Build.SourceBranchName)'
126
- displayName: 'Publish test results'
323
+ testResultsFormat: 'JUnit'
324
+ testResultsFiles: 'test-results/junit-results.xml'
325
+ searchFolder: $(API_DIR)
326
+ mergeTestResults: true
327
+ publishRunAttachments: false
328
+ failTaskOnFailedTests: true
329
+ testRunTitle: '[Auto API] $(Build.BuildNumber)'
330
+ displayName: 'Publish API test results (JUnit)'
331
+
332
+ # Artifact names include $(System.JobAttempt) to prevent collision on retries.
333
+ - task: PublishPipelineArtifact@1
334
+ condition: always()
335
+ inputs:
336
+ targetPath: '$(API_DIR)/playwright-report'
337
+ artifact: 'api-playwright-report-attempt-$(System.JobAttempt)'
338
+ displayName: 'Publish API HTML report'
127
339
 
128
- - task: PublishBuildArtifacts@1
340
+ - task: PublishPipelineArtifact@1
129
341
  condition: always()
130
342
  inputs:
131
- pathToPublish: '$(QA_DIR)/playwright-report'
132
- artifactName: 'playwright-report'
133
- displayName: 'Publish Playwright HTML report'
343
+ targetPath: '$(API_DIR)/test-results'
344
+ artifact: 'api-test-results-attempt-$(System.JobAttempt)'
345
+ displayName: 'Publish API trace artifacts'