qa360 1.4.5 → 2.0.1

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 (209) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/ai.d.ts +41 -0
  3. package/dist/commands/ai.js +499 -0
  4. package/dist/commands/ask.js +12 -12
  5. package/dist/commands/coverage.d.ts +8 -0
  6. package/dist/commands/coverage.js +252 -0
  7. package/dist/commands/explain.d.ts +27 -0
  8. package/dist/commands/explain.js +630 -0
  9. package/dist/commands/flakiness.d.ts +73 -0
  10. package/dist/commands/flakiness.js +435 -0
  11. package/dist/commands/generate.d.ts +66 -0
  12. package/dist/commands/generate.js +438 -0
  13. package/dist/commands/init.d.ts +56 -9
  14. package/dist/commands/init.js +217 -10
  15. package/dist/commands/monitor.d.ts +27 -0
  16. package/dist/commands/monitor.js +225 -0
  17. package/dist/commands/ollama.d.ts +40 -0
  18. package/dist/commands/ollama.js +301 -0
  19. package/dist/commands/pack.d.ts +37 -9
  20. package/dist/commands/pack.js +240 -141
  21. package/dist/commands/regression.d.ts +8 -0
  22. package/dist/commands/regression.js +340 -0
  23. package/dist/commands/repair.d.ts +26 -0
  24. package/dist/commands/repair.js +307 -0
  25. package/dist/commands/retry.d.ts +43 -0
  26. package/dist/commands/retry.js +275 -0
  27. package/dist/commands/run.d.ts +8 -3
  28. package/dist/commands/run.js +45 -31
  29. package/dist/commands/slo.d.ts +8 -0
  30. package/dist/commands/slo.js +327 -0
  31. package/dist/core/adapters/playwright-native-api.d.ts +183 -0
  32. package/dist/core/adapters/playwright-native-api.js +461 -0
  33. package/dist/core/adapters/playwright-ui.d.ts +7 -0
  34. package/dist/core/adapters/playwright-ui.js +29 -1
  35. package/dist/core/ai/anthropic-provider.d.ts +50 -0
  36. package/dist/core/ai/anthropic-provider.js +211 -0
  37. package/dist/core/ai/deepseek-provider.d.ts +81 -0
  38. package/dist/core/ai/deepseek-provider.js +254 -0
  39. package/dist/core/ai/index.d.ts +60 -0
  40. package/dist/core/ai/index.js +18 -0
  41. package/dist/core/ai/llm-client.d.ts +45 -0
  42. package/dist/core/ai/llm-client.js +7 -0
  43. package/dist/core/ai/mock-provider.d.ts +49 -0
  44. package/dist/core/ai/mock-provider.js +121 -0
  45. package/dist/core/ai/ollama-provider.d.ts +78 -0
  46. package/dist/core/ai/ollama-provider.js +192 -0
  47. package/dist/core/ai/openai-provider.d.ts +48 -0
  48. package/dist/core/ai/openai-provider.js +188 -0
  49. package/dist/core/ai/provider-factory.d.ts +160 -0
  50. package/dist/core/ai/provider-factory.js +269 -0
  51. package/dist/core/auth/api-key-provider.d.ts +16 -0
  52. package/dist/core/auth/api-key-provider.js +63 -0
  53. package/dist/core/auth/aws-iam-provider.d.ts +35 -0
  54. package/dist/core/auth/aws-iam-provider.js +177 -0
  55. package/dist/core/auth/azure-ad-provider.d.ts +15 -0
  56. package/dist/core/auth/azure-ad-provider.js +99 -0
  57. package/dist/core/auth/basic-auth-provider.d.ts +26 -0
  58. package/dist/core/auth/basic-auth-provider.js +111 -0
  59. package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
  60. package/dist/core/auth/gcp-adc-provider.js +126 -0
  61. package/dist/core/auth/index.d.ts +238 -0
  62. package/dist/core/auth/index.js +82 -0
  63. package/dist/core/auth/jwt-provider.d.ts +19 -0
  64. package/dist/core/auth/jwt-provider.js +160 -0
  65. package/dist/core/auth/manager.d.ts +84 -0
  66. package/dist/core/auth/manager.js +230 -0
  67. package/dist/core/auth/oauth2-provider.d.ts +17 -0
  68. package/dist/core/auth/oauth2-provider.js +114 -0
  69. package/dist/core/auth/totp-provider.d.ts +31 -0
  70. package/dist/core/auth/totp-provider.js +134 -0
  71. package/dist/core/auth/ui-login-provider.d.ts +26 -0
  72. package/dist/core/auth/ui-login-provider.js +198 -0
  73. package/dist/core/cache/index.d.ts +7 -0
  74. package/dist/core/cache/index.js +6 -0
  75. package/dist/core/cache/lru-cache.d.ts +203 -0
  76. package/dist/core/cache/lru-cache.js +397 -0
  77. package/dist/core/coverage/analyzer.d.ts +101 -0
  78. package/dist/core/coverage/analyzer.js +415 -0
  79. package/dist/core/coverage/collector.d.ts +74 -0
  80. package/dist/core/coverage/collector.js +459 -0
  81. package/dist/core/coverage/config.d.ts +37 -0
  82. package/dist/core/coverage/config.js +156 -0
  83. package/dist/core/coverage/index.d.ts +11 -0
  84. package/dist/core/coverage/index.js +15 -0
  85. package/dist/core/coverage/types.d.ts +267 -0
  86. package/dist/core/coverage/types.js +6 -0
  87. package/dist/core/coverage/vault.d.ts +95 -0
  88. package/dist/core/coverage/vault.js +405 -0
  89. package/dist/core/dashboard/assets.d.ts +6 -0
  90. package/dist/core/dashboard/assets.js +690 -0
  91. package/dist/core/dashboard/index.d.ts +6 -0
  92. package/dist/core/dashboard/index.js +5 -0
  93. package/dist/core/dashboard/server.d.ts +72 -0
  94. package/dist/core/dashboard/server.js +354 -0
  95. package/dist/core/dashboard/types.d.ts +70 -0
  96. package/dist/core/dashboard/types.js +5 -0
  97. package/dist/core/discoverer/index.d.ts +115 -0
  98. package/dist/core/discoverer/index.js +250 -0
  99. package/dist/core/flakiness/index.d.ts +228 -0
  100. package/dist/core/flakiness/index.js +384 -0
  101. package/dist/core/generation/code-formatter.d.ts +111 -0
  102. package/dist/core/generation/code-formatter.js +307 -0
  103. package/dist/core/generation/code-generator.d.ts +144 -0
  104. package/dist/core/generation/code-generator.js +293 -0
  105. package/dist/core/generation/generator.d.ts +40 -0
  106. package/dist/core/generation/generator.js +76 -0
  107. package/dist/core/generation/index.d.ts +30 -0
  108. package/dist/core/generation/index.js +28 -0
  109. package/dist/core/generation/pack-generator.d.ts +107 -0
  110. package/dist/core/generation/pack-generator.js +416 -0
  111. package/dist/core/generation/prompt-builder.d.ts +132 -0
  112. package/dist/core/generation/prompt-builder.js +672 -0
  113. package/dist/core/generation/source-analyzer.d.ts +213 -0
  114. package/dist/core/generation/source-analyzer.js +657 -0
  115. package/dist/core/generation/test-optimizer.d.ts +117 -0
  116. package/dist/core/generation/test-optimizer.js +328 -0
  117. package/dist/core/generation/types.d.ts +214 -0
  118. package/dist/core/generation/types.js +4 -0
  119. package/dist/core/index.d.ts +23 -1
  120. package/dist/core/index.js +39 -0
  121. package/dist/core/pack/validator.js +31 -1
  122. package/dist/core/pack-v2/index.d.ts +9 -0
  123. package/dist/core/pack-v2/index.js +8 -0
  124. package/dist/core/pack-v2/loader.d.ts +62 -0
  125. package/dist/core/pack-v2/loader.js +231 -0
  126. package/dist/core/pack-v2/migrator.d.ts +56 -0
  127. package/dist/core/pack-v2/migrator.js +455 -0
  128. package/dist/core/pack-v2/validator.d.ts +61 -0
  129. package/dist/core/pack-v2/validator.js +577 -0
  130. package/dist/core/regression/detector.d.ts +107 -0
  131. package/dist/core/regression/detector.js +497 -0
  132. package/dist/core/regression/index.d.ts +9 -0
  133. package/dist/core/regression/index.js +11 -0
  134. package/dist/core/regression/trend-analyzer.d.ts +102 -0
  135. package/dist/core/regression/trend-analyzer.js +345 -0
  136. package/dist/core/regression/types.d.ts +222 -0
  137. package/dist/core/regression/types.js +7 -0
  138. package/dist/core/regression/vault.d.ts +87 -0
  139. package/dist/core/regression/vault.js +289 -0
  140. package/dist/core/repair/engine/fixer.d.ts +24 -0
  141. package/dist/core/repair/engine/fixer.js +226 -0
  142. package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
  143. package/dist/core/repair/engine/suggestion-engine.js +187 -0
  144. package/dist/core/repair/index.d.ts +10 -0
  145. package/dist/core/repair/index.js +13 -0
  146. package/dist/core/repair/repairer.d.ts +90 -0
  147. package/dist/core/repair/repairer.js +284 -0
  148. package/dist/core/repair/types.d.ts +91 -0
  149. package/dist/core/repair/types.js +6 -0
  150. package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
  151. package/dist/core/repair/utils/error-analyzer.js +264 -0
  152. package/dist/core/retry/flakiness-integration.d.ts +60 -0
  153. package/dist/core/retry/flakiness-integration.js +228 -0
  154. package/dist/core/retry/index.d.ts +14 -0
  155. package/dist/core/retry/index.js +16 -0
  156. package/dist/core/retry/retry-engine.d.ts +80 -0
  157. package/dist/core/retry/retry-engine.js +296 -0
  158. package/dist/core/retry/types.d.ts +178 -0
  159. package/dist/core/retry/types.js +52 -0
  160. package/dist/core/retry/vault.d.ts +77 -0
  161. package/dist/core/retry/vault.js +304 -0
  162. package/dist/core/runner/e2e-helpers.d.ts +102 -0
  163. package/dist/core/runner/e2e-helpers.js +153 -0
  164. package/dist/core/runner/phase3-runner.d.ts +101 -2
  165. package/dist/core/runner/phase3-runner.js +559 -24
  166. package/dist/core/self-healing/assertion-healer.d.ts +97 -0
  167. package/dist/core/self-healing/assertion-healer.js +371 -0
  168. package/dist/core/self-healing/engine.d.ts +122 -0
  169. package/dist/core/self-healing/engine.js +538 -0
  170. package/dist/core/self-healing/index.d.ts +10 -0
  171. package/dist/core/self-healing/index.js +11 -0
  172. package/dist/core/self-healing/selector-healer.d.ts +103 -0
  173. package/dist/core/self-healing/selector-healer.js +372 -0
  174. package/dist/core/self-healing/types.d.ts +152 -0
  175. package/dist/core/self-healing/types.js +6 -0
  176. package/dist/core/slo/config.d.ts +107 -0
  177. package/dist/core/slo/config.js +360 -0
  178. package/dist/core/slo/index.d.ts +11 -0
  179. package/dist/core/slo/index.js +15 -0
  180. package/dist/core/slo/sli-calculator.d.ts +92 -0
  181. package/dist/core/slo/sli-calculator.js +364 -0
  182. package/dist/core/slo/slo-tracker.d.ts +148 -0
  183. package/dist/core/slo/slo-tracker.js +379 -0
  184. package/dist/core/slo/types.d.ts +281 -0
  185. package/dist/core/slo/types.js +7 -0
  186. package/dist/core/slo/vault.d.ts +102 -0
  187. package/dist/core/slo/vault.js +427 -0
  188. package/dist/core/tui/index.d.ts +7 -0
  189. package/dist/core/tui/index.js +6 -0
  190. package/dist/core/tui/monitor.d.ts +92 -0
  191. package/dist/core/tui/monitor.js +271 -0
  192. package/dist/core/tui/renderer.d.ts +33 -0
  193. package/dist/core/tui/renderer.js +218 -0
  194. package/dist/core/tui/types.d.ts +63 -0
  195. package/dist/core/tui/types.js +5 -0
  196. package/dist/core/types/pack-v2.d.ts +425 -0
  197. package/dist/core/types/pack-v2.js +8 -0
  198. package/dist/core/vault/index.d.ts +116 -0
  199. package/dist/core/vault/index.js +400 -5
  200. package/dist/core/watch/index.d.ts +7 -0
  201. package/dist/core/watch/index.js +6 -0
  202. package/dist/core/watch/watch-mode.d.ts +213 -0
  203. package/dist/core/watch/watch-mode.js +389 -0
  204. package/dist/index.js +68 -68
  205. package/dist/utils/config.d.ts +5 -0
  206. package/dist/utils/config.js +136 -0
  207. package/package.json +5 -1
  208. package/dist/core/adapters/playwright-api.d.ts +0 -82
  209. package/dist/core/adapters/playwright-api.js +0 -264
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Assertion Healer
3
+ *
4
+ * Intelligently heals broken assertions in tests.
5
+ * Supports Jest, Chai, and Node.js assert styles.
6
+ */
7
+ import type { AssertionUpdateResult, AssertionType, SelfHealingConfig } from './types.js';
8
+ /**
9
+ * Parsed assertion information
10
+ */
11
+ interface ParsedAssertion {
12
+ type: AssertionType;
13
+ originalAssertion?: string;
14
+ actual: string;
15
+ expected: string;
16
+ negated: boolean;
17
+ matcher?: string;
18
+ line: number;
19
+ column: number;
20
+ }
21
+ /**
22
+ * Assertion healing options
23
+ */
24
+ interface AssertionHealOptions {
25
+ /** Test file content */
26
+ fileContent: string;
27
+ /** Line number of failed assertion */
28
+ lineNumber: number;
29
+ /** Expected value */
30
+ expected: string;
31
+ /** Actual value received */
32
+ actual: string;
33
+ /** Error message from failure */
34
+ errorMessage?: string;
35
+ /** Test framework (jest, chai, assert) */
36
+ framework?: 'jest' | 'chai' | 'assert' | 'auto';
37
+ }
38
+ /**
39
+ * Assertion Healer class
40
+ */
41
+ export declare class AssertionHealer {
42
+ private config;
43
+ constructor(config: SelfHealingConfig);
44
+ /**
45
+ * Attempt to heal a broken assertion
46
+ */
47
+ healAssertion(options: AssertionHealOptions): Promise<AssertionUpdateResult | null>;
48
+ /**
49
+ * Parse the assertion from file content
50
+ */
51
+ private parseAssertion;
52
+ /**
53
+ * Detect test framework from file content
54
+ */
55
+ private detectFramework;
56
+ /**
57
+ * Parse Jest-style assertion
58
+ */
59
+ private parseJestAssertion;
60
+ /**
61
+ * Parse Chai-style assertion
62
+ */
63
+ private parseChaiAssertion;
64
+ /**
65
+ * Parse Node.js assert-style assertion
66
+ */
67
+ private parseAssertAssertion;
68
+ /**
69
+ * Map Jest matcher to assertion type
70
+ */
71
+ private mapJestMatcherToType;
72
+ /**
73
+ * Map Chai matcher to assertion type
74
+ */
75
+ private mapChaiMatcherToType;
76
+ /**
77
+ * Calculate confidence for healing
78
+ */
79
+ private calculateHealingConfidence;
80
+ /**
81
+ * Generate healed assertion
82
+ */
83
+ private generateHealedAssertion;
84
+ /**
85
+ * Format a value for use in code
86
+ */
87
+ private formatValue;
88
+ /**
89
+ * Calculate similarity between two strings (Levenshtein-based)
90
+ */
91
+ private calculateStringSimilarity;
92
+ /**
93
+ * Parse multiple assertions from a file
94
+ */
95
+ parseAssertionsFromFile(content: string): ParsedAssertion[];
96
+ }
97
+ export {};
@@ -0,0 +1,371 @@
1
+ /**
2
+ * Assertion Healer
3
+ *
4
+ * Intelligently heals broken assertions in tests.
5
+ * Supports Jest, Chai, and Node.js assert styles.
6
+ */
7
+ /**
8
+ * Assertion Healer class
9
+ */
10
+ export class AssertionHealer {
11
+ config;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ /**
16
+ * Attempt to heal a broken assertion
17
+ */
18
+ async healAssertion(options) {
19
+ if (!this.config.features.assertionUpdates) {
20
+ return null;
21
+ }
22
+ const parsed = this.parseAssertion(options);
23
+ if (!parsed) {
24
+ return null;
25
+ }
26
+ // Determine if healing is possible
27
+ const confidence = this.calculateHealingConfidence(parsed, options);
28
+ if (confidence < (this.config.confidenceThreshold || 0.7)) {
29
+ return null;
30
+ }
31
+ // Generate healed assertion
32
+ const updatedAssertion = this.generateHealedAssertion(parsed, options);
33
+ return {
34
+ testFile: '', // Caller should fill this
35
+ lineNumber: options.lineNumber,
36
+ originalAssertion: parsed.originalAssertion || '',
37
+ updatedAssertion,
38
+ expected: options.expected,
39
+ actual: options.actual,
40
+ confidence,
41
+ assertionType: parsed.type
42
+ };
43
+ }
44
+ /**
45
+ * Parse the assertion from file content
46
+ */
47
+ parseAssertion(options) {
48
+ const lines = options.fileContent.split('\n');
49
+ const line = lines[options.lineNumber - 1];
50
+ if (!line) {
51
+ return null;
52
+ }
53
+ const framework = options.framework === 'auto' ? this.detectFramework(options.fileContent) : options.framework;
54
+ switch (framework) {
55
+ case 'jest':
56
+ return this.parseJestAssertion(line, options);
57
+ case 'chai':
58
+ return this.parseChaiAssertion(line, options);
59
+ case 'assert':
60
+ return this.parseAssertAssertion(line, options);
61
+ default:
62
+ // Try all parsers
63
+ return (this.parseJestAssertion(line, options) ||
64
+ this.parseChaiAssertion(line, options) ||
65
+ this.parseAssertAssertion(line, options));
66
+ }
67
+ }
68
+ /**
69
+ * Detect test framework from file content
70
+ */
71
+ detectFramework(content) {
72
+ const hasJest = /\b(expect|describe|it|test)\(/.test(content);
73
+ const hasChai = /\b(expect|should)\./.test(content) && /\b(chai|assert)\b/.test(content);
74
+ const hasAssert = /\b(require\(['"]assert['"]\)|import.*assert)\b/.test(content);
75
+ if (hasJest && !hasChai)
76
+ return 'jest';
77
+ if (hasChai)
78
+ return 'chai';
79
+ if (hasAssert)
80
+ return 'assert';
81
+ return 'jest'; // Default
82
+ }
83
+ /**
84
+ * Parse Jest-style assertion
85
+ */
86
+ parseJestAssertion(line, options) {
87
+ const jestPattern = /expect\(([^)]+)\)\.\s*(not\.)?(to[\w]+)\(([^)]*)\)/;
88
+ const match = line.match(jestPattern);
89
+ if (!match) {
90
+ return null;
91
+ }
92
+ const [, actual, negated, matcher, expected] = match;
93
+ const type = this.mapJestMatcherToType(matcher);
94
+ return {
95
+ type,
96
+ originalAssertion: line.trim(),
97
+ actual: actual.trim(),
98
+ expected: expected.trim() || options.expected,
99
+ negated: !!negated,
100
+ matcher,
101
+ line: options.lineNumber,
102
+ column: line.indexOf(match[0]) + 1
103
+ };
104
+ }
105
+ /**
106
+ * Parse Chai-style assertion
107
+ */
108
+ parseChaiAssertion(line, options) {
109
+ // expect(actual).to/match/have.property
110
+ const expectPattern = /expect\(([^)]+)\)\.\s*(to|should)\.\s*(not\.)?([\w.]+)\(([^)]*)\)/;
111
+ let match = line.match(expectPattern);
112
+ if (match) {
113
+ const [, actual, , negated, matcher, expected] = match;
114
+ const type = this.mapChaiMatcherToType(matcher);
115
+ return {
116
+ type,
117
+ originalAssertion: line.trim(),
118
+ actual: actual.trim(),
119
+ expected: expected.trim() || options.expected,
120
+ negated: !!negated,
121
+ matcher,
122
+ line: options.lineNumber,
123
+ column: line.indexOf(match[0]) + 1
124
+ };
125
+ }
126
+ // should style
127
+ const shouldPattern = /([\w.]+)\.should\.\s*(not\.)?([\w.]+)\(([^)]*)\)/;
128
+ match = line.match(shouldPattern);
129
+ if (match) {
130
+ const [, actual, negated, matcher, expected] = match;
131
+ const type = this.mapChaiMatcherToType(matcher);
132
+ return {
133
+ type,
134
+ originalAssertion: line.trim(),
135
+ actual: actual.trim(),
136
+ expected: expected.trim() || options.expected,
137
+ negated: !!negated,
138
+ matcher,
139
+ line: options.lineNumber,
140
+ column: line.indexOf(match[0]) + 1
141
+ };
142
+ }
143
+ return null;
144
+ }
145
+ /**
146
+ * Parse Node.js assert-style assertion
147
+ */
148
+ parseAssertAssertion(line, options) {
149
+ // assert.strictEqual(actual, expected)
150
+ const strictEqualPattern = /assert\.(strictEqual|deepStrictEqual|equal)\(([^,]+),\s*([^)]+)\)/;
151
+ let match = line.match(strictEqualPattern);
152
+ if (match) {
153
+ const [, method, actual, expected] = match;
154
+ return {
155
+ type: 'equality',
156
+ originalAssertion: line.trim(),
157
+ actual: actual.trim(),
158
+ expected: expected.trim(),
159
+ negated: false,
160
+ matcher: method,
161
+ line: options.lineNumber,
162
+ column: line.indexOf(match[0]) + 1
163
+ };
164
+ }
165
+ // assert actual, expected
166
+ const simplePattern = new RegExp('^(assert\\.\\w+\\([^,]+),\\s*)');
167
+ const simpleMatch = line.match(simplePattern);
168
+ if (simpleMatch) {
169
+ return {
170
+ type: 'equality',
171
+ originalAssertion: line.trim(),
172
+ actual: simpleMatch[1],
173
+ expected: options.expected,
174
+ negated: false,
175
+ matcher: 'assert',
176
+ line: options.lineNumber,
177
+ column: 1
178
+ };
179
+ }
180
+ return null;
181
+ }
182
+ /**
183
+ * Map Jest matcher to assertion type
184
+ */
185
+ mapJestMatcherToType(matcher) {
186
+ const matcherMap = {
187
+ 'toBe': 'equality',
188
+ 'toEqual': 'equality',
189
+ 'toStrictEqual': 'equality',
190
+ 'toBeGreaterThan': 'count',
191
+ 'toBeGreaterThanOrEqual': 'count',
192
+ 'toBeLessThan': 'count',
193
+ 'toBeLessThanOrEqual': 'count',
194
+ 'toContain': 'containment',
195
+ 'toContainEqual': 'containment',
196
+ 'toMatch': 'containment',
197
+ 'toMatchObject': 'containment',
198
+ 'toBeTruthy': 'truthiness',
199
+ 'toBeFalsy': 'truthiness',
200
+ 'toBeNull': 'truthiness',
201
+ 'toBeUndefined': 'truthiness',
202
+ 'toBeDefined': 'truthiness',
203
+ 'toHaveLength': 'count',
204
+ 'toHaveProperty': 'containment'
205
+ };
206
+ return matcherMap[matcher] || 'equality';
207
+ }
208
+ /**
209
+ * Map Chai matcher to assertion type
210
+ */
211
+ mapChaiMatcherToType(matcher) {
212
+ const matcherMap = {
213
+ 'equal': 'equality',
214
+ 'deep.equal': 'equality',
215
+ 'eql': 'equality',
216
+ 'above': 'count',
217
+ 'least': 'count',
218
+ 'below': 'count',
219
+ 'most': 'count',
220
+ 'include': 'containment',
221
+ 'contain': 'containment',
222
+ 'contains': 'containment',
223
+ 'match': 'containment',
224
+ 'property': 'containment',
225
+ 'true': 'truthiness',
226
+ 'false': 'truthiness',
227
+ 'null': 'truthiness',
228
+ 'undefined': 'truthiness',
229
+ 'exist': 'truthiness',
230
+ 'empty': 'truthiness',
231
+ 'lengthOf': 'count'
232
+ };
233
+ return matcherMap[matcher] || 'equality';
234
+ }
235
+ /**
236
+ * Calculate confidence for healing
237
+ */
238
+ calculateHealingConfidence(parsed, options) {
239
+ let confidence = 0.5;
240
+ // Type-specific adjustments
241
+ if (parsed.type === 'equality') {
242
+ // Simple value changes are high confidence
243
+ const diffScore = this.calculateStringSimilarity(options.expected, options.actual);
244
+ confidence = Math.max(confidence, diffScore * 0.9);
245
+ }
246
+ if (parsed.type === 'containment') {
247
+ // Adding missing items is medium-high confidence
248
+ confidence = 0.75;
249
+ }
250
+ if (parsed.type === 'count') {
251
+ // Adjusting numbers is high confidence
252
+ const expectedNum = parseInt(options.expected, 10);
253
+ const actualNum = parseInt(options.actual, 10);
254
+ if (!isNaN(expectedNum) && !isNaN(actualNum)) {
255
+ confidence = 0.85;
256
+ }
257
+ }
258
+ // Adjust for negation
259
+ if (parsed.negated) {
260
+ confidence *= 0.8; // Lower confidence for negated assertions
261
+ }
262
+ // Adjust for error message clarity
263
+ if (options.errorMessage) {
264
+ if (options.errorMessage.includes('Expected:') && options.errorMessage.includes('Received:')) {
265
+ confidence += 0.1;
266
+ }
267
+ }
268
+ return Math.min(confidence, 1.0);
269
+ }
270
+ /**
271
+ * Generate healed assertion
272
+ */
273
+ generateHealedAssertion(parsed, options) {
274
+ const actualValue = this.formatValue(options.actual);
275
+ const expectedValue = this.formatValue(options.expected);
276
+ if (parsed.matcher?.includes('toBe') || parsed.matcher === 'equal') {
277
+ // Jest: expect(actual).toBe(expected)
278
+ // Chai: expect(actual).to.equal(expected)
279
+ const isJest = parsed.matcher?.startsWith('to');
280
+ const separator = isJest ? `.${parsed.matcher}(` : `.to.${parsed.matcher}(`;
281
+ return `expect(${parsed.actual}).${parsed.negated ? 'not.' : ''}${separator}${expectedValue})`;
282
+ }
283
+ if (parsed.matcher?.includes('Equal') || parsed.matcher === 'deep.equal' || parsed.matcher === 'eql') {
284
+ return `expect(${parsed.actual})${parsed.negated ? '.not.' : '.'}${parsed.matcher || 'toEqual'}(${expectedValue})`;
285
+ }
286
+ if (parsed.matcher?.includes('Contain') || parsed.matcher?.includes('include')) {
287
+ return `expect(${parsed.actual})${parsed.negated ? '.not.' : '.'}${parsed.matcher || 'toContain'}(${expectedValue})`;
288
+ }
289
+ // Default: update expected value in original
290
+ let result = parsed.originalAssertion || '';
291
+ // Replace the expected value
292
+ const lastComma = result.lastIndexOf(',');
293
+ if (lastComma !== -1) {
294
+ result = result.substring(0, lastComma + 1) + ' ' + expectedValue + result.substring(result.lastIndexOf(')'));
295
+ }
296
+ return result;
297
+ }
298
+ /**
299
+ * Format a value for use in code
300
+ */
301
+ formatValue(value) {
302
+ // Try to detect if it's already formatted
303
+ if (/^['"`{[\[]/.test(value)) {
304
+ return value;
305
+ }
306
+ // Numbers
307
+ if (/^\d+$/.test(value)) {
308
+ return value;
309
+ }
310
+ // Booleans
311
+ if (value === 'true' || value === 'false') {
312
+ return value;
313
+ }
314
+ // Null/undefined
315
+ if (value === 'null' || value === 'undefined') {
316
+ return value;
317
+ }
318
+ // Default: treat as string
319
+ return JSON.stringify(value);
320
+ }
321
+ /**
322
+ * Calculate similarity between two strings (Levenshtein-based)
323
+ */
324
+ calculateStringSimilarity(str1, str2) {
325
+ const len1 = str1.length;
326
+ const len2 = str2.length;
327
+ if (len1 === 0)
328
+ return len2 === 0 ? 1 : 0;
329
+ if (len2 === 0)
330
+ return 0;
331
+ const matrix = [];
332
+ for (let i = 0; i <= len1; i++) {
333
+ matrix[i] = [i];
334
+ }
335
+ for (let j = 0; j <= len2; j++) {
336
+ matrix[0][j] = j;
337
+ }
338
+ for (let i = 1; i <= len1; i++) {
339
+ for (let j = 1; j <= len2; j++) {
340
+ const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
341
+ matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
342
+ }
343
+ }
344
+ const maxLen = Math.max(len1, len2);
345
+ return 1 - matrix[len1][len2] / maxLen;
346
+ }
347
+ /**
348
+ * Parse multiple assertions from a file
349
+ */
350
+ parseAssertionsFromFile(content) {
351
+ const assertions = [];
352
+ const lines = content.split('\n');
353
+ for (let i = 0; i < lines.length; i++) {
354
+ const line = lines[i];
355
+ const options = {
356
+ fileContent: content,
357
+ lineNumber: i + 1,
358
+ expected: '',
359
+ actual: '',
360
+ framework: 'auto'
361
+ };
362
+ const parsed = this.parseJestAssertion(line, options) ||
363
+ this.parseChaiAssertion(line, options) ||
364
+ this.parseAssertAssertion(line, options);
365
+ if (parsed) {
366
+ assertions.push(parsed);
367
+ }
368
+ }
369
+ return assertions;
370
+ }
371
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Self-Healing Engine
3
+ *
4
+ * Main orchestration for self-healing functionality.
5
+ * Coordinates selector healing, assertion healing, and AI assistance.
6
+ */
7
+ import type { SelfHealingConfig, SelfHealingSession, TestFailureContext, AiHealingSuggestion } from './types.js';
8
+ /**
9
+ * Self-Healing Engine class
10
+ */
11
+ export declare class SelfHealingEngine {
12
+ private config;
13
+ private selectorHealer;
14
+ private assertionHealer;
15
+ private currentSession?;
16
+ constructor(config: SelfHealingConfig);
17
+ /**
18
+ * Start a new self-healing session
19
+ */
20
+ startSession(): string;
21
+ /**
22
+ * End current session and return results
23
+ */
24
+ endSession(): SelfHealingSession | null;
25
+ /**
26
+ * Attempt to heal a test failure
27
+ */
28
+ healFailure(context: TestFailureContext): Promise<SelfHealingResult>;
29
+ /**
30
+ * Heal a UI test failure (selector issues)
31
+ */
32
+ private healUiFailure;
33
+ /**
34
+ * Heal an API test failure
35
+ */
36
+ private healApiFailure;
37
+ /**
38
+ * Heal a generic test failure
39
+ */
40
+ private healGenericFailure;
41
+ /**
42
+ * Try AI-assisted healing
43
+ */
44
+ private tryAiHealing;
45
+ /**
46
+ * Build AI prompt from failure context
47
+ */
48
+ private buildAiPrompt;
49
+ /**
50
+ * Extract code from AI response
51
+ */
52
+ private extractCodeFromAiResponse;
53
+ /**
54
+ * Extract explanation from AI response
55
+ */
56
+ private extractExplanationFromAiResponse;
57
+ /**
58
+ * Analyze API failure
59
+ */
60
+ private analyzeApiFailure;
61
+ /**
62
+ * Detect API change type from context
63
+ */
64
+ private detectApiChangeType;
65
+ /**
66
+ * Extract selector from error message
67
+ */
68
+ private extractSelector;
69
+ /**
70
+ * Extract expected text from error message
71
+ */
72
+ private extractExpectedText;
73
+ /**
74
+ * Infer selector error type from message
75
+ */
76
+ private inferSelectorErrorType;
77
+ /**
78
+ * Extract line number from stack trace
79
+ */
80
+ private extractLineNumber;
81
+ /**
82
+ * Format selector heal result
83
+ */
84
+ private formatSelectorHeal;
85
+ /**
86
+ * Calculate session summary
87
+ */
88
+ private calculateSummary;
89
+ /**
90
+ * Generate unique session ID
91
+ */
92
+ private generateSessionId;
93
+ /**
94
+ * Get current session
95
+ */
96
+ getSession(): SelfHealingSession | undefined;
97
+ /**
98
+ * Update configuration
99
+ */
100
+ updateConfig(updates: Partial<SelfHealingConfig>): void;
101
+ /**
102
+ * Check if self-healing is enabled
103
+ */
104
+ isEnabled(): boolean;
105
+ /**
106
+ * Get confidence threshold
107
+ */
108
+ getConfidenceThreshold(): number;
109
+ }
110
+ /**
111
+ * Self-healing result
112
+ */
113
+ export interface SelfHealingResult {
114
+ success: boolean;
115
+ healed: boolean;
116
+ suggestion: AiHealingSuggestion | null;
117
+ reason: string;
118
+ }
119
+ /**
120
+ * Create a self-healing engine with default config
121
+ */
122
+ export declare function createSelfHealingEngine(config?: Partial<SelfHealingConfig>): SelfHealingEngine;