@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,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fixtures/test-helpers.ts
|
|
3
|
+
*
|
|
4
|
+
* Utility functions used across all spec files.
|
|
5
|
+
* Import only what you need; keep specs self-contained.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// -----------------------------------------------------------------------
|
|
9
|
+
// EXEC_IDX — unique numeric seed per minute-long execution window
|
|
10
|
+
// -----------------------------------------------------------------------
|
|
11
|
+
// Use this wherever test data needs to be unique (e.g., names, emails,
|
|
12
|
+
// codes) to avoid collisions between parallel or consecutive test runs
|
|
13
|
+
// without relying on random values that are impossible to correlate.
|
|
14
|
+
//
|
|
15
|
+
// Example:
|
|
16
|
+
// const idx = execIdx(); // e.g., 42591
|
|
17
|
+
// const name = `QA-Supplier-${idx}`;
|
|
18
|
+
// -----------------------------------------------------------------------
|
|
19
|
+
export function execIdx(): number {
|
|
20
|
+
return Math.floor(Date.now() / 60_000) % 100_000;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Date string formatted as YYYY-MM-DD in local time. */
|
|
24
|
+
export function todayISO(): string {
|
|
25
|
+
const d = new Date();
|
|
26
|
+
return d.toISOString().slice(0, 10);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Date string formatted as DD/MM/YYYY (common in Spanish-language UIs). */
|
|
30
|
+
export function todayDMY(): string {
|
|
31
|
+
const d = new Date();
|
|
32
|
+
const dd = String(d.getDate()).padStart(2, '0');
|
|
33
|
+
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
34
|
+
return `${dd}/${mm}/${d.getFullYear()}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Future date offset by `days` from today, formatted as YYYY-MM-DD. */
|
|
38
|
+
export function futureDateISO(days: number): string {
|
|
39
|
+
const d = new Date();
|
|
40
|
+
d.setDate(d.getDate() + days);
|
|
41
|
+
return d.toISOString().slice(0, 10);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// -----------------------------------------------------------------------
|
|
45
|
+
// 3-layer email assertion helper
|
|
46
|
+
// -----------------------------------------------------------------------
|
|
47
|
+
// Use this when asserting an email field value to avoid brittle exact-match
|
|
48
|
+
// assertions that break when display format changes.
|
|
49
|
+
//
|
|
50
|
+
// Example:
|
|
51
|
+
// await assertEmailContains(
|
|
52
|
+
// await page.locator('#email-cell').textContent() ?? '',
|
|
53
|
+
// process.env.QA_USER_EMAIL!
|
|
54
|
+
// );
|
|
55
|
+
// -----------------------------------------------------------------------
|
|
56
|
+
export function assertEmailContains(
|
|
57
|
+
actual: string,
|
|
58
|
+
expected: string
|
|
59
|
+
): void {
|
|
60
|
+
const localPart = expected.split('@')[0];
|
|
61
|
+
const domain = expected.split('@')[1];
|
|
62
|
+
if (!actual.includes(localPart)) {
|
|
63
|
+
throw new Error(`Email assertion failed: expected local part "${localPart}" in "${actual}"`);
|
|
64
|
+
}
|
|
65
|
+
if (!actual.includes(domain)) {
|
|
66
|
+
throw new Error(`Email assertion failed: expected domain "${domain}" in "${actual}"`);
|
|
67
|
+
}
|
|
68
|
+
if (!actual.includes('@')) {
|
|
69
|
+
throw new Error(`Email assertion failed: no "@" symbol found in "${actual}"`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// -----------------------------------------------------------------------
|
|
74
|
+
// Unique test string builder
|
|
75
|
+
// -----------------------------------------------------------------------
|
|
76
|
+
// Combines a readable prefix with EXEC_IDX for easy triage in QA data.
|
|
77
|
+
// -----------------------------------------------------------------------
|
|
78
|
+
export function uniqueName(prefix: string): string {
|
|
79
|
+
return `${prefix}-${execIdx()}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Unique email address for test isolation (uses execIdx). */
|
|
83
|
+
export function uniqueEmail(domain = 'qa-test.example.com'): string {
|
|
84
|
+
return `qa-user-${execIdx()}@${domain}`;
|
|
85
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* global-setup.ts
|
|
3
|
+
*
|
|
4
|
+
* Runs ONCE before all test files.
|
|
5
|
+
* Logs in as the default QA user and saves storageState so each test
|
|
6
|
+
* doesn't need to repeat the login flow.
|
|
7
|
+
*
|
|
8
|
+
* For multi-role projects:
|
|
9
|
+
* - Add additional loginAs() calls below, one per role.
|
|
10
|
+
* - Save each to `.auth/user-{role}.json`.
|
|
11
|
+
* - Reference the matching storageState in playwright.config.ts projects[].
|
|
12
|
+
*
|
|
13
|
+
* Environment variables required:
|
|
14
|
+
* QA_BASE_URL — Base URL of the application under test
|
|
15
|
+
* QA_USER_EMAIL — Default QA user email (or username/RUT)
|
|
16
|
+
* QA_USER_PASSWORD — Default QA user password
|
|
17
|
+
* QA_LOGIN_PATH — Relative path to the login page (default: /login)
|
|
18
|
+
* QA_LOGIN_EMAIL_SELECTOR — CSS selector for the username/email input
|
|
19
|
+
* QA_LOGIN_PASSWORD_SELECTOR — CSS selector for the password input
|
|
20
|
+
* QA_LOGIN_SUBMIT_SELECTOR — CSS selector for the submit button
|
|
21
|
+
* QA_LOGIN_SUCCESS_SELECTOR — CSS selector that confirms successful login
|
|
22
|
+
*
|
|
23
|
+
* See .env.example for all supported variables.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { chromium, FullConfig } from '@playwright/test';
|
|
27
|
+
import * as dotenv from 'dotenv';
|
|
28
|
+
import * as path from 'path';
|
|
29
|
+
import * as fs from 'fs';
|
|
30
|
+
|
|
31
|
+
dotenv.config();
|
|
32
|
+
|
|
33
|
+
/** Perform login and persist storageState to disk. */
|
|
34
|
+
async function loginAs(params: {
|
|
35
|
+
email: string;
|
|
36
|
+
password: string;
|
|
37
|
+
baseURL: string;
|
|
38
|
+
loginPath?: string;
|
|
39
|
+
emailSelector?: string;
|
|
40
|
+
passwordSelector?: string;
|
|
41
|
+
submitSelector?: string;
|
|
42
|
+
successSelector?: string;
|
|
43
|
+
stateFile: string;
|
|
44
|
+
}): Promise<void> {
|
|
45
|
+
const {
|
|
46
|
+
email,
|
|
47
|
+
password,
|
|
48
|
+
baseURL,
|
|
49
|
+
loginPath = process.env.QA_LOGIN_PATH ?? '/login',
|
|
50
|
+
emailSelector = process.env.QA_LOGIN_EMAIL_SELECTOR ?? 'input[type="email"]',
|
|
51
|
+
passwordSelector = process.env.QA_LOGIN_PASSWORD_SELECTOR ?? 'input[type="password"]',
|
|
52
|
+
submitSelector = process.env.QA_LOGIN_SUBMIT_SELECTOR ?? 'button[type="submit"]',
|
|
53
|
+
successSelector = process.env.QA_LOGIN_SUCCESS_SELECTOR ?? '.dashboard, .main-content, [data-testid="app-shell"]',
|
|
54
|
+
stateFile,
|
|
55
|
+
} = params;
|
|
56
|
+
|
|
57
|
+
const browser = await chromium.launch();
|
|
58
|
+
const context = await browser.newContext();
|
|
59
|
+
const page = await context.newPage();
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
await page.goto(`${baseURL}${loginPath}`, { waitUntil: 'domcontentloaded' });
|
|
63
|
+
await page.locator(emailSelector).fill(email);
|
|
64
|
+
await page.locator(passwordSelector).fill(password);
|
|
65
|
+
await page.locator(submitSelector).click();
|
|
66
|
+
await page.waitForSelector(successSelector, { timeout: 15_000 });
|
|
67
|
+
|
|
68
|
+
// Ensure .auth/ directory exists
|
|
69
|
+
const dir = path.dirname(stateFile);
|
|
70
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
71
|
+
|
|
72
|
+
await context.storageState({ path: stateFile });
|
|
73
|
+
console.log(`[global-setup] storageState saved: ${stateFile}`);
|
|
74
|
+
} finally {
|
|
75
|
+
await browser.close();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default async function globalSetup(_config: FullConfig): Promise<void> {
|
|
80
|
+
const baseURL = process.env.QA_BASE_URL!;
|
|
81
|
+
const email = process.env.QA_USER_EMAIL!;
|
|
82
|
+
const password = process.env.QA_USER_PASSWORD!;
|
|
83
|
+
|
|
84
|
+
// --- Default role login ---
|
|
85
|
+
await loginAs({
|
|
86
|
+
email,
|
|
87
|
+
password,
|
|
88
|
+
baseURL,
|
|
89
|
+
stateFile: '.auth/user-default.json',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// --- Additional roles (uncomment and adapt as needed) ---
|
|
93
|
+
// await loginAs({
|
|
94
|
+
// email: process.env.QA_ADMIN_EMAIL!,
|
|
95
|
+
// password: process.env.QA_ADMIN_PASSWORD!,
|
|
96
|
+
// baseURL,
|
|
97
|
+
// stateFile: '.auth/user-admin.json',
|
|
98
|
+
// });
|
|
99
|
+
//
|
|
100
|
+
// await loginAs({
|
|
101
|
+
// email: process.env.QA_READONLY_EMAIL!,
|
|
102
|
+
// password: process.env.QA_READONLY_PASSWORD!,
|
|
103
|
+
// baseURL,
|
|
104
|
+
// stateFile: '.auth/user-readonly.json',
|
|
105
|
+
// });
|
|
106
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}-qa-e2e",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "E2E Playwright test suite for {{PROJECT_NAME}}",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "playwright test",
|
|
8
|
+
"test:headed": "playwright test --headed",
|
|
9
|
+
"test:debug": "playwright test --debug",
|
|
10
|
+
"test:ui": "playwright test --ui",
|
|
11
|
+
"test:p0": "playwright test --grep @P0",
|
|
12
|
+
"test:p1": "playwright test --grep \"@P0|@P1\"",
|
|
13
|
+
"test:module": "playwright test --grep {{MODULE_PATTERN}}",
|
|
14
|
+
"report": "playwright show-report",
|
|
15
|
+
"validate": "npx keber/qa-framework validate"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@playwright/test": "^1.40.0",
|
|
19
|
+
"dotenv": "^16.0.0"
|
|
20
|
+
},
|
|
21
|
+
"optionalDependencies": {
|
|
22
|
+
"@alex_neo/playwright-azure-reporter": "^2.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
import * as dotenv from 'dotenv';
|
|
3
|
+
dotenv.config();
|
|
4
|
+
|
|
5
|
+
// -------------------------------------------------------------------
|
|
6
|
+
// Validate required environment variables at config load time
|
|
7
|
+
// -------------------------------------------------------------------
|
|
8
|
+
const required = ['QA_BASE_URL', 'QA_USER_EMAIL', 'QA_USER_PASSWORD'];
|
|
9
|
+
for (const key of required) {
|
|
10
|
+
if (!process.env[key]) {
|
|
11
|
+
throw new Error(`[qa-framework] Missing required env var: ${key}. Check your .env file.`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Optional: Azure DevOps reporter configuration
|
|
16
|
+
// Uncomment and fill in when ADO integration is enabled.
|
|
17
|
+
// import { AzureReporter } from '@alex_neo/playwright-azure-reporter';
|
|
18
|
+
// const adoConfig = {
|
|
19
|
+
// token: process.env.AZURE_TOKEN!,
|
|
20
|
+
// planId: Number(process.env.ADO_PLAN_ID),
|
|
21
|
+
// projectName: process.env.ADO_PROJECT_NAME!,
|
|
22
|
+
// orgUrl: process.env.ADO_ORG_URL!,
|
|
23
|
+
// testRunTitle: `[Automated] Sprint {{NNN}} — ${new Date().toISOString().slice(0, 10)}`,
|
|
24
|
+
// publishResultsOnFailure: true,
|
|
25
|
+
// isDisabled: process.env.ADO_SYNC_DISABLED === 'true',
|
|
26
|
+
// };
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
// ------ Test discovery ------
|
|
30
|
+
testDir: '.',
|
|
31
|
+
// Use any subdir pattern your project standardizes on, e.g.:
|
|
32
|
+
// testMatch: ['**/*.spec.ts'],
|
|
33
|
+
|
|
34
|
+
// ------ Parallelism ------
|
|
35
|
+
// Keep fullyParallel:false when tests share storageState / session data.
|
|
36
|
+
fullyParallel: false,
|
|
37
|
+
workers: 1,
|
|
38
|
+
|
|
39
|
+
// ------ Retry strategy ------
|
|
40
|
+
retries: process.env.CI ? 1 : 0,
|
|
41
|
+
|
|
42
|
+
// ------ Reporter ------
|
|
43
|
+
reporter: [
|
|
44
|
+
['html', { open: 'never' }],
|
|
45
|
+
['list'],
|
|
46
|
+
// Uncomment for ADO:
|
|
47
|
+
// ['@alex_neo/playwright-azure-reporter', adoConfig],
|
|
48
|
+
],
|
|
49
|
+
|
|
50
|
+
// ------ Global settings ------
|
|
51
|
+
use: {
|
|
52
|
+
baseURL: process.env.QA_BASE_URL,
|
|
53
|
+
headless: true,
|
|
54
|
+
screenshot: 'only-on-failure',
|
|
55
|
+
video: 'retain-on-failure',
|
|
56
|
+
trace: 'retain-on-failure',
|
|
57
|
+
actionTimeout: 15_000,
|
|
58
|
+
navigationTimeout: 30_000,
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// ------ Auth setup ------
|
|
62
|
+
// global-setup.ts logs in once and saves storageState per role.
|
|
63
|
+
globalSetup: './global-setup.ts',
|
|
64
|
+
|
|
65
|
+
// ------ Projects ------
|
|
66
|
+
projects: [
|
|
67
|
+
{
|
|
68
|
+
name: 'setup',
|
|
69
|
+
use: { ...devices['Desktop Chrome'] },
|
|
70
|
+
testMatch: /global-setup\.ts/,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'chromium',
|
|
74
|
+
use: {
|
|
75
|
+
...devices['Desktop Chrome'],
|
|
76
|
+
storageState: '.auth/user-default.json',
|
|
77
|
+
},
|
|
78
|
+
dependencies: ['setup'],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
|
|
82
|
+
// ------ Output directories ------
|
|
83
|
+
outputDir: 'test-results/',
|
|
84
|
+
snapshotPathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}',
|
|
85
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Bug Report — DEF-{{NNN}}: {{Short Title}}
|
|
2
|
+
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|-------|-------|
|
|
5
|
+
| Bug ID | DEF-{{NNN}} |
|
|
6
|
+
| Title | {{Short title (max 80 chars)}} |
|
|
7
|
+
| Severity | Critical / High / Medium / Low |
|
|
8
|
+
| Priority | P0 / P1 / P2 / P3 |
|
|
9
|
+
| Status | Open / In Progress / Resolved / Closed |
|
|
10
|
+
| Assigned to | {{Developer or "Unassigned"}} |
|
|
11
|
+
| Module | {{Module name}} |
|
|
12
|
+
| Submodule | {{Submodule name}} |
|
|
13
|
+
| Environment | QA ({{QA_BASE_URL}}) |
|
|
14
|
+
| Browser | Chromium {{version}} |
|
|
15
|
+
| Date reported | YYYY-MM-DD |
|
|
16
|
+
| ADO WI | #{ADO_WORK_ITEM_ID} (if ADO enabled) |
|
|
17
|
+
| Related TCs | TC-{{M}}-{{S}}-{{NNN}} |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Description
|
|
22
|
+
|
|
23
|
+
{{1-2 sentences describing what the bug is and where it occurs}}
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Steps to Reproduce
|
|
28
|
+
|
|
29
|
+
| Step | Action |
|
|
30
|
+
|------|--------|
|
|
31
|
+
| 1 | Navigate to `{{QA_BASE_URL}}/{{path}}` as `{{role}}` |
|
|
32
|
+
| 2 | {{action}} |
|
|
33
|
+
| 3 | {{action}} |
|
|
34
|
+
| 4 | Observe `{{element}}` |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Expected Result
|
|
39
|
+
|
|
40
|
+
{{What should happen according to business rules RN-{{M}}-{{NNN}}}}
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Actual Result
|
|
45
|
+
|
|
46
|
+
{{What actually happens}}
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Evidence
|
|
51
|
+
|
|
52
|
+
- Screenshot: `qa/07-automation/e2e/diagnosis/{{NNN}}-{{bug-slug}}.png`
|
|
53
|
+
- Test output: (link to execution report if captured automatically)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Root Cause Analysis
|
|
58
|
+
|
|
59
|
+
{{If known: explain why this happens. If unknown: "Under investigation"}}
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Fix Suggestion
|
|
64
|
+
|
|
65
|
+
{{If known: describe the fix. Example: "Set IND_CORREO default to true in C# model constructor"}}
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Impact on Automation
|
|
70
|
+
|
|
71
|
+
| TC ID | Current test state | Impact |
|
|
72
|
+
|-------|-------------------|--------|
|
|
73
|
+
| TC-{{M}}-{{S}}-{{NNN}} | `test.skip()` added | Test will remain skipped until fix is deployed |
|
|
74
|
+
| TC-{{M}}-{{S}}-{{NNN}} | Assertion adjusted | `toBeFalsy()` documents buggy default |
|
|
75
|
+
|
|
76
|
+
**Test skip command added**:
|
|
77
|
+
```typescript
|
|
78
|
+
test.skip(true,
|
|
79
|
+
'DEF-{{NNN}}: {{description}}. Reactivate when ADO #{{WI_ID}} is resolved.'
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Reactivation Instructions
|
|
86
|
+
|
|
87
|
+
When this bug is fixed:
|
|
88
|
+
1. Remove `test.skip()` from TC-{{M}}-{{S}}-{{NNN}} in `{{spec-file}}`
|
|
89
|
+
2. Restore original assertion (e.g., `toBeTruthy()`)
|
|
90
|
+
3. Run the test at least 2 times with different EXEC_IDX values to confirm stability
|
|
91
|
+
4. Move this file to `06-defects/resolved/`
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Changelog
|
|
96
|
+
|
|
97
|
+
| Version | Date | Description |
|
|
98
|
+
|---------|------|-------------|
|
|
99
|
+
| 1.0 | YYYY-MM-DD | Bug reported |
|
|
100
|
+
| 1.1 | YYYY-MM-DD | Root cause identified |
|
|
101
|
+
| 1.2 | YYYY-MM-DD | Fix deployed, verified |
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Execution Report — {{MODULE_NAME}}
|
|
2
|
+
|
|
3
|
+
**Report ID**: EXEC-{{MODULE}}-{{YYYYMMDD}}-{{NNN}}
|
|
4
|
+
**Sprint / Release**: Sprint {{NNN}}
|
|
5
|
+
**Execution type**: Automated / Manual / Mixed
|
|
6
|
+
**Executor**: (agent name or analyst name)
|
|
7
|
+
**Environment**: QA — `{{QA_BASE_URL}}`
|
|
8
|
+
**Date**: YYYY-MM-DD HH:MM UTC
|
|
9
|
+
**Playwright version**: {{version}} (if automated)
|
|
10
|
+
**ADO Test Plan**: #{ADO_PLAN_ID} (if ADO enabled)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Summary
|
|
15
|
+
|
|
16
|
+
| Metric | Value |
|
|
17
|
+
|--------|-------|
|
|
18
|
+
| Total TCs | {{N}} |
|
|
19
|
+
| Passed | {{N}} |
|
|
20
|
+
| Failed | {{N}} |
|
|
21
|
+
| Skipped | {{N}} |
|
|
22
|
+
| Pass rate | {{N}}% |
|
|
23
|
+
| Execution time | {{Nm Ns}} |
|
|
24
|
+
|
|
25
|
+
### Overall Result: ✅ PASS / ❌ FAIL / ⚠️ PARTIAL
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Results by Submodule
|
|
30
|
+
|
|
31
|
+
| Submodule | Total | Pass | Fail | Skip | Notes |
|
|
32
|
+
|-----------|-------|------|------|------|-------|
|
|
33
|
+
| {{submodule}} | | | | | |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Detailed Results
|
|
38
|
+
|
|
39
|
+
| TC-ID | Title | Priority | Result | Duration | Notes |
|
|
40
|
+
|-------|-------|----------|--------|----------|-------|
|
|
41
|
+
| TC-{{M}}-{{S}}-001 | {{title}} | P0 | ✅ Pass | {{Xs}} | |
|
|
42
|
+
| TC-{{M}}-{{S}}-002 | {{title}} | P0 | ❌ Fail | {{Xs}} | DEF-{{NNN}} opened |
|
|
43
|
+
| TC-{{M}}-{{S}}-003 | {{title}} | P1 | ⏭️ Skip | — | DEF-{{NNN}} blocks |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Failures Detail
|
|
48
|
+
|
|
49
|
+
### TC-{{M}}-{{S}}-{{NNN}} — {{Title}}
|
|
50
|
+
|
|
51
|
+
**Error**:
|
|
52
|
+
```
|
|
53
|
+
{{Error message or assertion failure output}}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Screenshot**: `{{path-to-screenshot-if-any}}`
|
|
57
|
+
|
|
58
|
+
**Action taken**: DEF-{{NNN}} opened / escalated to Dev.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Open Defects
|
|
63
|
+
|
|
64
|
+
| DEF-ID | Title | Severity | Linked TC | Status |
|
|
65
|
+
|--------|-------|----------|-----------|--------|
|
|
66
|
+
| DEF-{{NNN}} | {{title}} | High | TC-{{M}}-{{S}}-{{NNN}} | Open |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Skipped Tests
|
|
71
|
+
|
|
72
|
+
| TC-ID | Reason |
|
|
73
|
+
|-------|--------|
|
|
74
|
+
| TC-{{M}}-{{S}}-{{NNN}} | DEF-{{NNN}} — {{short description}} |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Environment Used
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
QA_BASE_URL={{QA_BASE_URL}}
|
|
82
|
+
Browser: Chromium {{version}}
|
|
83
|
+
Viewport: 1280x720
|
|
84
|
+
Workers: 1 (sequential, shared auth state)
|
|
85
|
+
Auth state: .auth/user-{{role}}.json (not committed)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> Credentials and tokens are NEVER logged in execution reports.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Recommendations
|
|
93
|
+
|
|
94
|
+
1. **DEF-{{NNN}}**: High priority — unblocks {{N}} skipped P0 tests.
|
|
95
|
+
2. **Flaky risk**: TC-{{M}}-{{S}}-{{NNN}} passed on retry — investigate timing issue.
|
|
96
|
+
3. **Coverage gap**: {{submodule}} `{{scenario}}` has no automated coverage — manual execution required.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Artifacts
|
|
101
|
+
|
|
102
|
+
| Artifact | Location |
|
|
103
|
+
|----------|----------|
|
|
104
|
+
| Playwright HTML report | `playwright-report/index.html` |
|
|
105
|
+
| Test results JSON | `test-results/` |
|
|
106
|
+
| Spec files | `qa/07-automation/e2e/{{module}}/` |
|
|
107
|
+
| ADO sync log | (if ADO enabled — see `integrations/ado-powershell/` output) |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Sign-off
|
|
112
|
+
|
|
113
|
+
| Role | Name | Date |
|
|
114
|
+
|------|------|------|
|
|
115
|
+
| QA Analyst | | |
|
|
116
|
+
| Tech Lead | | |
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Session Summary — {{SESSION_TITLE}}
|
|
2
|
+
|
|
3
|
+
**Date**: YYYY-MM-DD
|
|
4
|
+
**Session type**: Module Analysis / Spec Generation / Test Plan / Automation / ADO Sync / Maintenance
|
|
5
|
+
**Agent instruction used**: `agent-instructions/0{{N}}-{{name}}.md`
|
|
6
|
+
**Module / Submodule**: {{MODULE_NAME}} / {{SUBMODULE_NAME}} (or "N/A")
|
|
7
|
+
**Duration**: ~{{N}} minutes
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Objective
|
|
12
|
+
|
|
13
|
+
{{1-2 sentences describing what this session aimed to accomplish}}
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Completed
|
|
18
|
+
|
|
19
|
+
| Item | Output file | Status |
|
|
20
|
+
|------|-------------|--------|
|
|
21
|
+
| {{artifact type}} | `{{relative/path/to/file}}` | ✅ Done |
|
|
22
|
+
| {{artifact type}} | `{{relative/path/to/file}}` | ✅ Done |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Decisions Made
|
|
27
|
+
|
|
28
|
+
| Decision | Chosen option | Rationale |
|
|
29
|
+
|----------|--------------|-----------|
|
|
30
|
+
| {{e.g., "TC priority assignment for..."}} | P{{N}} | {{reason}} |
|
|
31
|
+
| {{e.g., "Skip automation for..."}} | Not automated | {{reason (external system, PDF, etc.)}} |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Open Items for Next Session
|
|
36
|
+
|
|
37
|
+
| Item | Priority | Notes |
|
|
38
|
+
|------|----------|-------|
|
|
39
|
+
| {{task}} | High / Medium / Low | {{context}} |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Defects Discovered
|
|
44
|
+
|
|
45
|
+
| DEF-ID | Title | Severity | File opened? |
|
|
46
|
+
|--------|-------|----------|--------------|
|
|
47
|
+
| DEF-{{NNN}} | {{title}} | {{severity}} | Yes — `qa/06-defects/open/DEF-{{NNN}}.md` |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Files Modified
|
|
52
|
+
|
|
53
|
+
| Path | Action |
|
|
54
|
+
|------|--------|
|
|
55
|
+
| `{{path}}` | Created / Updated |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Continuation Prompt
|
|
60
|
+
|
|
61
|
+
To resume this work in a new session, use:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Using keber/qa-framework agent instructions (agent-instructions/0{{N}}-{{name}}.md),
|
|
65
|
+
continue working on {{MODULE_NAME}} > {{SUBMODULE_NAME}}.
|
|
66
|
+
|
|
67
|
+
Last completed: {{last artifact}}
|
|
68
|
+
Next step: {{next specific task}}
|
|
69
|
+
|
|
70
|
+
Relevant files:
|
|
71
|
+
- {{file 1}}
|
|
72
|
+
- {{file 2}}
|
|
73
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# MODULE: {{MODULE_NAME}} — Submodule: {{SUBMODULE_NAME}}
|
|
2
|
+
|
|
3
|
+
> **Template version**: 1.0 | Replace all `{{...}}` with actual values before committing.
|
|
4
|
+
|
|
5
|
+
| Field | Value |
|
|
6
|
+
|-------|-------|
|
|
7
|
+
| Module code | {{MODULE_CODE}} |
|
|
8
|
+
| Submodule code | {{SUBMODULE_CODE}} |
|
|
9
|
+
| Primary URL | `{{QA_BASE_URL}}/{{SUBMODULE_PATH}}` |
|
|
10
|
+
| Secondary URLs | `{{URL_2}}`, `{{URL_3}}` |
|
|
11
|
+
| Status | Active |
|
|
12
|
+
| Deployed | YYYY-MM-DD |
|
|
13
|
+
| Last analyzed | YYYY-MM-DD |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Menu Location
|
|
18
|
+
|
|
19
|
+
| Level | Label | URL |
|
|
20
|
+
|-------|-------|-----|
|
|
21
|
+
| 1 | {{TOP_MENU}} | — |
|
|
22
|
+
| 2 | {{SUBMENU}} | `{{URL}}` |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## UI Elements
|
|
27
|
+
|
|
28
|
+
### Index / List View (`{{INDEX_URL}}`)
|
|
29
|
+
|
|
30
|
+
| Element | Type | Notes |
|
|
31
|
+
|---------|------|-------|
|
|
32
|
+
| {{field-name}} | text / select / checkbox / date / button | {{notes}} |
|
|
33
|
+
| Search input | text | Filters table by {{field}} |
|
|
34
|
+
| Pagination | paginator | N records per page |
|
|
35
|
+
| Export button | button | Generates {{format}} file |
|
|
36
|
+
|
|
37
|
+
### Create / Edit Form (`{{FORM_URL}}`)
|
|
38
|
+
|
|
39
|
+
| Field | Type | Required | Validation |
|
|
40
|
+
|-------|------|----------|------------|
|
|
41
|
+
| {{field-name}} | text | Yes/No | {{rule, e.g., max 100 chars}} |
|
|
42
|
+
| {{field-name}} | select | Yes/No | Options loaded from API |
|
|
43
|
+
| {{field-name}} | date | No | Future dates only |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## API Endpoints
|
|
48
|
+
|
|
49
|
+
| Method | Path | Purpose |
|
|
50
|
+
|--------|------|---------|
|
|
51
|
+
| GET | `/api/{{endpoint}}` | Load list with pagination |
|
|
52
|
+
| POST | `/api/{{endpoint}}` | Create new record |
|
|
53
|
+
| PUT | `/api/{{endpoint}}` | Update existing record |
|
|
54
|
+
| DELETE | `/api/{{endpoint}}` | Delete / deactivate record |
|
|
55
|
+
| GET | `/api/{{endpoint}}` | Load options for dropdown |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Key Identifiers
|
|
60
|
+
|
|
61
|
+
| Element | Selector / Identifier | Notes |
|
|
62
|
+
|---------|----------------------|-------|
|
|
63
|
+
| {{button}} | {{selector}} | {{usage}} |
|
|
64
|
+
| {{table}} | {{selector}} | {{usage}} |
|
|
65
|
+
| {{modal}} | {{selector}} | Opens on: {{trigger}} |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Related Submodules
|
|
70
|
+
|
|
71
|
+
| Submodule | Relationship | Notes |
|
|
72
|
+
|-----------|-------------|-------|
|
|
73
|
+
| {{submodule}} | Provides data to this module | Dropdown populated from {{API}} |
|
|
74
|
+
| {{submodule}} | Depends on data from this module | — |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Notes
|
|
79
|
+
|
|
80
|
+
- {{any technical notes discovered during analysis}}
|
|
81
|
+
- {{gotchas or non-obvious behaviors}}
|