@keber/qa-framework 1.10.0 → 1.12.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.
Files changed (113) hide show
  1. package/CHANGELOG.md +63 -18
  2. package/README.md +2 -2
  3. package/docs/architecture.md +30 -26
  4. package/docs/decisions/lane-heartbeat-caller.md +86 -0
  5. package/docs/final-report.md +23 -23
  6. package/docs/folder-structure-guide.md +106 -80
  7. package/docs/installation.md +35 -7
  8. package/docs/skills-architecture.md +23 -23
  9. package/docs/spec-driven-philosophy.md +9 -9
  10. package/docs/usage-with-agent.md +83 -9
  11. package/docs/visuals/diag-01-ejecutivo-1.png +0 -0
  12. package/docs/visuals/diag-02-tactico-1.png +0 -0
  13. package/docs/visuals/diag-03-tecnico-1.png +0 -0
  14. package/docs/visuals/info-01-ejecutivo-1.png +0 -0
  15. package/docs/visuals/info-02-tactico-1.png +0 -0
  16. package/docs/visuals/info-03-tecnico-1.png +0 -0
  17. package/docs/visuals/pres-01-ejecutivo-1.png +0 -0
  18. package/docs/visuals/pres-02-tactico-1.png +0 -0
  19. package/docs/visuals/pres-03-tecnico-1.png +0 -0
  20. package/docs/visuals/qa-01-problema-1.png +0 -0
  21. package/docs/visuals/qa-02-que-es-1.png +0 -0
  22. package/docs/visuals/qa-03-pipeline-1.png +0 -0
  23. package/docs/visuals/qa-04-6-archivos-1.png +0 -0
  24. package/docs/visuals/qa-05-humano-1.png +0 -0
  25. package/docs/visuals/qa-06-agente-1.png +0 -0
  26. package/docs/visuals/qa-07-skills-arch-1.png +0 -0
  27. package/docs/visuals/qa-08-traceability-1.png +0 -0
  28. package/docs/visuals/qa-en-01-problem-1.png +0 -0
  29. package/docs/visuals/qa-en-02-what-is-1.png +0 -0
  30. package/docs/visuals/qa-en-03-pipeline-1.png +0 -0
  31. package/docs/visuals/qa-en-04-6files-1.png +0 -0
  32. package/docs/visuals/qa-en-05-human-1.png +0 -0
  33. package/docs/visuals/qa-en-06-agent-1.png +0 -0
  34. package/docs/visuals/qa-en-07-skills-arch-1.png +0 -0
  35. package/docs/visuals/qa-en-08-traceability-1.png +0 -0
  36. package/examples/module-example/suppliers/00-inventory.md +1 -1
  37. package/examples/module-example/suppliers/suppliers-create.spec.ts +8 -8
  38. package/integrations/ado-powershell/README.md +1 -1
  39. package/integrations/ado-powershell/pipelines/azure-pipeline-qa.yml +92 -25
  40. package/integrations/ado-powershell/scripts/sync-ado-titles.ps1 +2 -2
  41. package/integrations/playwright/README.md +128 -4
  42. package/package.json +9 -6
  43. package/qa-framework.config.json +24 -3
  44. package/scripts/check-forbidden-chars.js +187 -0
  45. package/scripts/check-spanish-accents.js +159 -0
  46. package/scripts/cli.js +1 -1
  47. package/scripts/generate.js +2 -2
  48. package/scripts/init.js +108 -45
  49. package/scripts/lib/claude-agents.js +78 -0
  50. package/scripts/lib/claude-commands.js +56 -0
  51. package/scripts/sync-version.js +36 -0
  52. package/scripts/upgrade.js +461 -30
  53. package/scripts/validate.js +17 -17
  54. package/skills/qa-ado-integration/SKILL.md +19 -19
  55. package/skills/qa-ado-integration/references/scripts-and-config.md +6 -6
  56. package/skills/qa-automation/SKILL.md +49 -27
  57. package/skills/qa-automation/references/config-checklist.md +4 -4
  58. package/skills/qa-automation/references/dom-inspection-template.js +7 -7
  59. package/skills/qa-automation/references/patterns.md +20 -20
  60. package/skills/qa-automation/references/pom-template.md +161 -0
  61. package/skills/qa-maintenance/SKILL.md +11 -11
  62. package/skills/qa-maintenance/references/update-rules.md +8 -8
  63. package/skills/qa-module-analysis/SKILL.md +20 -19
  64. package/skills/qa-module-analysis/references/exploration-checklist.md +4 -4
  65. package/skills/qa-module-analysis/references/output-verification.md +69 -0
  66. package/skills/qa-module-analysis/references/spec-file-formats.md +14 -14
  67. package/skills/qa-spec-generation/SKILL.md +13 -7
  68. package/skills/qa-test-cases/SKILL.md +11 -81
  69. package/skills/qa-test-cases/references/test-case-template.md +5 -5
  70. package/skills/qa-test-plan/SKILL.md +22 -86
  71. package/skills/qa-test-plan/references/plan-de-pruebas-template.md +24 -24
  72. package/skills/qa-test-stabilization/SKILL.md +59 -30
  73. package/skills/qa-test-stabilization/references/classification-protocol.md +35 -35
  74. package/templates/agent-next-steps.md +10 -10
  75. package/templates/agents/qa-analisis.md +142 -0
  76. package/templates/agents/qa-asesoria.md +48 -0
  77. package/templates/agents/qa-informe-resultados.md +234 -0
  78. package/templates/agents/qa-plan.md +131 -0
  79. package/templates/automation-scaffold/.env.example +52 -3
  80. package/templates/automation-scaffold/fixtures/auth.ts +27 -5
  81. package/templates/automation-scaffold/fixtures/base.ts +130 -0
  82. package/templates/automation-scaffold/fixtures/test-helpers.ts +1 -1
  83. package/templates/automation-scaffold/global-setup.ts +196 -37
  84. package/templates/automation-scaffold/playwright.config.ts +74 -10
  85. package/templates/automation-scaffold/scripts/global-setup-guards.js +184 -0
  86. package/templates/automation-scaffold/scripts/lane-config.js +269 -0
  87. package/templates/automation-scaffold/scripts/lane-lock.js +589 -0
  88. package/templates/defect-report.md +18 -4
  89. package/templates/execution-report.md +9 -9
  90. package/templates/integration-scaffold/.env.example +40 -0
  91. package/templates/integration-scaffold/README.md +77 -0
  92. package/templates/integration-scaffold/global-setup.ts +119 -0
  93. package/templates/integration-scaffold/package.json +15 -0
  94. package/templates/integration-scaffold/playwright.config.ts +92 -0
  95. package/templates/integration-scaffold/tests/example.spec.ts +43 -0
  96. package/templates/memory/ci-pipeline-findings.md +36 -0
  97. package/templates/memory/data-volatility-strategies.md +70 -0
  98. package/templates/memory/e2e-stabilization-patterns.md +54 -0
  99. package/templates/qa-framework.instructions.md +16 -7
  100. package/templates/qa-framework.rules.md +53 -0
  101. package/templates/qa-readme.md +26 -5
  102. package/templates/session-summary.md +2 -2
  103. package/templates/specification/00-inventory.md +3 -3
  104. package/templates/specification/01-business-rules.md +6 -6
  105. package/templates/specification/02-workflows.md +1 -1
  106. package/templates/specification/03-roles-permissions.md +1 -1
  107. package/templates/specification/04-test-data.md +8 -8
  108. package/templates/specification/05-test-scenarios.md +5 -5
  109. package/templates/test-case.md +3 -3
  110. package/templates/test-data-guidelines.md +7 -7
  111. package/templates/test-plan-sprint.md +13 -13
  112. package/templates/test-plan.md +3 -3
  113. package/skills/qa-test-plan/references/priority-and-feasibility.md +0 -159
