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.
Files changed (65) hide show
  1. package/README.md +123 -0
  2. package/dist/bin/qi.js +27 -0
  3. package/dist/src/adapters/playwright-folder.adapter.js +68 -0
  4. package/dist/src/adapters/playwright-json.adapter.js +46 -0
  5. package/dist/src/adapters/playwright.adapter.js +36 -0
  6. package/dist/src/cli/qi-test.js +20 -0
  7. package/dist/src/cli/qi.js +59 -0
  8. package/dist/src/cli/ui/divider.js +10 -0
  9. package/dist/src/cli/ui/failureLogger.js +24 -0
  10. package/dist/src/configLoader.js +60 -0
  11. package/dist/src/console/issue-view.js +122 -0
  12. package/dist/src/failure-analysis/failure-analyzer.js +38 -0
  13. package/dist/src/final-run.js +130 -0
  14. package/dist/src/final-runner.js +27 -0
  15. package/dist/src/fixtures/networkCollector.js +18 -0
  16. package/dist/src/history/failure-history.store.js +25 -0
  17. package/dist/src/history/failure-history.types.js +4 -0
  18. package/dist/src/history/failure-trend.analyzer.js +31 -0
  19. package/dist/src/index.js +10 -0
  20. package/dist/src/integrations/ci/ci-annotator.js +26 -0
  21. package/dist/src/intelligence/confidence-calibration.engine.js +21 -0
  22. package/dist/src/intelligence/decision-intelligence/confidence.engine.js +16 -0
  23. package/dist/src/intelligence/decision-intelligence/decision.config.js +21 -0
  24. package/dist/src/intelligence/decision-intelligence/decision.engine.js +23 -0
  25. package/dist/src/intelligence/decision-intelligence/decision.types.js +2 -0
  26. package/dist/src/intelligence/failure-fingerprinting/failure.classifier.js +20 -0
  27. package/dist/src/intelligence/failure-fingerprinting/failure.store.js +39 -0
  28. package/dist/src/intelligence/failure-fingerprinting/failure.tracker.js +15 -0
  29. package/dist/src/intelligence/failure-fingerprinting/fingerprint.generator.js +28 -0
  30. package/dist/src/intelligence/failure-fingerprinting/fingerprint.types.js +2 -0
  31. package/dist/src/intelligence/flakiness-intelligence/flakiness.analyzer.js +21 -0
  32. package/dist/src/intelligence/flakiness-intelligence/flakiness.fingerprint.js +16 -0
  33. package/dist/src/intelligence/flakiness-intelligence/flakiness.store.js +24 -0
  34. package/dist/src/intelligence/flakiness-intelligence/flakiness.tracker.js +28 -0
  35. package/dist/src/intelligence/flakiness-intelligence/flakiness.types.js +2 -0
  36. package/dist/src/intelligence/intelligence.pipeline.js +17 -0
  37. package/dist/src/intelligence/llm-explainer.js +19 -0
  38. package/dist/src/intelligence/root-cause/rootcause.engine.js +25 -0
  39. package/dist/src/intelligence/trend-intelligence/trend.engine.js +25 -0
  40. package/dist/src/markdownWriter.js +64 -0
  41. package/dist/src/normalizer.js +17 -0
  42. package/dist/src/passAnalyzer.js +38 -0
  43. package/dist/src/pipeline/ai.summarizer.js +32 -0
  44. package/dist/src/pipeline/failure-analysis.pipeline.js +11 -0
  45. package/dist/src/pipeline/failure-grouping.pipeline.js +47 -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 +121 -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 +23 -0
