quality-intelligence-engine 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/dist/bin/qi.js +27 -0
- package/dist/src/adapters/playwright-folder.adapter.js +68 -0
- package/dist/src/adapters/playwright-json.adapter.js +46 -0
- package/dist/src/adapters/playwright.adapter.js +36 -0
- package/dist/src/cli/qi-test.js +20 -0
- package/dist/src/cli/qi.js +59 -0
- package/dist/src/cli/ui/divider.js +10 -0
- package/dist/src/cli/ui/failureLogger.js +24 -0
- package/dist/src/configLoader.js +60 -0
- package/dist/src/console/issue-view.js +122 -0
- package/dist/src/failure-analysis/failure-analyzer.js +38 -0
- package/dist/src/final-run.js +130 -0
- package/dist/src/final-runner.js +27 -0
- package/dist/src/fixtures/networkCollector.js +18 -0
- package/dist/src/history/failure-history.store.js +25 -0
- package/dist/src/history/failure-history.types.js +4 -0
- package/dist/src/history/failure-trend.analyzer.js +31 -0
- package/dist/src/index.js +10 -0
- package/dist/src/integrations/ci/ci-annotator.js +26 -0
- package/dist/src/intelligence/confidence-calibration.engine.js +21 -0
- package/dist/src/intelligence/decision-intelligence/confidence.engine.js +16 -0
- package/dist/src/intelligence/decision-intelligence/decision.config.js +21 -0
- package/dist/src/intelligence/decision-intelligence/decision.engine.js +23 -0
- package/dist/src/intelligence/decision-intelligence/decision.types.js +2 -0
- package/dist/src/intelligence/failure-fingerprinting/failure.classifier.js +20 -0
- package/dist/src/intelligence/failure-fingerprinting/failure.store.js +39 -0
- package/dist/src/intelligence/failure-fingerprinting/failure.tracker.js +15 -0
- package/dist/src/intelligence/failure-fingerprinting/fingerprint.generator.js +28 -0
- package/dist/src/intelligence/failure-fingerprinting/fingerprint.types.js +2 -0
- package/dist/src/intelligence/flakiness-intelligence/flakiness.analyzer.js +21 -0
- package/dist/src/intelligence/flakiness-intelligence/flakiness.fingerprint.js +16 -0
- package/dist/src/intelligence/flakiness-intelligence/flakiness.store.js +24 -0
- package/dist/src/intelligence/flakiness-intelligence/flakiness.tracker.js +28 -0
- package/dist/src/intelligence/flakiness-intelligence/flakiness.types.js +2 -0
- package/dist/src/intelligence/intelligence.pipeline.js +17 -0
- package/dist/src/intelligence/llm-explainer.js +19 -0
- package/dist/src/intelligence/root-cause/rootcause.engine.js +25 -0
- package/dist/src/intelligence/trend-intelligence/trend.engine.js +25 -0
- package/dist/src/markdownWriter.js +64 -0
- package/dist/src/normalizer.js +17 -0
- package/dist/src/passAnalyzer.js +38 -0
- package/dist/src/pipeline/ai.summarizer.js +32 -0
- package/dist/src/pipeline/failure-analysis.pipeline.js +11 -0
- package/dist/src/pipeline/failure-grouping.pipeline.js +47 -0
- package/dist/src/reporter.js +46 -0
- package/dist/src/rules.js +32 -0
- package/dist/src/runManager.js +19 -0
- package/dist/src/runner.js +13 -0
- package/dist/src/runtime/networkCollector.js +34 -0
- package/dist/src/stackParser.js +17 -0
- package/dist/src/test-run.js +48 -0
- package/dist/src/types/analysis-result.js +2 -0
- package/dist/src/types/failure.types.js +3 -0
- package/dist/src/types/playwright-failure.js +2 -0
- package/dist/src/types.js +5 -0
- package/dist/src/utils/artifact.locator.js +35 -0
- package/dist/src/utils/confidence-constants.js +90 -0
- package/dist/src/utils/file-utils.js +121 -0
- package/dist/src/v2/llm/llm-advisor.js +17 -0
- package/dist/src/v2/pipeline/v2-intelligence.pipeline.js +17 -0
- package/dist/src/v2/self-healing/self-healer.js +44 -0
- package/dist/src/v2/trace-intelligence/trace-analyzer.js +33 -0
- package/dist/src/v2-test-run.js +59 -0
- package/package.json +23 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.analyzeTrend = analyzeTrend;
|
|
4
|
+
function analyzeTrend(history, windowSize = 10) {
|
|
5
|
+
const recent = history.slice(-windowSize);
|
|
6
|
+
const totalRuns = recent.length;
|
|
7
|
+
const passCount = recent.filter(r => r === 'PASS').length;
|
|
8
|
+
const failCount = recent.filter(r => r === 'FAIL').length;
|
|
9
|
+
const passRate = totalRuns ? passCount / totalRuns : 0;
|
|
10
|
+
const failRate = totalRuns ? failCount / totalRuns : 0;
|
|
11
|
+
const oscillations = recent.filter((v, i, arr) => i > 0 && v !== arr[i - 1]).length;
|
|
12
|
+
let flakiness = 'LOW';
|
|
13
|
+
if (oscillations >= 4)
|
|
14
|
+
flakiness = 'HIGH';
|
|
15
|
+
else if (oscillations >= 2)
|
|
16
|
+
flakiness = 'MEDIUM';
|
|
17
|
+
const stability = flakiness === 'HIGH' || failRate > 0.4 ? 'UNSTABLE' : 'STABLE';
|
|
18
|
+
return {
|
|
19
|
+
totalRuns,
|
|
20
|
+
passRate,
|
|
21
|
+
failRate,
|
|
22
|
+
flakiness,
|
|
23
|
+
stability
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.writeAnalysisMarkdown = writeAnalysisMarkdown;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function writeAnalysisMarkdown(baseDir, issueId, result, occurrences) {
|
|
10
|
+
const issueDir = path_1.default.join(baseDir, issueId);
|
|
11
|
+
fs_1.default.mkdirSync(issueDir, { recursive: true });
|
|
12
|
+
const mdPath = path_1.default.join(issueDir, 'analysis.md');
|
|
13
|
+
const content = `
|
|
14
|
+
# ❌ ${result.category}
|
|
15
|
+
|
|
16
|
+
**Occurrences** : ${occurrences}
|
|
17
|
+
**Confidence** : ${result.confidence}
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📍 Failure Location
|
|
22
|
+
- **File** : ${result.location.file}
|
|
23
|
+
- **Line** : ${result.location.line}
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🌐 Failed API Call
|
|
28
|
+
- **Method** : ${result.failedApi.method}
|
|
29
|
+
- **Endpoint** : ${result.failedApi.endpoint}
|
|
30
|
+
- **Status** : ${result.failedApi.status}
|
|
31
|
+
- **Response** : ${result.failedApi.response ?? '-'}
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 🧠 Root Cause
|
|
36
|
+
${result.rootCause}
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🔁 Retry Guidance
|
|
41
|
+
${result.retryGuidance}
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ▶️ Reproduction Steps
|
|
46
|
+
${result.reproductionSteps.map((s, i) => `${i + 1}. ${s}`).join('\n')}
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## ✅ Expected Result
|
|
51
|
+
${result.expected}
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## ❌ Actual Result
|
|
56
|
+
${result.actual}
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🛠 Suggested Actions
|
|
61
|
+
${result.suggestedActions.map(a => `- ${a}`).join('\n')}
|
|
62
|
+
`.trim();
|
|
63
|
+
fs_1.default.writeFileSync(mdPath, content, 'utf-8');
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* src/normalizer.ts */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.normalizeRawInput = normalizeRawInput;
|
|
5
|
+
/**
|
|
6
|
+
* Public normalizer API
|
|
7
|
+
*/
|
|
8
|
+
function normalizeRawInput(items) {
|
|
9
|
+
return items.map((item) => {
|
|
10
|
+
const safeItem = item;
|
|
11
|
+
return {
|
|
12
|
+
rootCause: safeItem.message,
|
|
13
|
+
actual: safeItem.message,
|
|
14
|
+
response: safeItem.api?.response
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.analyzePasses = analyzePasses;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function analyzePasses() {
|
|
10
|
+
const passPath = path_1.default.join(process.cwd(), 'input/raw-pass.json');
|
|
11
|
+
const items = JSON.parse(fs_1.default.readFileSync(passPath, 'utf-8'));
|
|
12
|
+
const risks = [];
|
|
13
|
+
items.forEach((item) => {
|
|
14
|
+
// Flaky pass
|
|
15
|
+
if (item.retries > 0) {
|
|
16
|
+
risks.push({
|
|
17
|
+
test: item.test,
|
|
18
|
+
riskType: 'FLAKY_PASS',
|
|
19
|
+
location: { file: item.test, line: -1 },
|
|
20
|
+
reason: 'Test passed after retry',
|
|
21
|
+
fix: 'Stabilize locator or add explicit waits'
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// API warnings during pass
|
|
25
|
+
item.apiEvents?.forEach((api) => {
|
|
26
|
+
if (api.status >= 400 && api.recovered) {
|
|
27
|
+
risks.push({
|
|
28
|
+
test: item.test,
|
|
29
|
+
riskType: 'API_WARNING',
|
|
30
|
+
location: { file: item.test, line: -1 },
|
|
31
|
+
reason: `${api.method} ${api.endpoint} failed with ${api.status} but recovered`,
|
|
32
|
+
fix: 'Investigate backend instability or add retry with backoff'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
return risks;
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.summarizeWithAI = summarizeWithAI;
|
|
4
|
+
async function summarizeWithAI(input) {
|
|
5
|
+
// 🔒 Safety first — AI is OPTIONAL
|
|
6
|
+
if (!process.env.AI_ENABLED) {
|
|
7
|
+
return deterministicFallback(input);
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
// 🔹 Placeholder for real LLM call
|
|
11
|
+
// 🔹 Intentionally simple & replaceable
|
|
12
|
+
return `
|
|
13
|
+
This failure occurred in the test "${input.testName}".
|
|
14
|
+
Based on the observed error and system heuristics, the root cause is classified as:
|
|
15
|
+
"${input.rootCause}"
|
|
16
|
+
|
|
17
|
+
The confidence score (${(input.confidence / 100).toFixed(2)}) indicates a stable and repeatable issue.
|
|
18
|
+
Recommended action is to follow the suggested remediation rather than retrying the test.
|
|
19
|
+
`.trim();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// 🔒 Never crash pipeline because of AI
|
|
23
|
+
return deterministicFallback(input);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function deterministicFallback(input) {
|
|
27
|
+
return `
|
|
28
|
+
Failure in "${input.testName}" was analyzed deterministically.
|
|
29
|
+
Root cause identified as: ${input.rootCause}.
|
|
30
|
+
Confidence level: ${(input.confidence / 100).toFixed(2)}.
|
|
31
|
+
`.trim();
|
|
32
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/pipeline/failure-analysis.pipeline.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.runFailureAnalysisFromPlaywright = runFailureAnalysisFromPlaywright;
|
|
5
|
+
const playwright_folder_adapter_1 = require("../adapters/playwright-folder.adapter");
|
|
6
|
+
/**
|
|
7
|
+
* Phase 1 – Playwright Failure Intake (Folder-based)
|
|
8
|
+
*/
|
|
9
|
+
async function runFailureAnalysisFromPlaywright(playwrightResultsDir) {
|
|
10
|
+
return (0, playwright_folder_adapter_1.parsePlaywrightFailureFolders)(playwrightResultsDir);
|
|
11
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/pipeline/failure-grouping.pipeline.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.groupFailures = groupFailures;
|
|
5
|
+
const failure_history_store_1 = require("../history/failure-history.store");
|
|
6
|
+
const failure_trend_analyzer_1 = require("../history/failure-trend.analyzer");
|
|
7
|
+
function groupFailures(results) {
|
|
8
|
+
const groupedCounts = {};
|
|
9
|
+
let flakyCount = 0;
|
|
10
|
+
for (const r of results) {
|
|
11
|
+
const key = r.classification ?? "UNKNOWN";
|
|
12
|
+
groupedCounts[key] = (groupedCounts[key] || 0) + 1;
|
|
13
|
+
if (key === "FLAKY") {
|
|
14
|
+
flakyCount++;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
let dominantCategory = "UNKNOWN";
|
|
18
|
+
let dominantCount = 0;
|
|
19
|
+
for (const [category, count] of Object.entries(groupedCounts)) {
|
|
20
|
+
if (count > dominantCount) {
|
|
21
|
+
dominantCategory = category;
|
|
22
|
+
dominantCount = count;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const total = results.length || 1;
|
|
26
|
+
let confidence = dominantCount / total;
|
|
27
|
+
// 🔻 FLAKY PENALTY (KEY LOGIC)
|
|
28
|
+
if (flakyCount > 0) {
|
|
29
|
+
const penalty = Math.min(0.3, flakyCount / total);
|
|
30
|
+
confidence = Math.max(0, confidence - penalty);
|
|
31
|
+
}
|
|
32
|
+
const summary = {
|
|
33
|
+
dominantCategory,
|
|
34
|
+
groupedCounts,
|
|
35
|
+
confidence,
|
|
36
|
+
flakyCount
|
|
37
|
+
};
|
|
38
|
+
(0, failure_history_store_1.saveFailureHistory)({
|
|
39
|
+
runId: Date.now().toString(),
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
dominantCategory,
|
|
42
|
+
groupedCounts,
|
|
43
|
+
confidence
|
|
44
|
+
});
|
|
45
|
+
summary.trend = (0, failure_trend_analyzer_1.analyzeFailureTrends)((0, failure_history_store_1.loadFailureHistory)());
|
|
46
|
+
return summary;
|
|
47
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.printSummaryAndWriteReports = printSummaryAndWriteReports;
|
|
4
|
+
exports.printPassRisks = printPassRisks;
|
|
5
|
+
const markdownWriter_1 = require("./markdownWriter");
|
|
6
|
+
/**
|
|
7
|
+
* FAILURES: Print summary + write markdown reports
|
|
8
|
+
*/
|
|
9
|
+
function printSummaryAndWriteReports(grouped, run, config) {
|
|
10
|
+
let printed = 0;
|
|
11
|
+
grouped.forEach((items, key) => {
|
|
12
|
+
const sample = items[0];
|
|
13
|
+
// Respect confidence threshold
|
|
14
|
+
if (sample.confidence <
|
|
15
|
+
config.engine.confidenceThresholds.fail) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (printed === 0) {
|
|
19
|
+
console.log(`❌ Failures Detected (${grouped.size} unique issues)\n`);
|
|
20
|
+
}
|
|
21
|
+
printed++;
|
|
22
|
+
console.log(`${printed}) ${sample.category} (${items.length} occurrences)`);
|
|
23
|
+
console.log(` Location : ${sample.location.file}:${sample.location.line}`);
|
|
24
|
+
console.log(` API : ${sample.failedApi.endpoint} → ${sample.failedApi.status}`);
|
|
25
|
+
console.log(` Cause : ${sample.rootCause}`);
|
|
26
|
+
console.log(` Details : output/${run.runDir.split('/').pop()}/${key}/analysis.md\n`);
|
|
27
|
+
(0, markdownWriter_1.writeAnalysisMarkdown)(run.runDir, key, sample, items.length);
|
|
28
|
+
});
|
|
29
|
+
if (printed === 0) {
|
|
30
|
+
console.log('✅ No failures exceeded confidence threshold\n');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* PASSES: Print non-blocking risk warnings
|
|
35
|
+
*/
|
|
36
|
+
function printPassRisks(risks, _run) {
|
|
37
|
+
if (risks.length === 0)
|
|
38
|
+
return;
|
|
39
|
+
console.log(`⚠️ Pass Risks Detected (${risks.length})\n`);
|
|
40
|
+
risks.forEach((risk, i) => {
|
|
41
|
+
console.log(`${i + 1}) ${risk.test} → ${risk.riskType}`);
|
|
42
|
+
console.log(` Location : ${risk.location.file}`);
|
|
43
|
+
console.log(` Reason : ${risk.reason}`);
|
|
44
|
+
console.log(` Fix : ${risk.fix}\n`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateDummyResult = generateDummyResult;
|
|
4
|
+
function generateDummyResult() {
|
|
5
|
+
return {
|
|
6
|
+
category: 'BACKEND_API_FAILURE',
|
|
7
|
+
confidence: 0.93,
|
|
8
|
+
location: {
|
|
9
|
+
file: 'AuthController.java',
|
|
10
|
+
line: 87
|
|
11
|
+
},
|
|
12
|
+
failedApi: {
|
|
13
|
+
method: 'GET',
|
|
14
|
+
endpoint: '/users/{id}',
|
|
15
|
+
status: 404,
|
|
16
|
+
response: 'User not found'
|
|
17
|
+
},
|
|
18
|
+
rootCause: 'The requested user ID does not exist in the database.',
|
|
19
|
+
retryGuidance: 'Automated CI retry is not advised (high confidence application failure).',
|
|
20
|
+
reproductionSteps: [
|
|
21
|
+
'Start backend service',
|
|
22
|
+
'Run: curl GET /users/{id}',
|
|
23
|
+
'Observe: 404 Not Found'
|
|
24
|
+
],
|
|
25
|
+
expected: 'User details are returned successfully.',
|
|
26
|
+
actual: 'API returns 404 and request fails in AuthController.java:87',
|
|
27
|
+
suggestedActions: [
|
|
28
|
+
'Validate user existence before API call',
|
|
29
|
+
'Add graceful handling for missing user records'
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRunContext = createRunContext;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function createRunContext() {
|
|
10
|
+
const now = new Date();
|
|
11
|
+
const runId = now
|
|
12
|
+
.toISOString()
|
|
13
|
+
.replace(/[:.]/g, '-')
|
|
14
|
+
.replace('T', '_')
|
|
15
|
+
.replace('Z', '');
|
|
16
|
+
const runDir = path_1.default.join(process.cwd(), 'output', `run-${runId}`);
|
|
17
|
+
fs_1.default.mkdirSync(runDir, { recursive: true });
|
|
18
|
+
return { runId, runDir };
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/runner.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.runQualityIntelligence = runQualityIntelligence;
|
|
5
|
+
const failure_analysis_pipeline_1 = require("./pipeline/failure-analysis.pipeline");
|
|
6
|
+
const failure_grouping_pipeline_1 = require("./pipeline/failure-grouping.pipeline");
|
|
7
|
+
const intelligence_pipeline_1 = require("./intelligence/intelligence.pipeline");
|
|
8
|
+
async function runQualityIntelligence(input) {
|
|
9
|
+
const analysisResults = await (0, failure_analysis_pipeline_1.runFailureAnalysisFromPlaywright)(input);
|
|
10
|
+
const summary = (0, failure_grouping_pipeline_1.groupFailures)(analysisResults);
|
|
11
|
+
const enriched = await (0, intelligence_pipeline_1.enrichWithIntelligence)(summary);
|
|
12
|
+
return enriched;
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.attachNetworkCollector = attachNetworkCollector;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function attachNetworkCollector(page, testId) {
|
|
10
|
+
const failures = [];
|
|
11
|
+
page.on('response', response => {
|
|
12
|
+
if (response.status() >= 400) {
|
|
13
|
+
failures.push({
|
|
14
|
+
method: response.request().method(),
|
|
15
|
+
url: new URL(response.url()).pathname,
|
|
16
|
+
status: response.status()
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
page.on('requestfailed', request => {
|
|
21
|
+
failures.push({
|
|
22
|
+
method: request.method(),
|
|
23
|
+
url: new URL(request.url()).pathname,
|
|
24
|
+
error: request.failure()?.errorText
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
process.on('exit', () => {
|
|
28
|
+
if (failures.length === 0)
|
|
29
|
+
return;
|
|
30
|
+
const dir = path_1.default.join('test-results', testId);
|
|
31
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
32
|
+
fs_1.default.writeFileSync(path_1.default.join(dir, 'network.json'), JSON.stringify(failures, null, 2));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseStackTrace = parseStackTrace;
|
|
4
|
+
function parseStackTrace(stack) {
|
|
5
|
+
if (!stack || stack.length === 0) {
|
|
6
|
+
return { file: 'Unknown', line: -1 };
|
|
7
|
+
}
|
|
8
|
+
// Supports formats like: Class.method(File.java:87)
|
|
9
|
+
const match = stack[0].match(/\((.*):(\d+)\)/);
|
|
10
|
+
if (!match) {
|
|
11
|
+
return { file: 'Unknown', line: -1 };
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
file: match[1],
|
|
15
|
+
line: Number(match[2])
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/test-run.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const runner_1 = require("./runner");
|
|
5
|
+
function line(char = "=", count = 60) {
|
|
6
|
+
console.log(char.repeat(count));
|
|
7
|
+
}
|
|
8
|
+
async function main() {
|
|
9
|
+
const playwrightResultsDir = "playwright-results";
|
|
10
|
+
const result = await (0, runner_1.runQualityIntelligence)(playwrightResultsDir);
|
|
11
|
+
line();
|
|
12
|
+
console.log("QUALITY INTELLIGENCE – FINAL OUTPUT");
|
|
13
|
+
line();
|
|
14
|
+
console.log(`Primary Failure : ${result.dominantCategory}`);
|
|
15
|
+
console.log(`Confidence Score : ${result.confidence}`);
|
|
16
|
+
console.log(`Flaky Failures : ${result.flakyCount}`);
|
|
17
|
+
console.log(`Trend Signal : ${result.trend?.signal ?? "N/A"}`);
|
|
18
|
+
line("-");
|
|
19
|
+
console.log("Failure Breakdown:");
|
|
20
|
+
for (const [k, v] of Object.entries(result.groupedCounts)) {
|
|
21
|
+
console.log(` - ${k}: ${v}`);
|
|
22
|
+
}
|
|
23
|
+
line("-");
|
|
24
|
+
console.log("Confidence Diagnosis:");
|
|
25
|
+
for (const lineText of result.intelligence.confidence.explanation) {
|
|
26
|
+
console.log(` • ${lineText}`);
|
|
27
|
+
}
|
|
28
|
+
line("-");
|
|
29
|
+
console.log("AI Explanation:");
|
|
30
|
+
console.log(` Summary: ${result.intelligence.explanation.summary}`);
|
|
31
|
+
if (result.intelligence.explanation.reasoning?.length) {
|
|
32
|
+
console.log(" Reasoning:");
|
|
33
|
+
for (const r of result.intelligence.explanation.reasoning) {
|
|
34
|
+
console.log(` - ${r}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (result.intelligence.explanation.recommendedAction?.length) {
|
|
38
|
+
console.log(" Recommended Actions:");
|
|
39
|
+
for (const a of result.intelligence.explanation.recommendedAction) {
|
|
40
|
+
console.log(` - ${a}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
line();
|
|
44
|
+
}
|
|
45
|
+
main().catch(err => {
|
|
46
|
+
console.error("QUALITY INTELLIGENCE FAILED");
|
|
47
|
+
console.error(err);
|
|
48
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.locatePlaywrightArtifacts = locatePlaywrightArtifacts;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function locatePlaywrightArtifacts() {
|
|
10
|
+
const resultsDir = path_1.default.resolve('test-results');
|
|
11
|
+
const screenshots = [];
|
|
12
|
+
let trace;
|
|
13
|
+
if (!fs_1.default.existsSync(resultsDir)) {
|
|
14
|
+
return { screenshots, trace };
|
|
15
|
+
}
|
|
16
|
+
const runDirs = fs_1.default.readdirSync(resultsDir);
|
|
17
|
+
for (const dir of runDirs) {
|
|
18
|
+
const fullDir = path_1.default.join(resultsDir, dir);
|
|
19
|
+
if (!fs_1.default.statSync(fullDir).isDirectory())
|
|
20
|
+
continue;
|
|
21
|
+
const files = fs_1.default.readdirSync(fullDir);
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
const fullPath = path_1.default.join(fullDir, file);
|
|
24
|
+
// 🎥 Trace ZIP (take the latest retry if exists)
|
|
25
|
+
if (file === 'trace.zip') {
|
|
26
|
+
trace = fullPath;
|
|
27
|
+
}
|
|
28
|
+
// 📸 Screenshots
|
|
29
|
+
if (file.endsWith('.png')) {
|
|
30
|
+
screenshots.push(fullPath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { trace, screenshots };
|
|
35
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Confidence Calculation Constants
|
|
4
|
+
*
|
|
5
|
+
* These constants define the base confidence levels and adjustments
|
|
6
|
+
* used throughout the quality intelligence engine.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.TAXONOMY_BASE_CONFIDENCE = exports.CONFIDENCE_THRESHOLDS = exports.CONFIDENCE_BOUNDS = exports.CONFIDENCE_ADJUSTMENTS = exports.BASE_CONFIDENCE = void 0;
|
|
10
|
+
exports.clampConfidence = clampConfidence;
|
|
11
|
+
exports.formatConfidence = formatConfidence;
|
|
12
|
+
/**
|
|
13
|
+
* Base confidence levels for different error types
|
|
14
|
+
*/
|
|
15
|
+
exports.BASE_CONFIDENCE = {
|
|
16
|
+
/** Strong backend failure signal (5xx errors) */
|
|
17
|
+
BACKEND_SERVER_ERROR: 0.95,
|
|
18
|
+
/** Backend API failure (any API error) */
|
|
19
|
+
BACKEND_API_ERROR: 0.9,
|
|
20
|
+
/** Test or automation failure */
|
|
21
|
+
TEST_ERROR: 0.75,
|
|
22
|
+
/** Unknown or weak signal */
|
|
23
|
+
UNKNOWN: 0.6,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Confidence adjustments based on test context and signals
|
|
27
|
+
*/
|
|
28
|
+
exports.CONFIDENCE_ADJUSTMENTS = {
|
|
29
|
+
/** UI successfully rendered and reached assertion */
|
|
30
|
+
UI_RENDERED: 0.05,
|
|
31
|
+
/** Test involves authentication or login flow */
|
|
32
|
+
AUTH_FLOW_DETECTED: 0.05,
|
|
33
|
+
/** Explicit authentication failure detected */
|
|
34
|
+
EXPLICIT_AUTH_FAILURE: 0.1,
|
|
35
|
+
/** Test involves inventory or data operations */
|
|
36
|
+
DATA_OPERATION_DETECTED: 0.05,
|
|
37
|
+
/** Numeric mismatch detected in assertions */
|
|
38
|
+
NUMERIC_MISMATCH: 0.05,
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Maximum and minimum confidence bounds
|
|
42
|
+
*/
|
|
43
|
+
exports.CONFIDENCE_BOUNDS = {
|
|
44
|
+
/** Maximum confidence score (never 100% certain) */
|
|
45
|
+
MAX: 0.95,
|
|
46
|
+
/** Minimum confidence score for reporting */
|
|
47
|
+
MIN: 0.5,
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Confidence thresholds for decision making
|
|
51
|
+
*/
|
|
52
|
+
exports.CONFIDENCE_THRESHOLDS = {
|
|
53
|
+
/** Threshold for blocking CI/CD (high confidence failure) */
|
|
54
|
+
FAIL: 0.85,
|
|
55
|
+
/** Threshold for reporting pass risks */
|
|
56
|
+
PASS_RISK: 0.6,
|
|
57
|
+
/** Threshold for investigating (medium confidence) */
|
|
58
|
+
INVESTIGATE: 0.7,
|
|
59
|
+
/** Threshold for shipping (high confidence in safety) */
|
|
60
|
+
SHIP: 0.85,
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Taxonomy rule base confidence levels
|
|
64
|
+
*/
|
|
65
|
+
exports.TAXONOMY_BASE_CONFIDENCE = {
|
|
66
|
+
/** Numeric data mismatch */
|
|
67
|
+
NUMERIC_MISMATCH: 0.6,
|
|
68
|
+
/** Authentication failure */
|
|
69
|
+
AUTH_FAILURE: 0.7,
|
|
70
|
+
/** UI visibility issue */
|
|
71
|
+
VISIBILITY: 0.7,
|
|
72
|
+
/** Network timeout */
|
|
73
|
+
TIMEOUT: 0.65,
|
|
74
|
+
/** Element not found */
|
|
75
|
+
ELEMENT_NOT_FOUND: 0.7,
|
|
76
|
+
/** Default fallback */
|
|
77
|
+
DEFAULT: 0.7,
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Helper function to clamp confidence within bounds
|
|
81
|
+
*/
|
|
82
|
+
function clampConfidence(value) {
|
|
83
|
+
return Math.max(exports.CONFIDENCE_BOUNDS.MIN, Math.min(exports.CONFIDENCE_BOUNDS.MAX, value));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Helper function to format confidence as percentage string
|
|
87
|
+
*/
|
|
88
|
+
function formatConfidence(value) {
|
|
89
|
+
return `${(value * 100).toFixed(1)}%`;
|
|
90
|
+
}
|