@@ -0,0 +1,40 @@
1
+ # -----------------------------------------------------------------------
2
+ # Integration test environment variables
3
+ # -----------------------------------------------------------------------
4
+ # Copy this file to .env and fill in real values.
5
+ # NEVER commit .env to source control.
6
+ # -----------------------------------------------------------------------
7
+
8
+ # -----------------------------------------------------------------------
9
+ # Application under test
10
+ # -----------------------------------------------------------------------
11
+ QA_BASE_URL=https://your-app.qa.example.com
12
+
13
+ # -----------------------------------------------------------------------
14
+ # Auth - choose one strategy
15
+ # -----------------------------------------------------------------------
16
+
17
+ # Strategy 1: Static bearer token (preferred for pure API services)
18
+ # QA_API_TOKEN=your-api-token-here
19
+
20
+ # Strategy 2: Browser login (for apps with cookie/session auth)
21
+ # QA_USER_EMAIL=qa-user@example.com
22
+ # QA_USER_PASSWORD=CHANGE_ME
23
+
24
+ # -----------------------------------------------------------------------
25
+ # Login form selectors (used only when QA_API_TOKEN is not set)
26
+ # -----------------------------------------------------------------------
27
+ # QA_LOGIN_PATH=/login
28
+ # QA_LOGIN_EMAIL_SELECTOR=input[type="email"]
29
+ # QA_LOGIN_PASSWORD_SELECTOR=input[type="password"]
30
+ # QA_LOGIN_SUBMIT_SELECTOR=button[type="submit"]
31
+ # QA_LOGIN_SUCCESS_SELECTOR=.dashboard
32
+
33
+ # -----------------------------------------------------------------------
34
+ # Azure DevOps integration (optional)
35
+ # -----------------------------------------------------------------------
36
+ # ADO_ORG=your-org
37
+ # ADO_PROJECT=YourProject
38
+ # ADO_PLAN_ID=00000
39
+ # ADO_PAT=your-pat-here
40
+ # SYSTEM_ACCESSTOKEN= # Set automatically in Azure Pipelines
@@ -0,0 +1,77 @@
1
+ # API Integration Tests
2
+
3
+ Playwright-based API test project for `qa/07-automation/integration/`.
4
+
5
+ Tests run without a browser. All tests use Playwright's `APIRequestContext`
6
+ to call HTTP endpoints directly. Auth state is established once by
7
+ `global-setup.ts` and reused across the test run.
8
+
9
+ ## Requirements
10
+
11
+ - Node.js 18+
12
+ - `@playwright/test` (installed via `npm install` in this directory)
13
+
14
+ ## Setup
15
+
16
+ ```bash
17
+ cd qa/07-automation/integration
18
+ npm install
19
+ cp .env.example .env
20
+ # Edit .env and fill in QA_BASE_URL and auth credentials
21
+ ```
22
+
23
+ Add the following to your root `.gitignore`:
24
+
25
+ ```
26
+ qa/07-automation/integration/.env
27
+ qa/07-automation/integration/.auth/
28
+ qa/07-automation/integration/test-results/
29
+ qa/07-automation/integration/playwright-report/
30
+ ```
31
+
32
+ ## Environment variables
33
+
34
+ | Variable | Required | Description |
35
+ |---|---|---|
36
+ | `QA_BASE_URL` | Yes | Base URL of the API under test |
37
+ | `QA_API_TOKEN` | One of | Static bearer token for token-based APIs |
38
+ | `QA_USER_EMAIL` | One of | Email/username for browser-login APIs |
39
+ | `QA_USER_PASSWORD` | One of | Password for browser-login APIs |
40
+
41
+ See `.env.example` for all supported variables.
42
+
43
+ ## Running tests
44
+
45
+ ```bash
46
+ # All tests
47
+ npm test
48
+
49
+ # CI mode (retries enabled)
50
+ npm run test:ci
51
+
52
+ # Open HTML report
53
+ npm run report
54
+ ```
55
+
56
+ ## Writing tests
57
+
58
+ Import from `@playwright/test` and use the `request` fixture:
59
+
60
+ ```typescript
61
+ import { test, expect } from '@playwright/test';
62
+
63
+ test('GET /users returns 200', async ({ request }) => {
64
+ const response = await request.get('/users');
65
+ expect(response.status()).toBe(200);
66
+ });
67
+ ```
68
+
69
+ For token-based APIs that require an `Authorization` header, pass it per request:
70
+
71
+ ```typescript
72
+ const response = await request.get('/api/protected', {
73
+ headers: { Authorization: `Bearer ${process.env.QA_API_TOKEN}` },
74
+ });
75
+ ```
76
+
77
+ See `tests/example.spec.ts` for a starter test to replace.
@@ -0,0 +1,119 @@
1
+ /**
2
+ * global-setup.ts - Integration (API-only) project
3
+ *
4
+ * Runs once before all test files to establish auth state.
5
+ *
6
+ * Two strategies, tried in order:
7
+ * 1. Token-based: QA_API_TOKEN is set -> write a minimal storageState with the
8
+ * token in localStorage so the `request` fixture picks it up automatically.
9
+ * 2. Browser login: QA_USER_EMAIL + QA_USER_PASSWORD are set -> launch Chromium,
10
+ * perform the login flow, and save the resulting storageState to
11
+ * .auth/api-session.json.
12
+ *
13
+ * Playwright's `storageState` mechanism handles cookies and localStorage for
14
+ * APIRequestContext automatically when `use.storageState` is configured.
15
+ * For token-only APIs that require an Authorization header, set the header
16
+ * directly in each test or extend the `request` fixture in fixtures/base.ts.
17
+ */
18
+
19
+ import * as fs from 'fs';
20
+ import * as path from 'path';
21
+ import { chromium } from '@playwright/test';
22
+ import * as dotenv from 'dotenv';
23
+
24
+ dotenv.config();
25
+
26
+ const AUTH_FILE = path.join(__dirname, '.auth', 'api-session.json');
27
+
28
+ export default async function globalSetup(): Promise<void> {
29
+ fs.mkdirSync(path.dirname(AUTH_FILE), { recursive: true });
30
+
31
+ if (process.env.QA_API_TOKEN) {
32
+ await setupWithToken(process.env.QA_API_TOKEN, process.env.QA_BASE_URL!);
33
+ return;
34
+ }
35
+
36
+ await setupWithBrowserLogin();
37
+ }
38
+
39
+ /**
40
+ * Write a minimal storageState that carries the bearer token in localStorage.
41
+ * Replace the localStorage key/value format if your app uses a different scheme
42
+ * (e.g. a cookie, or a different localStorage key name).
43
+ */
44
+ async function setupWithToken(token: string, baseURL: string): Promise<void> {
45
+ const origin = baseURL.replace(/\/$/, '');
46
+
47
+ const state = {
48
+ cookies: [],
49
+ origins: [
50
+ {
51
+ origin,
52
+ localStorage: [
53
+ { name: 'qa_api_token', value: token },
54
+ ],
55
+ },
56
+ ],
57
+ };
58
+
59
+ fs.writeFileSync(AUTH_FILE, JSON.stringify(state, null, 2), 'utf-8');
60
+ console.log('[integration-setup] Token-based auth written to api-session.json');
61
+ }
62
+
63
+ /**
64
+ * Perform a browser login and save the resulting cookies + localStorage to disk.
65
+ *
66
+ * Configure login form selectors via env vars (see .env.example) or update the
67
+ * defaults below to match your application's login page.
68
+ */
69
+ async function setupWithBrowserLogin(): Promise<void> {
70
+ const baseURL = process.env.QA_BASE_URL!.replace(/\/$/, '');
71
+ const email = process.env.QA_USER_EMAIL!;
72
+ const password = process.env.QA_USER_PASSWORD!;
73
+ const loginPath = process.env.QA_LOGIN_PATH ?? '/login';
74
+ const emailSelector = process.env.QA_LOGIN_EMAIL_SELECTOR ?? 'input[type="email"]';
75
+ const passwordSelector = process.env.QA_LOGIN_PASSWORD_SELECTOR ?? 'input[type="password"]';
76
+ const submitSelector = process.env.QA_LOGIN_SUBMIT_SELECTOR ?? 'button[type="submit"]';
77
+ const successSelector = process.env.QA_LOGIN_SUCCESS_SELECTOR ?? '.dashboard, .main-content, [data-testid="app-shell"]';
78
+
79
+ console.log('[integration-setup] Performing browser login...');
80
+
81
+ const browser = await chromium.launch();
82
+ const context = await browser.newContext();
83
+ const page = await context.newPage();
84
+
85
+ try {
86
+ await page.goto(`${baseURL}${loginPath}`, { waitUntil: 'load', timeout: 60_000 });
87
+
88
+ await page.locator(emailSelector).waitFor({ state: 'visible', timeout: 30_000 });
89
+ await page.locator(emailSelector).fill(email);
90
+ // Trace safety: Playwright records fill() argument values in traces, so a project
91
+ // that enables trace/video capture would persist the plaintext password in its
92
+ // artifacts. Setting the value through evaluate() keeps it out of the trace.
93
+ // Do not "simplify" this back to fill().
94
+ // The input/change events are required because assigning .value directly does
95
+ // not notify SPA frameworks (Blazor/Radzen bind on those events).
96
+ // evaluate() has no auto-wait, so the explicit waitFor replaces the one that
97
+ // locator().fill() performed implicitly.
98
+ await page.locator(passwordSelector).waitFor({ state: 'visible', timeout: 30_000 });
99
+ await page.evaluate(
100
+ ([selector, pwd]) => {
101
+ const input = document.querySelector(selector) as HTMLInputElement | null;
102
+ if (!input) {
103
+ throw new Error(`[qa-framework] Password input not found for selector: ${selector}`);
104
+ }
105
+ input.value = pwd;
106
+ input.dispatchEvent(new Event('input', { bubbles: true }));
107
+ input.dispatchEvent(new Event('change', { bubbles: true }));
108
+ },
109
+ [passwordSelector, password] as const
110
+ );
111
+ await page.locator(submitSelector).click();
112
+ await page.waitForSelector(successSelector, { timeout: 60_000 });
113
+
114
+ await context.storageState({ path: AUTH_FILE });
115
+ console.log(`[integration-setup] Auth saved: ${AUTH_FILE}`);
116
+ } finally {
117
+ await browser.close();
118
+ }
119
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "qa-integration-tests",
3
+ "version": "1.0.0",
4
+ "description": "API integration tests - no browser required",
5
+ "private": true,
6
+ "scripts": {
7
+ "test": "playwright test",
8
+ "test:ci": "CI=true playwright test",
9
+ "report": "playwright show-report"
10
+ },
11
+ "devDependencies": {
12
+ "@playwright/test": "^1.44.0",
13
+ "dotenv": "^16.4.0"
14
+ }
15
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * playwright.config.ts - API integration test project (no browser)
3
+ *
4
+ * All tests use APIRequestContext directly. No browser projects are defined.
5
+ * Auth is handled by global-setup.ts, which writes .auth/api-session.json.
6
+ *
7
+ * Required env vars:
8
+ * QA_BASE_URL - Base URL of the API under test
9
+ *
10
+ * Auth (at least one of the following):
11
+ * QA_API_TOKEN - Bearer token (skips browser login in global-setup)
12
+ * QA_USER_EMAIL + QA_USER_PASSWORD - Credentials for browser-based login
13
+ */
14
+
15
+ import { defineConfig } from '@playwright/test';
16
+ import * as dotenv from 'dotenv';
17
+ import * as fs from 'fs';
18
+
19
+ // Least privilege: read only the keys this config actually uses. dotenv.parse() returns
20
+ // a plain object without touching process.env, so the other secrets in .env - the other
21
+ // QA accounts, ADO tokens - are never loaded into a process that has no use for them.
22
+ // QA_USER_PASSWORD is included because the credentials check below reads it; its value
23
+ // is only tested for presence, never logged. Do not "simplify" this back to config().
24
+ const ENV_KEYS = ['QA_BASE_URL', 'QA_API_TOKEN', 'QA_USER_EMAIL', 'QA_USER_PASSWORD'] as const;
25
+ if (fs.existsSync('.env')) {
26
+ const parsed = dotenv.parse(fs.readFileSync('.env'));
27
+ for (const key of ENV_KEYS) {
28
+ if (process.env[key] === undefined && parsed[key] !== undefined) {
29
+ process.env[key] = parsed[key];
30
+ }
31
+ }
32
+ }
33
+
34
+ const required = ['QA_BASE_URL'];
35
+ for (const key of required) {
36
+ if (!process.env[key]) {
37
+ throw new Error(`[integration] Missing required env var: ${key}. Check your .env file.`);
38
+ }
39
+ }
40
+
41
+ const hasToken = !!process.env.QA_API_TOKEN;
42
+ const hasCredentials = !!(process.env.QA_USER_EMAIL && process.env.QA_USER_PASSWORD);
43
+
44
+ if (!hasToken && !hasCredentials) {
45
+ throw new Error(
46
+ '[integration] No auth configured. Set QA_API_TOKEN, or both QA_USER_EMAIL and QA_USER_PASSWORD.',
47
+ );
48
+ }
49
+
50
+ // Optional: Azure DevOps reporter configuration
51
+ // To enable: set env vars ADO_ORG, ADO_PROJECT, ADO_PAT, ADO_PLAN_ID and CI=true,
52
+ // then uncomment the reporter entry in the `reporter` array below.
53
+ // Install: npm install @alex_neo/playwright-azure-reporter --save-dev
54
+ // const adoReporterConfig = {
55
+ // orgUrl: `https://dev.azure.com/${process.env.ADO_ORG}`,
56
+ // token: process.env.SYSTEM_ACCESSTOKEN ?? process.env.ADO_PAT,
57
+ // planId: Number(process.env.ADO_PLAN_ID),
58
+ // projectName: process.env.ADO_PROJECT!,
59
+ // testRunTitle: `[Auto API] ${new Date().toISOString().slice(0, 10)}`,
60
+ // publishTestResultsMode: 'testRun' as const,
61
+ // uploadAttachments: false,
62
+ // isDisabled: !process.env.CI,
63
+ // autoMarkTestCasesAsAutomated: {
64
+ // enabled: true,
65
+ // updateAutomatedTestName: true,
66
+ // updateAutomatedTestStorage: true,
67
+ // },
68
+ // };
69
+
70
+ export default defineConfig({
71
+ testDir: './tests',
72
+ fullyParallel: false,
73
+ workers: 1,
74
+ timeout: 30_000,
75
+ retries: process.env.CI ? 1 : 0,
76
+
77
+ globalSetup: './global-setup.ts',
78
+
79
+ reporter: [
80
+ ['list'],
81
+ ['html', { open: 'never', outputFolder: 'playwright-report' }],
82
+ // Uncomment for ADO:
83
+ // ['@alex_neo/playwright-azure-reporter', adoReporterConfig],
84
+ ],
85
+
86
+ use: {
87
+ baseURL: process.env.QA_BASE_URL,
88
+ storageState: '.auth/api-session.json',
89
+ },
90
+
91
+ outputDir: 'test-results/',
92
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * example.spec.ts - API integration test example
3
+ *
4
+ * This file shows the basic pattern for API tests using Playwright's
5
+ * APIRequestContext. Replace this with your real tests.
6
+ *
7
+ * The `request` fixture is pre-configured with:
8
+ * - baseURL from QA_BASE_URL
9
+ * - storageState from .auth/api-session.json (set by global-setup.ts)
10
+ *
11
+ * For token-based APIs that require an Authorization header, add it
12
+ * explicitly per request or extend the fixture in a fixtures/base.ts file.
13
+ */
14
+
15
+ import { test, expect } from '@playwright/test';
16
+
17
+ // Replace with the actual health/status endpoint of your API.
18
+ const HEALTH_ENDPOINT = '/health';
19
+
20
+ test.describe('API smoke tests', () => {
21
+
22
+ test('GET health endpoint returns 200', async ({ request }) => {
23
+ const response = await request.get(HEALTH_ENDPOINT);
24
+
25
+ expect(response.status()).toBe(200);
26
+ });
27
+
28
+ // Example of a test with an Authorization header when QA_API_TOKEN is set.
29
+ // Uncomment and adapt when your API uses Bearer token auth.
30
+ //
31
+ // test('GET protected resource returns 200 with bearer token', async ({ request }) => {
32
+ // const response = await request.get('/api/me', {
33
+ // headers: {
34
+ // Authorization: `Bearer ${process.env.QA_API_TOKEN}`,
35
+ // },
36
+ // });
37
+ //
38
+ // expect(response.status()).toBe(200);
39
+ // const body = await response.json();
40
+ // expect(body).toHaveProperty('id');
41
+ // });
42
+
43
+ });
@@ -0,0 +1,36 @@
1
+ # CI Pipeline Findings
2
+
3
+ > Document CI pipeline issues, root causes, and applied fixes as they are discovered.
4
+ > This file is loaded by the agent when diagnosing CI failures or reviewing pipeline changes.
5
+
6
+ ## Applied Fixes
7
+
8
+ Document each fix that was applied to the pipeline or test setup. Use a table or prose - whatever fits the change.
9
+
10
+ | Problem | Root cause | Fix applied |
11
+ |---|---|---|
12
+ | _Add pipeline issue here_ | _Root cause_ | _What was changed and where_ |
13
+
14
+ > Examples: auth setup defaults, missing reporter packages, artifact name collisions,
15
+ > browser binary not installed in a CI stage, grep flag escaping issues.
16
+
17
+ ## Known Limitations
18
+
19
+ Document constraints that are accepted but not fixed (timeout budgets, worker counts, retry behavior).
20
+
21
+ > Examples:
22
+ > - Full suite exceeds the CI timeout with 1 worker. Workaround: run only P0/P1 tags by default.
23
+ > - `retries: 2` counts each attempt separately, so reported execution count exceeds test count.
24
+ > - Attachment upload warnings on `PublishTestResults` when multiple failures share filenames.
25
+
26
+ ## Failure Triage Categories
27
+
28
+ Use these categories when classifying CI failures. Add project-specific categories as needed.
29
+
30
+ | Category | Description | Action |
31
+ |---|---|---|
32
+ | TIMEOUT | Test exceeded its time budget | Adjust `timeout` in the spec or in `playwright.config.ts` |
33
+ | SESSION | Auth session expired mid-run | Implement session-refresh fixture or reduce suite duration |
34
+ | FLAKY | Intermittent failure, passes on retry | Acceptable if retries cover it; investigate if failure rate > 20% |
35
+ | APP-DEFECT | Application does not meet the spec | Open defect file; mark test with `test.fail()` |
36
+ | TEST-CODE | Selector or assertion is wrong in CI | Fix the spec file |
@@ -0,0 +1,70 @@
1
+ # Data Volatility Strategies
2
+
3
+ > The QA environment is typically shared between automated tests and manual testers.
4
+ > Data (record counts, available filter values, document states) changes constantly,
5
+ > which invalidates hardcoded values in specs. Document the chosen strategy here.
6
+
7
+ ## Problem
8
+
9
+ List the types of data that are volatile in this project's QA environment.
10
+
11
+ | Data type | Example of fragile assertion | Tests affected |
12
+ |---|---|---|
13
+ | Filter option values | `hasText: 'specific-value'` | _Add count here_ |
14
+ | Exact row counts | `toBe(33)` | _Add count here_ |
15
+ | Record names used as search inputs | `fill('specific-record-name')` | _Add count here_ |
16
+ | Process or transaction IDs | `TEST_ID = '608'` | _Add count here_ |
17
+
18
+ ## Strategy 1: Shared Constants with Dynamic Discovery
19
+
20
+ Maintain a `fixtures/test-data-constants.ts` file with well-named constants. Populate them
21
+ from a discovery step (global-setup or a `beforeAll` fixture) that reads the actual environment.
22
+
23
+ ```typescript
24
+ // fixtures/test-data-constants.ts
25
+ export const QA_ITEM_CURRENT = 'current-item-name'; // most recent available
26
+ export const QA_ITEM_OLDEST = 'oldest-item-name'; // oldest available
27
+ export const QA_ITEM_INVALID = 'nonexistent-item'; // guaranteed absent
28
+ ```
29
+
30
+ **Tradeoff:** eliminates hardcoded filter values centrally, but discovery adds startup time
31
+ and blocks the suite if it fails.
32
+
33
+ ## Strategy 2: Resilient Assertions (Patterns and Ranges)
34
+
35
+ Replace exact-value assertions with pattern or range checks.
36
+
37
+ ```typescript
38
+ // Instead of:
39
+ expect(count).toBe(33);
40
+ await expect(counter).toHaveText('1-5 of 5');
41
+
42
+ // Use:
43
+ expect(count).toBeGreaterThan(0);
44
+ await expect(counter).toHaveText(/\d+-\d+ of \d+/);
45
+ ```
46
+
47
+ **Tradeoff:** no extra infrastructure, each test is self-contained, but precision is lower.
48
+ Useful for count assertions; less useful for filter-value selection.
49
+
50
+ ## Strategy 3: Snapshot Delta Validation
51
+
52
+ Capture the initial state before applying a filter, then assert that the filtered state
53
+ differs from the initial state in the expected direction (fewer rows, etc.).
54
+
55
+ **Tradeoff:** maximum resilience, but tests become longer and harder to trace. Use only for
56
+ critical filter tests where behavior (not data) must be validated.
57
+
58
+ ## Chosen Approach
59
+
60
+ > Document which strategy (or combination) was chosen for this project, and which test
61
+ > categories each strategy applies to.
62
+
63
+ | Test category | Strategy | Status |
64
+ |---|---|---|
65
+ | Filter option values | Strategy 1 or 2 | _Pending / Implemented_ |
66
+ | Row count assertions | Strategy 2 | _Pending / Implemented_ |
67
+ | Search input values | Strategy 2 or 3 | _Pending / Implemented_ |
68
+
69
+ > Tests that are blocked on a data strategy can be marked `test.skip()` with a
70
+ > `PENDING-DATA-STRATEGY` annotation until the strategy is implemented.
@@ -0,0 +1,54 @@
1
+ # E2E Stabilization Patterns
2
+
3
+ > A running log of flakiness patterns found in this project and the techniques used to fix them.
4
+ > Load this file when investigating intermittent test failures or refactoring fragile specs.
5
+
6
+ ## Crash-Recovery Pattern
7
+
8
+ When the application server crashes intermittently (e.g. unhandled error page with a Reload link),
9
+ a bare `waitFor` will timeout. Use `Promise.race` to detect the error state and recover:
10
+
11
+ ```typescript
12
+ const outcome = await Promise.race([
13
+ targetElement.waitFor({ state: 'visible', timeout: 60_000 }).then(() => 'ready' as const),
14
+ page.getByText('An unhandled error has occurred.').waitFor({ state: 'visible', timeout: 60_000 }).then(() => 'crash' as const),
15
+ ]).catch(() => 'timeout' as const);
16
+
17
+ if (outcome === 'crash') {
18
+ await page.getByRole('link', { name: 'Reload' }).click();
19
+ await targetElement.waitFor({ state: 'visible', timeout: 60_000 });
20
+ }
21
+ ```
22
+
23
+ > Document which spec files use this pattern and under what conditions it fires.
24
+
25
+ ## Strict-Mode Selector Conflicts
26
+
27
+ `getByText()` and similar matchers can match multiple elements, triggering strict-mode violations.
28
+ Scope selectors to the most specific container available.
29
+
30
+ > Document conflicts found in this project here.
31
+ > Example: a pagination counter regex that also matches a card element.
32
+ > Fix: use a scoped `locator('.specific-class')` instead of a broad text match.
33
+
34
+ ## Known Flaky Failure Types
35
+
36
+ Document categories of instability specific to this project. A row per pattern is enough.
37
+
38
+ | ID | Root cause | Fix | Affected tests |
39
+ |---|---|---|---|
40
+ | _Add ID_ | _Describe the underlying cause_ | _Technique used to fix_ | _Spec files or TC IDs_ |
41
+
42
+ > Examples: framework hydration delays, input binding issues requiring `pressSequentially`,
43
+ > elements that are in the DOM but not yet rendered, session expiry during long runs.
44
+
45
+ ## Reference Timeouts
46
+
47
+ Fill in the timeout values used in this project once they are stabilized.
48
+
49
+ | Setting | Value | Location |
50
+ |---|---|---|
51
+ | Default test timeout | - | `playwright.config.ts` |
52
+ | `actionTimeout` | - | `playwright.config.ts` |
53
+ | `navigationTimeout` | - | `playwright.config.ts` |
54
+ | Long-running spec timeout | - | Per-spec `describe.configure` |
@@ -8,7 +8,7 @@ This project uses `@keber/qa-framework` v{{VERSION}} for spec-driven automated t
8
8
  ## Agent behavior rules
9
9
 
10
10
  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.
11
- 1. Before performing any QA task, load the relevant skill from `.github/skills/`. For project context, read `qa/memory/INDEX.md` if it exists, then load only the memory files relevant to the current task — do not load all memory files unconditionally. Never execute a pipeline stage unless its prerequisite is satisfied.
11
+ 1. Before performing any QA task, load the relevant skill from `.github/skills/`. For project context, read `qa/memory/INDEX.md` if it exists, then load only the memory files relevant to the current task - do not load all memory files unconditionally. Never execute a pipeline stage unless its prerequisite is satisfied.
12
12
  2. Always save artifacts in the correct `qa/` subfolder - refer to `qa/QA-STRUCTURE-GUIDE.md`
13
13
  3. Never hardcode credentials - always use env vars and `<PLACEHOLDER>` in documentation
14
14
  4. Follow the naming conventions in `qa/00-standards/naming-conventions.md`
@@ -16,15 +16,24 @@ This project uses `@keber/qa-framework` v{{VERSION}} for spec-driven automated t
16
16
  6. Project QA config is at `qa/qa-framework.config.json`
17
17
  7. Save learnings in `qa/memory/` with proper naming and metadata. Always update `qa/memory/INDEX.md` after adding or updating any memory file.
18
18
  8. **Sprint/module completion criteria:** A sprint or module is complete when every TC in scope has one of these three valid states - and no other: (a) `test()` passing: the app meets the spec; (b) `test.fail()`: the app violates the spec **and** a file `qa/06-defects/open/DEF-SIS-NNN_*.md` exists documenting which business rule is violated and what the app actually does; (c) `test.skip()`: the TC is not yet executable, annotated with `PENDING-CODE` and a linked issue. A sprint is **not** complete if any TC is failing without `test.fail()`, or has `test.fail()` without a defect file, or has `test.skip()` without a `PENDING-CODE` reason.
19
- 9. **On sprint/module completion:** (1) update the module status row in `qa/README.md`; (2) move the completed sprint checklist from `AGENT-NEXT-STEPS.md` to the `## Sprint History` section of `qa/README.md`; (3) trim `AGENT-NEXT-STEPS.md` so it contains only the next sprint — never let it accumulate more than one active sprint.
20
- 10. **Assertion polarity rule (BLOCKING):** A test must assert what the **spec** requires, not what the app currently does. If the app fails to meet the spec, use `test.fail()` + correct assertion to document the defect — **never invert or weaken an assertion to make a test go green.** A failing test that exposes a real defect is always more valuable than a passing test that hides one.
19
+ 9. **On sprint/module completion:** (1) update the module status row in `qa/README.md`; (2) move the completed sprint checklist from `AGENT-NEXT-STEPS.md` to the `## Sprint History` section of `qa/README.md`; (3) trim `AGENT-NEXT-STEPS.md` so it contains only the next sprint - never let it accumulate more than one active sprint.
20
+ 10. **Assertion polarity rule (BLOCKING):** A test must assert what the **spec** requires, not what the app currently does. If the app fails to meet the spec, use `test.fail()` + correct assertion to document the defect - **never invert or weaken an assertion to make a test go green.** A failing test that exposes a real defect is always more valuable than a passing test that hides one.
21
21
  11. **Character encoding safety (BLOCKING):** In ALL generated content (markdown, scripts, test titles, ADO fields, config files), never use characters at these Unicode code points: em-dash (U+2014), en-dash (U+2013), horizontal ellipsis (U+2026), smart/curly quotes (U+201C, U+201D, U+2018, U+2019), or directional arrows (U+2190-U+21FF). Use ASCII equivalents instead: ` - ` (hyphen with surrounding spaces) for dashes, `...` for ellipsis, `"` and `'` for quotes, `->` and `<-` for arrows. Exception: Latin Extended characters (U+00C0-U+024F) are always permitted - this covers Spanish vowels with accents (U+00E0-U+00FA), n with tilde (U+00F1/U+00D1), and u/o with umlaut (U+00FC/U+00DC, U+00F6/U+00D6).
22
+ 12. **Lane lock for parallel QA execution (BLOCKING):** Parallel QA lanes exist because the applications under test invalidate a session when the same account logs in again - two concurrent workers on one account silently destroy each other's session, and the damage surfaces later as an unexplained logout or as evidence recorded under the wrong account. Before dispatching any worker (sub-agent, test runner project, or CI job) against one of the lanes configured in `parallelLanes.lanes` in `qa/qa-framework.config.json`, **acquire a lane through the project's lane-lock script and release it when the work is done.** Never assign a lane by prompt or config alone without going through the lock. Use `acquire` when the worker does not care which lane it gets, and `reserve <laneId>` when it needs a specific predictable lane (a CI job or a local CLI run) - these are two verbs because there are two use cases, and collapsing them is how a CI job lands on a random lane. If no lane is free, queue (capped at the configured lane count) or reject - **never force a lane assignment past that cap.** Check that a lane actually has the capability a worker needs before handing it over: capabilities are per-lane, so a lane that lacks (for example) an MCP server must not be given to a worker that needs one. A held lane is swept as stale only after the configured threshold and only when no recent heartbeat proves the holder alive, so **the dispatcher must keep the lane alive with `heartbeat` while the work is in flight** - do not rely on the dispatched worker to do it, since a worker that was never told the mechanism exists cannot be expected to use it. A lock held far longer than the app's session TTL is a signal to verify, not a defect to ignore; each project's agent-specific instructions define how it verifies a lock is still legitimately held and how it clears a stale one.
22
23
 
23
24
  ## Formatting rules for generated content
24
25
  1. Generate the output in `UTF-8` encoding without BOM (`UTF-8`, no signature).
25
26
  2. Ensure the raw output is `UTF-8` encoded with no `EF BB BF` bytes at the beginning.
26
27
 
27
- {{ADO_SECTION}}
28
+ ## Azure DevOps integration
29
+
30
+ Before any ADO operation, check if `.github/skills/ado-qa/` exists or if
31
+ `integrations.azureDevOps.enabled` is `true` in `qa/qa-framework.config.json`. If either
32
+ condition is met, load `.github/skills/qa-ado-integration/SKILL.md` and use it for
33
+ all ADO interactions (work items, test plans, test cases, bugs, etc.).
34
+
35
+ > To enable Azure DevOps integration run: `npm install github:keber/ado-qa`
36
+
28
37
  ## QA Pipeline
29
38
 
30
39
  Stages must run in order. Never start a stage unless its prerequisite is met.
@@ -38,8 +47,8 @@ Stages must run in order. Never start a stage unless its prerequisite is met.
38
47
  | 5 | Generate automation | `.github/skills/qa-automation/SKILL.md` | Specs approved, no PENDING-CODE |
39
48
  | 5b | Stabilize failing tests | `.github/skills/qa-test-stabilization/SKILL.md` | Failing tests exist |
40
49
  | 6 | Maintenance | `.github/skills/qa-maintenance/SKILL.md` | Application change delivered |
41
- | — | ADO integration | `.github/skills/qa-ado-integration/SKILL.md` | ADO enabled in config |
50
+ | - | ADO integration | `.github/skills/qa-ado-integration/SKILL.md` | ADO enabled in config |
42
51
 
43
52
  ## Project KB
44
- 1. `qa/README.md` — The Living Index: module status, sprint history, blockers, quick-start commands.
45
- 2. `qa/memory/INDEX.md` — Index of all memory files; load this before selecting which files to read.
53
+ 1. `qa/README.md` - The Living Index: module status, sprint history, blockers, quick-start commands.
54
+ 2. `qa/memory/INDEX.md` - Index of all memory files; load this before selecting which files to read.
@@ -0,0 +1,53 @@
1
+ # QA Framework Instructions
2
+
3
+ This project uses `@keber/qa-framework` v{{VERSION}} for spec-driven automated testing.
4
+
5
+ ## Agent behavior rules
6
+
7
+ 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.
8
+ 1. Before performing any QA task, run the corresponding `/qa-{name}` command (see `.claude/commands/`), which loads the relevant skill via `.github/skills/qa-{name}/SKILL.md`. For project context, read `qa/memory/INDEX.md` if it exists, then load only the memory files relevant to the current task - do not load all memory files unconditionally. Never execute a pipeline stage unless its prerequisite is satisfied.
9
+ 2. Always save artifacts in the correct `qa/` subfolder - refer to `qa/QA-STRUCTURE-GUIDE.md`
10
+ 3. Never hardcode credentials - always use env vars and `<PLACEHOLDER>` in documentation
11
+ 4. Follow the naming conventions in `qa/00-standards/naming-conventions.md`
12
+ 5. Read previous test suites code in `qa/07-automation/e2e/tests/` if available before writing new automation to maintain consistency in style and approach
13
+ 6. Project QA config is at `qa/qa-framework.config.json`
14
+ 7. Save learnings in `qa/memory/` with proper naming and metadata. Always update `qa/memory/INDEX.md` after adding or updating any memory file.
15
+ 8. **Sprint/module completion criteria:** A sprint or module is complete when every TC in scope has one of these three valid states - and no other: (a) `test()` passing: the app meets the spec; (b) `test.fail()`: the app violates the spec **and** a file `qa/06-defects/open/DEF-SIS-NNN_*.md` exists documenting which business rule is violated and what the app actually does; (c) `test.skip()`: the TC is not yet executable, annotated with `PENDING-CODE` and a linked issue. A sprint is **not** complete if any TC is failing without `test.fail()`, or has `test.fail()` without a defect file, or has `test.skip()` without a `PENDING-CODE` reason.
16
+ 9. **On sprint/module completion:** (1) update the module status row in `qa/README.md`; (2) move the completed sprint checklist from `AGENT-NEXT-STEPS.md` to the `## Sprint History` section of `qa/README.md`; (3) trim `AGENT-NEXT-STEPS.md` so it contains only the next sprint - never let it accumulate more than one active sprint.
17
+ 10. **Assertion polarity rule (BLOCKING):** A test must assert what the **spec** requires, not what the app currently does. If the app fails to meet the spec, use `test.fail()` + correct assertion to document the defect - **never invert or weaken an assertion to make a test go green.** A failing test that exposes a real defect is always more valuable than a passing test that hides one.
18
+ 11. **Character encoding safety (BLOCKING):** In ALL generated content (markdown, scripts, test titles, ADO fields, config files), never use characters at these Unicode code points: em-dash (U+2014), en-dash (U+2013), horizontal ellipsis (U+2026), smart/curly quotes (U+201C, U+201D, U+2018, U+2019), or directional arrows (U+2190-U+21FF). Use ASCII equivalents instead: ` - ` (hyphen with surrounding spaces) for dashes, `...` for ellipsis, `"` and `'` for quotes, `->` and `<-` for arrows. Exception: Latin Extended characters (U+00C0-U+024F) are always permitted - this covers Spanish vowels with accents (U+00E0-U+00FA), n with tilde (U+00F1/U+00D1), and u/o with umlaut (U+00FC/U+00DC, U+00F6/U+00D6).
19
+
20
+ ## Formatting rules for generated content
21
+ 1. Generate the output in `UTF-8` encoding without BOM (`UTF-8`, no signature).
22
+ 2. Ensure the raw output is `UTF-8` encoded with no `EF BB BF` bytes at the beginning.
23
+
24
+ ## Azure DevOps integration
25
+
26
+ Before any ADO operation, check if `.github/skills/ado-qa/` exists or if
27
+ `integrations.azureDevOps.enabled` is `true` in `qa/qa-framework.config.json`. If either
28
+ condition is met, run `/qa-ado-integration` (see `.claude/commands/`), which loads
29
+ `.github/skills/qa-ado-integration/SKILL.md`, and use it for all ADO interactions
30
+ (work items, test plans, test cases, bugs, etc.).
31
+
32
+ > To enable Azure DevOps integration run: `npm install github:keber/ado-qa`
33
+
34
+ ## QA Pipeline
35
+
36
+ Stages must run in order. Never start a stage unless its prerequisite is met.
37
+
38
+ | Stage | Task | Command | Prerequisite |
39
+ |---|---|---|---|
40
+ | 1 | Analyze module | `/qa-module-analysis` | None |
41
+ | 2 | Generate specifications | `/qa-spec-generation` | 00-inventory.md exists |
42
+ | 3 | Generate test plan | `/qa-test-plan` | 05-test-scenarios.md exists |
43
+ | 4 | Generate test cases | `/qa-test-cases` | Test plan exists |
44
+ | 5 | Generate automation | `/qa-automation` | Specs approved, no PENDING-CODE |
45
+ | 5b | Stabilize failing tests | `/qa-test-stabilization` | Failing tests exist |
46
+ | 6 | Maintenance | `/qa-maintenance` | Application change delivered |
47
+ | - | ADO integration | `/qa-ado-integration` | ADO enabled in config |
48
+
49
+ Each command reads its full skill from `.github/skills/qa-{name}/SKILL.md` before acting - see `.claude/commands/` for the generated wrappers.
50
+
51
+ ## Project KB
52
+ 1. `qa/README.md` - The Living Index: module status, sprint history, blockers, quick-start commands.
53
+ 2. `qa/memory/INDEX.md` - Index of all memory files; load this before selecting which files to read.