@@ -0,0 +1,121 @@
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.FileOperationError = void 0;
7
+ exports.readJsonFile = readJsonFile;
8
+ exports.writeJsonFile = writeJsonFile;
9
+ exports.fileExists = fileExists;
10
+ exports.ensureDirectory = ensureDirectory;
11
+ exports.resolvePath = resolvePath;
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ /**
15
+ * Custom error class for file operations
16
+ */
17
+ class FileOperationError extends Error {
18
+ filePath;
19
+ operation;
20
+ originalError;
21
+ constructor(message, filePath, operation, originalError) {
22
+ super(message);
23
+ this.filePath = filePath;
24
+ this.operation = operation;
25
+ this.originalError = originalError;
26
+ this.name = 'FileOperationError';
27
+ }
28
+ }
29
+ exports.FileOperationError = FileOperationError;
30
+ /**
31
+ * Safely read and parse a JSON file with proper error handling
32
+ * @param filePath - Absolute or relative path to the JSON file
33
+ * @returns Parsed JSON object
34
+ * @throws FileOperationError if file cannot be read or parsed
35
+ */
36
+ function readJsonFile(filePath) {
37
+ try {
38
+ // Check if file exists
39
+ if (!fs_1.default.existsSync(filePath)) {
40
+ throw new FileOperationError(`File not found: ${filePath}`, filePath, 'read');
41
+ }
42
+ // Read file content
43
+ let content;
44
+ try {
45
+ content = fs_1.default.readFileSync(filePath, 'utf-8');
46
+ }
47
+ catch (error) {
48
+ throw new FileOperationError(`Failed to read file: ${filePath}`, filePath, 'read', error);
49
+ }
50
+ // Parse JSON
51
+ try {
52
+ return JSON.parse(content);
53
+ }
54
+ catch (error) {
55
+ throw new FileOperationError(`Invalid JSON in file: ${filePath}`, filePath, 'parse', error);
56
+ }
57
+ }
58
+ catch (error) {
59
+ if (error instanceof FileOperationError) {
60
+ throw error;
61
+ }
62
+ throw new FileOperationError(`Unexpected error reading ${filePath}: ${error.message}`, filePath, 'read', error);
63
+ }
64
+ }
65
+ /**
66
+ * Safely write JSON to a file with proper error handling
67
+ * @param filePath - Absolute or relative path to the JSON file
68
+ * @param data - Data to write (will be JSON.stringified)
69
+ * @param pretty - Whether to pretty-print the JSON (default: true)
70
+ */
71
+ function writeJsonFile(filePath, data, pretty = true) {
72
+ try {
73
+ // Ensure directory exists
74
+ const dir = path_1.default.dirname(filePath);
75
+ if (!fs_1.default.existsSync(dir)) {
76
+ fs_1.default.mkdirSync(dir, { recursive: true });
77
+ }
78
+ // Stringify data
79
+ const content = pretty
80
+ ? JSON.stringify(data, null, 2)
81
+ : JSON.stringify(data);
82
+ // Write to file
83
+ try {
84
+ fs_1.default.writeFileSync(filePath, content, 'utf-8');
85
+ }
86
+ catch (error) {
87
+ throw new FileOperationError(`Failed to write file: ${filePath}`, filePath, 'write', error);
88
+ }
89
+ }
90
+ catch (error) {
91
+ if (error instanceof FileOperationError) {
92
+ throw error;
93
+ }
94
+ throw new FileOperationError(`Unexpected error writing ${filePath}: ${error.message}`, filePath, 'write', error);
95
+ }
96
+ }
97
+ /**
98
+ * Check if a file exists
99
+ * @param filePath - Path to check
100
+ * @returns true if file exists
101
+ */
102
+ function fileExists(filePath) {
103
+ return fs_1.default.existsSync(filePath);
104
+ }
105
+ /**
106
+ * Ensure a directory exists, creating it if necessary
107
+ * @param dirPath - Directory path to ensure
108
+ */
109
+ function ensureDirectory(dirPath) {
110
+ if (!fs_1.default.existsSync(dirPath)) {
111
+ fs_1.default.mkdirSync(dirPath, { recursive: true });
112
+ }
113
+ }
114
+ /**
115
+ * Resolve a path relative to the project root
116
+ * @param relativePath - Path relative to project root
117
+ * @returns Absolute path
118
+ */
119
+ function resolvePath(...segments) {
120
+ return path_1.default.join(process.cwd(), ...segments);
121
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ // src/v2/llm/llm-advisor.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.getLLMAdvice = getLLMAdvice;
5
+ /**
6
+ * Stub for ChatGPT / Azure / Local LLM
7
+ */
8
+ async function getLLMAdvice(failureSummary) {
9
+ return {
10
+ summary: `AI analysis of failure: ${failureSummary}`,
11
+ fixRecommendation: [
12
+ "Check backend API response",
13
+ "Validate UI rendering timing",
14
+ "Review recent code changes"
15
+ ]
16
+ };
17
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ // src/v2/pipeline/v2-intelligence.pipeline.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.runV2Intelligence = runV2Intelligence;
5
+ const trace_analyzer_1 = require("../trace-intelligence/trace-analyzer");
6
+ const self_healer_1 = require("../self-healing/self-healer");
7
+ const llm_advisor_1 = require("../llm/llm-advisor");
8
+ async function runV2Intelligence(failureFolder, failureType, errorMessage) {
9
+ const trace = (0, trace_analyzer_1.analyzeTrace)(failureFolder);
10
+ const healing = (0, self_healer_1.attemptSelfHeal)(failureType, errorMessage);
11
+ const llm = await (0, llm_advisor_1.getLLMAdvice)(failureType);
12
+ return {
13
+ trace,
14
+ healing,
15
+ llm
16
+ };
17
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ // src/v2/self-healing/self-healer.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.attemptSelfHeal = attemptSelfHeal;
5
+ /**
6
+ * Self-Healing Decision Engine (V2)
7
+ * Decides WHAT can be auto-fixed and WHAT should not
8
+ */
9
+ function attemptSelfHeal(failureType, errorMessage) {
10
+ const msg = errorMessage.toLowerCase();
11
+ // 🔁 Flaky tests
12
+ if (failureType === "FLAKY") {
13
+ return {
14
+ reason: "Intermittent retry-based failure detected",
15
+ suggestedFix: "Add proper waits or retry assertions",
16
+ confidence: 0.6
17
+ };
18
+ }
19
+ // 🧭 UI / Locator issues
20
+ if (failureType === "UI_STATE" || failureType === "LOCATOR_CHANGED") {
21
+ return {
22
+ reason: "UI element state or locator changed",
23
+ suggestedFix: "Re-locate element using role/text-based selectors",
24
+ confidence: 0.7
25
+ };
26
+ }
27
+ // 🔢 Numeric mismatch — CONDITIONAL healing
28
+ if (failureType === "NUMERIC_MISMATCH") {
29
+ // UI-level numeric problems (healable)
30
+ if (msg.includes("count") ||
31
+ msg.includes("items") ||
32
+ msg.includes("length") ||
33
+ msg.includes("round")) {
34
+ return {
35
+ reason: "UI count or rounding issue detected",
36
+ suggestedFix: "Update assertion logic or normalize UI values",
37
+ confidence: 0.55
38
+ };
39
+ }
40
+ // Backend/API numeric issues (DO NOT HEAL)
41
+ return null;
42
+ }
43
+ return null;
44
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ // src/v2/trace-intelligence/trace-analyzer.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.analyzeTrace = analyzeTrace;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ function analyzeTrace(failureFolder) {
11
+ const fullPath = path_1.default.resolve(failureFolder);
12
+ if (!fs_1.default.existsSync(fullPath)) {
13
+ return {
14
+ page: "UNKNOWN",
15
+ failureStep: "Trace folder not found",
16
+ screenshots: [],
17
+ note: `Missing folder: ${failureFolder}`
18
+ };
19
+ }
20
+ const files = fs_1.default.readdirSync(fullPath);
21
+ const screenshots = files
22
+ .filter(f => f.endsWith(".png") || f.endsWith(".jpg"))
23
+ .map(f => path_1.default.join(fullPath, f));
24
+ const traceFile = files.includes("trace.zip")
25
+ ? path_1.default.join(fullPath, "trace.zip")
26
+ : undefined;
27
+ return {
28
+ page: "UNKNOWN_PAGE",
29
+ failureStep: "Action before failure",
30
+ screenshots,
31
+ traceFile
32
+ };
33
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ // src/v2-test-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
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const v2_intelligence_pipeline_1 = require("./v2/pipeline/v2-intelligence.pipeline");
10
+ function pickOneFailureFolder() {
11
+ const base = "playwright-results";
12
+ if (!fs_1.default.existsSync(base))
13
+ return null;
14
+ const entries = fs_1.default.readdirSync(base, { withFileTypes: true });
15
+ const folder = entries.find(e => e.isDirectory());
16
+ return folder ? path_1.default.join(base, folder.name) : null;
17
+ }
18
+ async function run() {
19
+ const failureFolder = pickOneFailureFolder();
20
+ if (!failureFolder) {
21
+ console.error("No Playwright failure folders found.");
22
+ return;
23
+ }
24
+ const result = await (0, v2_intelligence_pipeline_1.runV2Intelligence)(failureFolder, "NUMERIC_MISMATCH", "Expected 10, received 6");
25
+ console.log("==================================================");
26
+ console.log("V2 TRACE INTELLIGENCE OUTPUT");
27
+ console.log("==================================================");
28
+ console.log(`Failure Folder : ${failureFolder}`);
29
+ console.log(`Failure Type : NUMERIC_MISMATCH`);
30
+ console.log("\nEvidence:");
31
+ if (result.trace.screenshots.length > 0) {
32
+ console.log(" Screenshots:");
33
+ result.trace.screenshots.forEach(s => console.log(` - ${s}`));
34
+ }
35
+ else {
36
+ console.log(" Screenshots: none");
37
+ }
38
+ if (result.trace.traceFile) {
39
+ console.log(` Trace File : ${result.trace.traceFile}`);
40
+ console.log(` Open with : npx playwright show-trace ${result.trace.traceFile}`);
41
+ }
42
+ else {
43
+ console.log(" Trace File : none");
44
+ }
45
+ console.log("\nSelf-Healing:");
46
+ if (result.healing) {
47
+ console.log(` Reason : ${result.healing.reason}`);
48
+ console.log(` SuggestedFix : ${result.healing.suggestedFix}`);
49
+ console.log(` Confidence : ${result.healing.confidence}`);
50
+ }
51
+ else {
52
+ console.log(" Not safe to auto-heal");
53
+ }
54
+ console.log("\nAI Advice:");
55
+ console.log(` Summary: ${result.llm.summary}`);
56
+ result.llm.fixRecommendation.forEach(r => console.log(` - ${r}`));
57
+ console.log("==================================================");
58
+ }
59
+ run();
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "quality-intelligence-engine",
3
+ "version": "2.2.0",
4
+ "description": "AI-powered failure intelligence for Playwright test runs",
5
+ "bin": {
6
+ "qi": "dist/bin/qi.js"
7
+ },
8
+ "scripts": {
9
+ "build": "tsc"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "devDependencies": {
19
+ "@playwright/test": "^1.58.0",
20
+ "ts-node": "^10.9.2",
21
+ "typescript": "^5.3.3"
22
+ }
23
+ }