quality-intelligence-engine 2.2.17 → 2.2.22

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 (65) hide show
  1. package/dist/bin/qi.js +8 -3
  2. package/dist/src/adapters/playwright-folder.adapter.js +68 -0
  3. package/dist/src/adapters/playwright-json.adapter.js +46 -0
  4. package/dist/src/adapters/playwright.adapter.js +36 -0
  5. package/dist/src/cli/qi-test.js +20 -0
  6. package/dist/src/cli/qi.js +59 -0
  7. package/dist/src/cli/ui/divider.js +10 -0
  8. package/dist/src/cli/ui/failureLogger.js +24 -0
  9. package/dist/src/configLoader.js +60 -0
  10. package/dist/src/console/issue-view.js +81 -0
  11. package/dist/src/failure-analysis/failure-analyzer.js +38 -0
  12. package/dist/src/final-run.js +131 -0
  13. package/dist/src/final-runner.js +27 -0
  14. package/dist/src/fixtures/networkCollector.js +18 -0
  15. package/dist/src/history/failure-history.store.js +25 -0
  16. package/dist/src/history/failure-history.types.js +4 -0
  17. package/dist/src/history/failure-trend.analyzer.js +31 -0
  18. package/dist/src/index.js +10 -0
  19. package/dist/src/integrations/ci/ci-annotator.js +26 -0
  20. package/dist/src/intelligence/confidence-calibration.engine.js +21 -0
  21. package/dist/src/intelligence/decision-intelligence/confidence.engine.js +16 -0
  22. package/dist/src/intelligence/decision-intelligence/decision.config.js +21 -0
  23. package/dist/src/intelligence/decision-intelligence/decision.engine.js +23 -0
  24. package/dist/src/intelligence/decision-intelligence/decision.types.js +2 -0
  25. package/dist/src/intelligence/failure-fingerprinting/failure.classifier.js +32 -0
  26. package/dist/src/intelligence/failure-fingerprinting/failure.store.js +17 -0
  27. package/dist/src/intelligence/failure-fingerprinting/failure.tracker.js +19 -0
  28. package/dist/src/intelligence/failure-fingerprinting/fingerprint.generator.js +28 -0
  29. package/dist/src/intelligence/failure-fingerprinting/fingerprint.types.js +2 -0
  30. package/dist/src/intelligence/flakiness-intelligence/flakiness.analyzer.js +21 -0
  31. package/dist/src/intelligence/flakiness-intelligence/flakiness.fingerprint.js +16 -0
  32. package/dist/src/intelligence/flakiness-intelligence/flakiness.store.js +24 -0
  33. package/dist/src/intelligence/flakiness-intelligence/flakiness.tracker.js +28 -0
  34. package/dist/src/intelligence/flakiness-intelligence/flakiness.types.js +2 -0
  35. package/dist/src/intelligence/intelligence.pipeline.js +17 -0
  36. package/dist/src/intelligence/llm-explainer.js +19 -0
  37. package/dist/src/intelligence/root-cause/rootcause.engine.js +25 -0
  38. package/dist/src/intelligence/trend-intelligence/trend.engine.js +25 -0
  39. package/dist/src/markdownWriter.js +64 -0
  40. package/dist/src/normalizer.js +17 -0
  41. package/dist/src/passAnalyzer.js +38 -0
  42. package/dist/src/pipeline/ai.summarizer.js +32 -0
  43. package/dist/src/pipeline/failure-analysis.pipeline.js +11 -0
  44. package/dist/src/pipeline/failure-grouping.pipeline.js +59 -0
  45. package/dist/src/playwright/qi.reporter.js +17 -0
  46. package/dist/src/reporter.js +46 -0
  47. package/dist/src/rules.js +32 -0
  48. package/dist/src/runManager.js +19 -0
  49. package/dist/src/runner.js +13 -0
  50. package/dist/src/runtime/networkCollector.js +34 -0
  51. package/dist/src/stackParser.js +17 -0
  52. package/dist/src/test-run.js +48 -0
  53. package/dist/src/types/analysis-result.js +2 -0
  54. package/dist/src/types/failure.types.js +3 -0
  55. package/dist/src/types/playwright-failure.js +2 -0
  56. package/dist/src/types.js +5 -0
  57. package/dist/src/utils/artifact.locator.js +35 -0
  58. package/dist/src/utils/confidence-constants.js +90 -0
  59. package/dist/src/utils/file-utils.js +118 -0
  60. package/dist/src/v2/llm/llm-advisor.js +17 -0
  61. package/dist/src/v2/pipeline/v2-intelligence.pipeline.js +17 -0
  62. package/dist/src/v2/self-healing/self-healer.js +44 -0
  63. package/dist/src/v2/trace-intelligence/trace-analyzer.js +33 -0
  64. package/dist/src/v2-test-run.js +59 -0
  65. package/package.json +1 -1
package/dist/bin/qi.js CHANGED
@@ -13,10 +13,15 @@ async function main() {
13
13
  const args = process.argv.slice(2);
14
14
  const playwrightResultsDir = args.find(a => !a.startsWith("--")) ?? "playwright-results";
15
15
  const showIssues = args.includes("--issue") || args.includes("--issues");
16
- // Resolve project root (works after npm install)
16
+ /**
17
+ * __dirname → dist/bin
18
+ * projectRoot → dist
19
+ */
17
20
  const projectRoot = path_1.default.resolve(__dirname, "..");
18
- // IMPORTANT: call compiled JS, never TS
19
- // dist/final-run.js EXISTS in published package
21
+ /**
22
+ * final-run.ts → dist/final-run.js
23
+ * (this file IS published)
24
+ */
20
25
  const finalRunPath = path_1.default.join(projectRoot, "final-run.js");
21
26
  // eslint-disable-next-line @typescript-eslint/no-var-requires
22
27
  const { runFinal } = require(finalRunPath);
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ // src/adapters/playwright-folder.adapter.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.parsePlaywrightFailureFolders = parsePlaywrightFailureFolders;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /**
11
+ * Improved Playwright failure folder parser
12
+ * Focus: reduce UNKNOWN classifications
13
+ */
14
+ function parsePlaywrightFailureFolders(resultsDir) {
15
+ const fullDir = path_1.default.resolve(resultsDir);
16
+ if (!fs_1.default.existsSync(fullDir)) {
17
+ throw new Error(`Playwright results directory not found: ${fullDir}`);
18
+ }
19
+ const entries = fs_1.default.readdirSync(fullDir, { withFileTypes: true });
20
+ const failures = [];
21
+ for (const entry of entries) {
22
+ if (!entry.isDirectory())
23
+ continue;
24
+ const name = entry.name;
25
+ if (!name.includes("FAIL"))
26
+ continue;
27
+ const lower = name.toLowerCase();
28
+ let classification = "UNKNOWN";
29
+ // 🔢 Numeric / data mismatches
30
+ if (lower.includes("numeric-mismatch") ||
31
+ lower.includes("count") ||
32
+ lower.includes("total") ||
33
+ lower.includes("sum") ||
34
+ lower.includes("price")) {
35
+ classification = "NUMERIC_MISMATCH";
36
+ }
37
+ // 🔐 Auth / permission issues
38
+ else if (lower.includes("unauthorized") ||
39
+ lower.includes("forbidden") ||
40
+ lower.includes("permission")) {
41
+ classification = "AUTH_BUG";
42
+ }
43
+ // ⏱ Timeouts / waits
44
+ else if (lower.includes("timeout") ||
45
+ lower.includes("timed-out") ||
46
+ lower.includes("wait")) {
47
+ classification = "TIMEOUT";
48
+ }
49
+ // 🧭 UI / locator issues
50
+ else if (lower.includes("locator") ||
51
+ lower.includes("not-visible") ||
52
+ lower.includes("hidden") ||
53
+ lower.includes("detached")) {
54
+ classification = "UI_STATE";
55
+ }
56
+ // 🔁 Retry / flaky signal
57
+ else if (lower.includes("retry")) {
58
+ classification = "FLAKY";
59
+ }
60
+ failures.push({
61
+ testName: name,
62
+ classification,
63
+ failureType: classification,
64
+ message: `Derived from Playwright folder name: ${name}`
65
+ });
66
+ }
67
+ return failures;
68
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ // src/adapters/playwright-json.adapter.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.parsePlaywrightJsonReport = parsePlaywrightJsonReport;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /**
11
+ * Converts Playwright JSON report → FailureAnalysisResult[]
12
+ */
13
+ function parsePlaywrightJsonReport(reportPath) {
14
+ const fullPath = path_1.default.resolve(reportPath);
15
+ const raw = fs_1.default.readFileSync(fullPath, "utf-8");
16
+ const report = JSON.parse(raw);
17
+ const failures = [];
18
+ for (const suite of report.suites ?? []) {
19
+ for (const spec of suite.specs ?? []) {
20
+ for (const test of spec.tests ?? []) {
21
+ for (const result of test.results ?? []) {
22
+ if (result.status === "failed") {
23
+ const error = result.error?.message ?? "";
24
+ let classification = "UNKNOWN";
25
+ if (error.includes("toHaveCount")) {
26
+ classification = "NUMERIC_MISMATCH";
27
+ }
28
+ else if (error.includes("timeout")) {
29
+ classification = "TIMEOUT";
30
+ }
31
+ else if (error.includes("locator")) {
32
+ classification = "LOCATOR_CHANGED";
33
+ }
34
+ failures.push({
35
+ testName: test.title,
36
+ classification,
37
+ failureType: classification,
38
+ message: error
39
+ });
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ return failures;
46
+ }
@@ -0,0 +1,36 @@
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.readPlaywrightFailures = readPlaywrightFailures;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function readPlaywrightFailures(reportDir) {
10
+ const reportFile = path_1.default.join(reportDir, 'report.json');
11
+ if (!fs_1.default.existsSync(reportFile)) {
12
+ throw new Error(`Playwright JSON report not found.\nExpected at: ${reportFile}`);
13
+ }
14
+ const raw = JSON.parse(fs_1.default.readFileSync(reportFile, 'utf-8'));
15
+ const failures = [];
16
+ for (const suite of raw.suites ?? []) {
17
+ for (const spec of suite.specs ?? []) {
18
+ for (const test of spec.tests ?? []) {
19
+ const failedResults = test.results?.filter((r) => r.status === 'failed');
20
+ if (!failedResults || failedResults.length === 0)
21
+ continue;
22
+ const firstFailure = failedResults[0];
23
+ const error = firstFailure.error;
24
+ failures.push({
25
+ testName: spec.title,
26
+ errorMessage: error?.message ?? 'Unknown error',
27
+ stack: error?.stack,
28
+ filePath: error?.location?.file ?? spec.file,
29
+ lineNumber: error?.location?.line ?? spec.line ?? 0,
30
+ retryCount: failedResults.length - 1
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return failures;
36
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runQiTest = runQiTest;
4
+ const child_process_1 = require("child_process");
5
+ function runQiTest(args) {
6
+ const playwrightArgs = [
7
+ 'playwright',
8
+ 'test',
9
+ '--config',
10
+ 'playwright.config.ts',
11
+ ...args
12
+ ];
13
+ const child = (0, child_process_1.spawn)('npx', playwrightArgs, {
14
+ stdio: 'inherit',
15
+ shell: true
16
+ });
17
+ child.on('exit', code => {
18
+ process.exit(code ?? 0);
19
+ });
20
+ }
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // src/cli/qi.ts
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.runQiCli = runQiCli;
6
+ const runner_1 = require("../runner");
7
+ /**
8
+ * Core CLI runner (reusable)
9
+ */
10
+ async function runQiCli(input) {
11
+ const results = await (0, runner_1.runQualityIntelligence)(input);
12
+ if (!Array.isArray(results) || results.length === 0) {
13
+ console.log("No failures detected.");
14
+ return;
15
+ }
16
+ for (const f of results) {
17
+ const testName = f.testName ?? "UNKNOWN_TEST";
18
+ const isExpected = testName.includes("EXPECTED");
19
+ console.log("=================================");
20
+ console.log(`Test Name : ${testName}${isExpected ? " (EXPECTED)" : ""}`);
21
+ console.log(`Failure Type : ${f.failureType ?? f.classification}`);
22
+ console.log(`Confidence : ${f.confidence ?? "N/A"}\n`);
23
+ if (f.rootCause?.length) {
24
+ console.log("Root Cause:");
25
+ for (const line of f.rootCause) {
26
+ console.log(` - ${line}`);
27
+ }
28
+ console.log();
29
+ }
30
+ if (f.evidence?.length) {
31
+ console.log("Evidence:");
32
+ for (const line of f.evidence) {
33
+ console.log(` - ${line}`);
34
+ }
35
+ console.log();
36
+ }
37
+ if (f.diagnosis?.length) {
38
+ console.log("Diagnosis:");
39
+ for (const line of f.diagnosis) {
40
+ console.log(` - ${line}`);
41
+ }
42
+ console.log();
43
+ }
44
+ }
45
+ }
46
+ /**
47
+ * CLI ENTRY POINT
48
+ * Allows: npx qi <path>
49
+ */
50
+ async function main() {
51
+ const input = process.argv[2] ?? "playwright-results";
52
+ await runQiCli(input);
53
+ }
54
+ if (process.argv[1]?.includes("qi")) {
55
+ main().catch(err => {
56
+ console.error("QI CLI failed:", err);
57
+ process.exit(1);
58
+ });
59
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.divider = divider;
4
+ function divider(title, width = 60) {
5
+ const line = '━'.repeat(width);
6
+ if (!title) {
7
+ return `\n${line}\n`;
8
+ }
9
+ return `\n${line}\n${title}\n${line}\n`;
10
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logFailure = logFailure;
4
+ function logFailure(input) {
5
+ const confidencePercent = Math.round(input.confidence * 100);
6
+ console.log(`
7
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
8
+ ❌ Automation Test Failure
9
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10
+
11
+ Test Name : ${input.testName}
12
+ Failure Type : ${input.failureType}
13
+ Severity : ${input.severity}
14
+ Priority : ${input.priority}
15
+ Confidence : ${confidencePercent}%
16
+
17
+ Failure Location:
18
+ - Test File : ${input.file}
19
+ - Line Number : ${input.line}
20
+
21
+ Root Cause:
22
+ - ${input.rootCause}
23
+ `);
24
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadConfig = loadConfig;
4
+ const file_utils_1 = require("./utils/file-utils");
5
+ /**
6
+ * Validate configuration object structure
7
+ */
8
+ function validateConfig(config) {
9
+ if (typeof config !== 'object' || config === null) {
10
+ return false;
11
+ }
12
+ const cfg = config;
13
+ // Validate engine section
14
+ if (typeof cfg.engine !== 'object' ||
15
+ cfg.engine === null) {
16
+ return false;
17
+ }
18
+ const engine = cfg.engine;
19
+ if (typeof engine.mode !== 'string' ||
20
+ typeof engine.confidenceThresholds !== 'object') {
21
+ return false;
22
+ }
23
+ return true;
24
+ }
25
+ /**
26
+ * Load and validate configuration
27
+ */
28
+ function loadConfig() {
29
+ try {
30
+ const configPath = (0, file_utils_1.resolvePath)('config', 'agent.config.json');
31
+ const config = (0, file_utils_1.readJsonFile)(configPath);
32
+ if (!validateConfig(config)) {
33
+ throw new Error('Invalid configuration structure');
34
+ }
35
+ return config;
36
+ }
37
+ catch (error) {
38
+ console.error('❌ Failed to load configuration:', error);
39
+ console.error('\n💡 Using default configuration');
40
+ // Return safe defaults
41
+ return {
42
+ engine: {
43
+ mode: 'standard',
44
+ confidenceThresholds: {
45
+ fail: 0.85,
46
+ passRisk: 0.6
47
+ }
48
+ },
49
+ output: {
50
+ writeMarkdown: true,
51
+ maxHistoryRuns: 10
52
+ },
53
+ passAnalysis: {
54
+ enable: true,
55
+ reportFlakyPass: true,
56
+ reportApiWarnings: true
57
+ }
58
+ };
59
+ }
60
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ // src/console/issue-view.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.extractIssues = extractIssues;
5
+ exports.filterIssues = filterIssues;
6
+ exports.printIssues = printIssues;
7
+ /* ===================================================== */
8
+ /* 🔹 EXISTING LOGIC (RESTORED – NO BEHAVIOR CHANGE) */
9
+ /* ===================================================== */
10
+ function extractIssues(groupedCounts, confidence) {
11
+ return Object.entries(groupedCounts).map(([type, count]) => ({
12
+ type,
13
+ count,
14
+ confidence,
15
+ autoHealAllowed: type === "FLAKY",
16
+ owner: {
17
+ team: type === "FLAKY"
18
+ ? "QA"
19
+ : type === "NUMERIC_MISMATCH"
20
+ ? "Backend"
21
+ : "Frontend"
22
+ },
23
+ summary: type === "FLAKY"
24
+ ? "Test behavior is unstable across executions"
25
+ : type === "NUMERIC_MISMATCH"
26
+ ? "Numeric values returned by backend do not match expected results"
27
+ : "Test failures detected but root cause is unclear",
28
+ reasoning: type === "FLAKY"
29
+ ? ["Failures disappear on retry", "Timing or synchronization issues detected"]
30
+ : type === "NUMERIC_MISMATCH"
31
+ ? ["API response data differs from expected calculation"]
32
+ : ["Failure artifacts exist", "Signals insufficient for confident classification"],
33
+ recommendations: type === "FLAKY"
34
+ ? ["Improve waits or synchronization", "Stabilize test setup and assertions"]
35
+ : type === "NUMERIC_MISMATCH"
36
+ ? ["Verify backend calculation logic", "Validate API response against expected schema"]
37
+ : ["Review screenshot and trace manually"]
38
+ }));
39
+ }
40
+ function filterIssues(issues, filter) {
41
+ if (!filter.enabled)
42
+ return [];
43
+ let result = issues;
44
+ if (filter.keyword) {
45
+ result = result.filter(i => i.type.toLowerCase().includes(filter.keyword.toLowerCase()));
46
+ }
47
+ if (filter.topN) {
48
+ result = result.slice(0, filter.topN);
49
+ }
50
+ return result;
51
+ }
52
+ /* ===================================================== */
53
+ /* 🔹 UPDATED PRINTER (NEW DESIGN) */
54
+ /* ===================================================== */
55
+ function printIssues(issues, failureFolder) {
56
+ if (!issues.length) {
57
+ console.log("No matching issues found.");
58
+ return;
59
+ }
60
+ issues.forEach((issue, index) => {
61
+ console.log(`\nISSUE #${index + 1}`);
62
+ console.log(`Type : ${issue.type}`);
63
+ console.log(`Occurrences : ${issue.count}`);
64
+ console.log(`Confidence : ${issue.confidence}`);
65
+ console.log(`Domain : ${issue.owner?.team ?? "UNKNOWN"}`);
66
+ console.log("\nWHAT IS THE ISSUE:");
67
+ console.log(` ${issue.summary}`);
68
+ console.log("\nWHY IT IS HAPPENING:");
69
+ issue.reasoning.forEach((r) => console.log(` • ${r}`));
70
+ console.log("\nWHAT TO DO NEXT:");
71
+ issue.recommendations.forEach((r) => console.log(` • ${r}`));
72
+ if (issue.autoHealAllowed) {
73
+ console.log("\nSelf-Healing:");
74
+ console.log(" Allowed : YES (retry-based stabilization is safe)");
75
+ }
76
+ console.log("\nEvidence:");
77
+ console.log(` Screenshot : ${failureFolder}/test-failed-1.png`);
78
+ console.log(` Trace : npx playwright show-trace ${failureFolder}/trace.zip`);
79
+ console.log("-".repeat(70));
80
+ });
81
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ // src/failure-analysis/failure-analyzer.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.FailureAnalyzer = void 0;
5
+ /**
6
+ * FailureAnalyzer
7
+ * ----------------
8
+ * Phase 1 core analyzer.
9
+ * This class is intentionally simple and stable.
10
+ * Do NOT add history, trends, or intelligence here.
11
+ */
12
+ class FailureAnalyzer {
13
+ analyze(input) {
14
+ if (!input || !Array.isArray(input)) {
15
+ return [];
16
+ }
17
+ return input.map((item) => {
18
+ // Minimal safe classification logic
19
+ if (item?.type === "NUMERIC_MISMATCH") {
20
+ return {
21
+ classification: "NUMERIC_MISMATCH",
22
+ message: item.message
23
+ };
24
+ }
25
+ if (item?.type === "API_BUG") {
26
+ return {
27
+ classification: "API_BUG",
28
+ message: item.message
29
+ };
30
+ }
31
+ return {
32
+ classification: "UNKNOWN",
33
+ message: item?.message
34
+ };
35
+ });
36
+ }
37
+ }
38
+ exports.FailureAnalyzer = FailureAnalyzer;
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ // src/final-run.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runFinal = runFinal;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const runner_1 = require("./runner");
11
+ const v2_intelligence_pipeline_1 = require("./v2/pipeline/v2-intelligence.pipeline");
12
+ /* ===================================================== */
13
+ /* 🔹 STRONG METADATA DERIVATION (NO GUESSING) */
14
+ /* ===================================================== */
15
+ function deriveTestMetadata(failureFolder) {
16
+ // 1️⃣ Try spec file (best)
17
+ try {
18
+ const files = fs_1.default.readdirSync(failureFolder, { recursive: true });
19
+ const spec = files.find(f => f.endsWith(".spec.ts") || f.endsWith(".spec.js"));
20
+ if (spec) {
21
+ return {
22
+ testName: path_1.default.basename(spec).replace(/\.(spec\.ts|spec\.js)$/, ""),
23
+ testLocation: `${spec}:?`
24
+ };
25
+ }
26
+ }
27
+ catch { }
28
+ // 2️⃣ Fallback: derive from folder name (deterministic)
29
+ const folderName = path_1.default.basename(failureFolder);
30
+ const cleaned = folderName
31
+ .replace(/--chromium|--firefox|--webkit/g, "")
32
+ .replace(/-FAIL.*/i, "")
33
+ .replace(/[-_]/g, " ")
34
+ .trim();
35
+ return {
36
+ testName: cleaned || "Unknown test",
37
+ testLocation: "Derived from Playwright results"
38
+ };
39
+ }
40
+ /* ===================================================== */
41
+ /* 🔹 FAILURE FALLBACK CLASSIFIER (SAFE) */
42
+ /* ===================================================== */
43
+ function normalizeFailure(dominant, failureFolder) {
44
+ if (dominant !== "UNCLASSIFIED_FAILURE") {
45
+ return {
46
+ primary: dominant,
47
+ domain: dominant === "NUMERIC_MISMATCH"
48
+ ? "API"
49
+ : dominant === "FLAKY"
50
+ ? "TEST"
51
+ : dominant === "ASSERTION_FAILURE"
52
+ ? "UI"
53
+ : "UNKNOWN"
54
+ };
55
+ }
56
+ const keywords = ["invalid", "required", "rejected", "format", "error", "fail"];
57
+ const name = failureFolder.toLowerCase();
58
+ if (keywords.some(k => name.includes(k))) {
59
+ return {
60
+ primary: "UI_VALIDATION_FAILURE",
61
+ domain: "UI"
62
+ };
63
+ }
64
+ return {
65
+ primary: "UNKNOWN",
66
+ domain: "UNKNOWN"
67
+ };
68
+ }
69
+ function line(char = "=", count = 70) {
70
+ console.log(char.repeat(count));
71
+ }
72
+ /* ===================================================== */
73
+ /* ✅ MAIN EXECUTION – NO LOGIC REGRESSION */
74
+ /* ===================================================== */
75
+ async function runFinal() {
76
+ const playwrightResultsDir = "playwright-results";
77
+ const folders = fs_1.default.readdirSync(playwrightResultsDir).filter(f => fs_1.default.statSync(path_1.default.join(playwrightResultsDir, f)).isDirectory());
78
+ if (!folders.length) {
79
+ console.error("No Playwright failure folders found.");
80
+ return;
81
+ }
82
+ const failureFolder = path_1.default.join(playwrightResultsDir, folders[0]);
83
+ const meta = deriveTestMetadata(failureFolder);
84
+ const v1 = await (0, runner_1.runQualityIntelligence)(playwrightResultsDir);
85
+ const normalized = normalizeFailure(v1.dominantCategory, failureFolder);
86
+ line();
87
+ console.log("QUALITY INTELLIGENCE – FINAL PROJECT OUTPUT");
88
+ line();
89
+ console.log(`Test Case : ${meta.testName}`);
90
+ console.log(`Test Location : ${meta.testLocation}`);
91
+ console.log(`Primary Failure : ${normalized.primary}`);
92
+ console.log(`Failure Domain : ${normalized.domain}`);
93
+ console.log(`Confidence Score : ${v1.confidence}`);
94
+ console.log(`Trend Signal : ${v1.trend?.signal ?? "STABLE"}`);
95
+ line("-");
96
+ console.log("WHAT FAILED:");
97
+ console.log(normalized.primary === "UI_VALIDATION_FAILURE"
98
+ ? " UI validation error occurred during user input"
99
+ : normalized.primary === "NUMERIC_MISMATCH"
100
+ ? " Numeric values returned by backend do not match expected results"
101
+ : " Test failure detected");
102
+ line("-");
103
+ console.log("WHY IT FAILED:");
104
+ v1.intelligence.confidence.explanation.forEach(e => console.log(` • ${e}`));
105
+ line("-");
106
+ console.log("WHAT TO DO NEXT:");
107
+ if (normalized.domain === "UI") {
108
+ console.log(" • Review UI validation rules and test assertions");
109
+ }
110
+ else if (normalized.domain === "API") {
111
+ console.log(" • Verify backend calculations and API responses");
112
+ }
113
+ else {
114
+ console.log(" • Review screenshot and trace manually");
115
+ }
116
+ const v2 = await (0, v2_intelligence_pipeline_1.runV2Intelligence)(failureFolder, normalized.primary, "Derived from Playwright failure artifacts");
117
+ line("-");
118
+ console.log("TRACE & SELF-HEALING INTELLIGENCE");
119
+ console.log("Evidence:");
120
+ v2.trace.screenshots.forEach(s => console.log(` Screenshot: ${s}`));
121
+ line("-");
122
+ console.log("Self-Healing Decision:");
123
+ console.log(" Allowed : NO (requires human decision)");
124
+ line();
125
+ }
126
+ /* ===================================================== */
127
+ /* CLI SUPPORT */
128
+ /* ===================================================== */
129
+ if (require.main === module) {
130
+ runFinal();
131
+ }
@@ -0,0 +1,27 @@
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.runFinalOutput = runFinalOutput;
7
+ const child_process_1 = require("child_process");
8
+ const path_1 = __importDefault(require("path"));
9
+ async function runFinalOutput(options) {
10
+ const args = [];
11
+ if (options.showIssues) {
12
+ args.push("--issue");
13
+ }
14
+ // run existing final-run.ts via ts-node / node
15
+ const scriptPath = path_1.default.join(__dirname, "final-run.ts");
16
+ return new Promise((resolve, reject) => {
17
+ const proc = (0, child_process_1.spawn)("node", ["--loader", "ts-node/esm", scriptPath, ...args], {
18
+ stdio: "inherit"
19
+ });
20
+ proc.on("close", code => {
21
+ if (code === 0)
22
+ resolve();
23
+ else
24
+ reject(new Error(`final-run exited with ${code}`));
25
+ });
26
+ });
27
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.test = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ exports.test = test_1.test.extend({
6
+ networkResponses: async ({ page }, use) => {
7
+ const responses = [];
8
+ page.on('response', async (response) => {
9
+ responses.push({
10
+ url: response.url(),
11
+ method: response.request().method(),
12
+ status: response.status(),
13
+ ok: response.ok()
14
+ });
15
+ });
16
+ await use(responses);
17
+ }
18
+ });
@@ -0,0 +1,25 @@
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.saveFailureHistory = saveFailureHistory;
7
+ exports.loadFailureHistory = loadFailureHistory;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const HISTORY_DIR = path_1.default.join(process.cwd(), "artifacts/failure-history");
11
+ function saveFailureHistory(entry) {
12
+ if (!fs_1.default.existsSync(HISTORY_DIR)) {
13
+ fs_1.default.mkdirSync(HISTORY_DIR, { recursive: true });
14
+ }
15
+ const filePath = path_1.default.join(HISTORY_DIR, `${entry.runId}.json`);
16
+ fs_1.default.writeFileSync(filePath, JSON.stringify(entry, null, 2));
17
+ }
18
+ function loadFailureHistory() {
19
+ if (!fs_1.default.existsSync(HISTORY_DIR))
20
+ return [];
21
+ return fs_1.default.readdirSync(HISTORY_DIR).map(file => {
22
+ const fullPath = path_1.default.join(HISTORY_DIR, file);
23
+ return JSON.parse(fs_1.default.readFileSync(fullPath, "utf-8"));
24
+ });
25
+ }