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,28 @@
1
+ /**
2
+ * Error Analyzer
3
+ *
4
+ * Analyzes test errors to extract patterns and classify problems.
5
+ */
6
+ import type { TestError, ErrorType } from '../types.js';
7
+ export interface ParsedError {
8
+ type: ErrorType;
9
+ message: string;
10
+ details: Record<string, unknown>;
11
+ fixable: boolean;
12
+ }
13
+ /**
14
+ * Analyze a test error message and classify it
15
+ */
16
+ export declare function analyzeTestError(testFile: string, testName: string, errorMessage: string, stack?: string): TestError;
17
+ /**
18
+ * Classify multiple test errors
19
+ */
20
+ export declare function classifyErrors(errors: string[]): Map<ErrorType, number>;
21
+ /**
22
+ * Check if error is auto-fixable
23
+ */
24
+ export declare function isAutoFixable(error: TestError): boolean;
25
+ /**
26
+ * Get fix suggestions for an error type
27
+ */
28
+ export declare function getCommonFixes(error: TestError): string[];
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Error Analyzer
3
+ *
4
+ * Analyzes test errors to extract patterns and classify problems.
5
+ */
6
+ /**
7
+ * Analyze a test error message and classify it
8
+ */
9
+ export function analyzeTestError(testFile, testName, errorMessage, stack) {
10
+ const parsed = parseErrorMessage(errorMessage, stack);
11
+ return {
12
+ testFile,
13
+ testName,
14
+ line: extractErrorLine(stack),
15
+ type: parsed.type,
16
+ message: parsed.message,
17
+ stack,
18
+ context: extractContext(parsed),
19
+ code: extractErrorCode(parsed)
20
+ };
21
+ }
22
+ /**
23
+ * Parse error message to extract type and details
24
+ */
25
+ function parseErrorMessage(message, stack) {
26
+ const lower = message.toLowerCase();
27
+ // AssertionError
28
+ if (lower.includes('expected') || lower.includes('assertion')) {
29
+ return {
30
+ type: 'assertion_error',
31
+ message,
32
+ details: {
33
+ expected: extractExpected(message),
34
+ received: extractReceived(message),
35
+ },
36
+ fixable: true
37
+ };
38
+ }
39
+ // TimeoutError
40
+ if (lower.includes('timeout') || lower.includes('timed out')) {
41
+ return {
42
+ type: 'timeout_error',
43
+ message,
44
+ details: {},
45
+ fixable: true
46
+ };
47
+ }
48
+ // ReferenceError
49
+ if (lower.includes('is not defined') || lower.includes('reference error')) {
50
+ return {
51
+ type: 'reference_error',
52
+ message,
53
+ details: {
54
+ missingVar: extractMissingVariable(message)
55
+ },
56
+ fixable: true
57
+ };
58
+ }
59
+ // TypeError
60
+ if (lower.includes('is not a') || lower.includes('is not function') || lower.includes('type error')) {
61
+ return {
62
+ type: 'type_error',
63
+ message,
64
+ details: {},
65
+ fixable: true
66
+ };
67
+ }
68
+ // Import error
69
+ if (lower.includes("cannot find module") || lower.includes('unexpected token')) {
70
+ return {
71
+ type: 'import_error',
72
+ message,
73
+ details: {
74
+ missingModule: extractMissingModule(message)
75
+ },
76
+ fixable: true
77
+ };
78
+ }
79
+ // Async error
80
+ if (lower.includes('async') || lower.includes('promise')) {
81
+ return {
82
+ type: 'async_error',
83
+ message,
84
+ details: {},
85
+ fixable: true
86
+ };
87
+ }
88
+ return {
89
+ type: 'unknown',
90
+ message,
91
+ details: {},
92
+ fixable: false
93
+ };
94
+ }
95
+ /**
96
+ * Extract line number from stack trace
97
+ */
98
+ function extractErrorLine(stack) {
99
+ if (!stack)
100
+ return 0;
101
+ const lines = stack.split('\n');
102
+ for (const line of lines) {
103
+ const match = line.match(/:(\d+):(\d+)/);
104
+ if (match) {
105
+ return parseInt(match[1], 10);
106
+ }
107
+ }
108
+ return 0;
109
+ }
110
+ /**
111
+ * Extract expected value from error message
112
+ */
113
+ function extractExpected(message) {
114
+ const patterns = [
115
+ /expected\s+["']([^"']+)["']/i,
116
+ /to be\s+["']?([^"')\s]+)["']?/i,
117
+ /expected:\s*(.+?)(?:,|but)/i
118
+ ];
119
+ for (const pattern of patterns) {
120
+ const match = message.match(pattern);
121
+ if (match)
122
+ return match[1].trim();
123
+ }
124
+ return '';
125
+ }
126
+ /**
127
+ * Extract received value from error message
128
+ */
129
+ function extractReceived(message) {
130
+ const patterns = [
131
+ /received\s+["']([^"']+)["']/i,
132
+ /but got\s+["']?([^"')\s]+)["']?/i,
133
+ /received:\s*(.+?)(?:,|\)|$)/i
134
+ ];
135
+ for (const pattern of patterns) {
136
+ const match = message.match(pattern);
137
+ if (match)
138
+ return match[1].trim();
139
+ }
140
+ return '';
141
+ }
142
+ /**
143
+ * Extract missing variable from reference error
144
+ */
145
+ function extractMissingVariable(message) {
146
+ const match = message.match(/(\w+)\s+is not defined/i);
147
+ if (match)
148
+ return match[1];
149
+ const refMatch = message.match(/ReferenceError:\s*(\w+)/i);
150
+ if (refMatch)
151
+ return refMatch[1];
152
+ return '';
153
+ }
154
+ /**
155
+ * Extract missing module from import error
156
+ */
157
+ function extractMissingModule(message) {
158
+ const match = message.match(/Cannot find module ['"]([^'"]+)['"]/i);
159
+ if (match)
160
+ return match[1];
161
+ const modMatch = message.match(/Cannot find module ['"](.+)['"]/);
162
+ if (modMatch)
163
+ return modMatch[1];
164
+ return '';
165
+ }
166
+ /**
167
+ * Extract context from parsed error
168
+ */
169
+ function extractContext(parsed) {
170
+ const contexts = {
171
+ assertion_error: 'Assertion failed - check expected vs actual values',
172
+ timeout_error: 'Test took too long - increase timeout or fix performance',
173
+ reference_error: 'Undefined variable - check imports and spelling',
174
+ type_error: 'Type mismatch - check data types and conversions',
175
+ import_error: 'Module not found - check import path and dependencies',
176
+ async_error: 'Async issue - check promises and async/await usage',
177
+ mock_error: 'Mock not configured - check test setup and mocks',
178
+ unknown: 'Unknown error type'
179
+ };
180
+ return contexts[parsed.type] || contexts.unknown;
181
+ }
182
+ /**
183
+ * Extract error code if present
184
+ */
185
+ function extractErrorCode(parsed) {
186
+ return parsed.type.toUpperCase().replace(/_/g, '-');
187
+ }
188
+ /**
189
+ * Classify multiple test errors
190
+ */
191
+ export function classifyErrors(errors) {
192
+ const counts = new Map();
193
+ for (const error of errors) {
194
+ const parsed = parseErrorMessage(error);
195
+ counts.set(parsed.type, (counts.get(parsed.type) || 0) + 1);
196
+ }
197
+ return counts;
198
+ }
199
+ /**
200
+ * Check if error is auto-fixable
201
+ */
202
+ export function isAutoFixable(error) {
203
+ // Most assertion and reference errors are auto-fixable
204
+ if (error.type === 'assertion_error' || error.type === 'reference_error') {
205
+ return true;
206
+ }
207
+ // Import errors and type errors are often fixable
208
+ if (error.type === 'import_error' || error.type === 'type_error') {
209
+ return true;
210
+ }
211
+ // Timeouts can sometimes be fixed by increasing timeout
212
+ if (error.type === 'timeout_error') {
213
+ return true;
214
+ }
215
+ return false;
216
+ }
217
+ /**
218
+ * Get fix suggestions for an error type
219
+ */
220
+ export function getCommonFixes(error) {
221
+ const fixes = {
222
+ assertion_error: [
223
+ 'Update expected value to match actual',
224
+ 'Add/modify mock to return expected value',
225
+ 'Fix test data setup'
226
+ ],
227
+ timeout_error: [
228
+ 'Increase test timeout',
229
+ 'Optimize test execution',
230
+ 'Remove unnecessary waits'
231
+ ],
232
+ reference_error: [
233
+ 'Import missing module/variable',
234
+ 'Fix typo in variable name',
235
+ 'Define missing variable'
236
+ ],
237
+ type_error: [
238
+ 'Add type conversion',
239
+ 'Fix data type mismatch',
240
+ 'Check API response structure'
241
+ ],
242
+ import_error: [
243
+ 'Install missing dependency',
244
+ 'Fix import path',
245
+ 'Add module to dependencies'
246
+ ],
247
+ async_error: [
248
+ 'Add await to async calls',
249
+ 'Return promise from async function',
250
+ 'Fix promise chain'
251
+ ],
252
+ mock_error: [
253
+ 'Configure mock properly',
254
+ 'Add mock setup in test',
255
+ 'Reset mocks between tests'
256
+ ],
257
+ unknown: [
258
+ 'Review test code',
259
+ 'Check test setup',
260
+ 'Verify test environment'
261
+ ]
262
+ };
263
+ return fixes[error.type] || fixes.unknown;
264
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Flakiness Integration for Smart Retry
3
+ *
4
+ * Integrates Smart Retry with the Flakiness Detection Engine
5
+ * to make intelligent retry decisions based on historical data.
6
+ */
7
+ import type { FlakinessResult, TestResult as FlakinessTestResult } from '../flakiness/index.js';
8
+ import type { RetryConfig, RetryRecommendation } from './types.js';
9
+ /**
10
+ * Enhanced retry config with flakiness awareness
11
+ */
12
+ export interface FlakinessAwareRetryConfig extends RetryConfig {
13
+ /** Use flakiness score to determine retry strategy */
14
+ useFlakinessScore?: boolean;
15
+ /** Minimum historical runs before using flakiness data */
16
+ minHistoricalRuns?: number;
17
+ /** Boost retry attempts for known flaky tests */
18
+ boostRetriesForFlaky?: boolean;
19
+ /** Reduce retries for known stable tests */
20
+ reduceRetriesForStable?: boolean;
21
+ }
22
+ /**
23
+ * Flakiness-aware retry engine
24
+ */
25
+ export declare class FlakinessAwareRetryEngine {
26
+ private flakinessHistory;
27
+ private testHistory;
28
+ /**
29
+ * Load flakiness data
30
+ */
31
+ loadFlakinessData(results: FlakinessResult[]): void;
32
+ /**
33
+ * Add test result to history
34
+ */
35
+ addTestResult(testId: string, result: FlakinessTestResult): void;
36
+ /**
37
+ * Get retry config for a specific test based on flakiness
38
+ */
39
+ getRetryConfigForTest(testId: string, baseConfig: FlakinessAwareRetryConfig): RetryConfig;
40
+ /**
41
+ * Get comprehensive retry recommendation
42
+ */
43
+ getRetryRecommendation(testId: string): RetryRecommendation;
44
+ /**
45
+ * Check if test should be skipped (too flaky)
46
+ */
47
+ shouldSkipTest(testId: string): boolean;
48
+ /**
49
+ * Get flakiness history
50
+ */
51
+ getFlakinessHistory(): Map<string, FlakinessResult>;
52
+ /**
53
+ * Clear all history
54
+ */
55
+ clearHistory(): void;
56
+ }
57
+ /**
58
+ * Create a flakiness-aware retry engine
59
+ */
60
+ export declare function createFlakinessAwareRetryEngine(): FlakinessAwareRetryEngine;
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Flakiness Integration for Smart Retry
3
+ *
4
+ * Integrates Smart Retry with the Flakiness Detection Engine
5
+ * to make intelligent retry decisions based on historical data.
6
+ */
7
+ import { RetryStrategy } from './types.js';
8
+ /**
9
+ * Flakiness-aware retry engine
10
+ */
11
+ export class FlakinessAwareRetryEngine {
12
+ flakinessHistory = new Map();
13
+ testHistory = new Map();
14
+ /**
15
+ * Load flakiness data
16
+ */
17
+ loadFlakinessData(results) {
18
+ for (const result of results) {
19
+ this.flakinessHistory.set(result.testId, result);
20
+ }
21
+ }
22
+ /**
23
+ * Add test result to history
24
+ */
25
+ addTestResult(testId, result) {
26
+ if (!this.testHistory.has(testId)) {
27
+ this.testHistory.set(testId, []);
28
+ }
29
+ this.testHistory.get(testId).push(result);
30
+ }
31
+ /**
32
+ * Get retry config for a specific test based on flakiness
33
+ */
34
+ getRetryConfigForTest(testId, baseConfig) {
35
+ const flakiness = this.flakinessHistory.get(testId);
36
+ const recentResults = this.testHistory.get(testId);
37
+ // If no flakiness data, return base config
38
+ const minRuns = baseConfig.minHistoricalRuns ?? 0;
39
+ if (!flakiness || !recentResults || recentResults.length < minRuns) {
40
+ return baseConfig;
41
+ }
42
+ const config = { ...baseConfig };
43
+ // Adjust based on flakiness score
44
+ if (baseConfig.useFlakinessScore) {
45
+ const score = flakiness.score;
46
+ if (score >= 90) {
47
+ // Legendary/Solid - reduce retries
48
+ if (baseConfig.reduceRetriesForStable) {
49
+ config.maxRetries = Math.max(0, baseConfig.maxRetries - 1);
50
+ config.strategy = RetryStrategy.FIXED;
51
+ }
52
+ }
53
+ else if (score >= 75) {
54
+ // Good - keep base config
55
+ config.strategy = RetryStrategy.FIXED;
56
+ }
57
+ else if (score >= 50) {
58
+ // Shaky - increase retries slightly
59
+ if (baseConfig.boostRetriesForFlaky) {
60
+ config.maxRetries = baseConfig.maxRetries + 1;
61
+ config.strategy = RetryStrategy.ADAPTIVE;
62
+ }
63
+ }
64
+ else {
65
+ // Unstable - aggressive retry
66
+ if (baseConfig.boostRetriesForFlaky) {
67
+ config.maxRetries = baseConfig.maxRetries + 2;
68
+ config.strategy = RetryStrategy.INTELLIGENT;
69
+ }
70
+ }
71
+ }
72
+ // Adjust based on pattern type
73
+ if (flakiness.patternType) {
74
+ switch (flakiness.patternType) {
75
+ case 'timing':
76
+ config.initialDelayMs = Math.max(config.initialDelayMs, 2000);
77
+ config.retryOnTimeout = true;
78
+ break;
79
+ case 'external_dependency':
80
+ config.initialDelayMs = Math.max(config.initialDelayMs, 3000);
81
+ config.strategy = RetryStrategy.EXPONENTIAL;
82
+ break;
83
+ case 'race_condition':
84
+ config.strategy = RetryStrategy.EXPONENTIAL;
85
+ config.jitterFactor = Math.max(config.jitterFactor, 0.2);
86
+ break;
87
+ case 'selector_issue':
88
+ config.strategy = RetryStrategy.FIXED;
89
+ config.maxRetries = Math.min(config.maxRetries, 3);
90
+ break;
91
+ }
92
+ }
93
+ // Adjust based on recent streak
94
+ if (flakiness.currentStreak && flakiness.currentStreak > 3) {
95
+ if (flakiness.streakType === 'fail') {
96
+ // Long fail streak - boost retries
97
+ config.maxRetries = config.maxRetries + 1;
98
+ }
99
+ else {
100
+ // Long pass streak - reduce retries
101
+ config.maxRetries = Math.max(1, config.maxRetries - 1);
102
+ }
103
+ }
104
+ return config;
105
+ }
106
+ /**
107
+ * Get comprehensive retry recommendation
108
+ */
109
+ getRetryRecommendation(testId) {
110
+ const flakiness = this.flakinessHistory.get(testId);
111
+ const recentResults = this.testHistory.get(testId);
112
+ if (!flakiness || !recentResults || recentResults.length < 3) {
113
+ return {
114
+ shouldRetry: true,
115
+ strategy: RetryStrategy.ADAPTIVE,
116
+ maxRetries: 3,
117
+ initialDelayMs: 1000,
118
+ confidence: 0.5,
119
+ reason: 'Insufficient historical data, using default adaptive retry'
120
+ };
121
+ }
122
+ // Analyze recent failures
123
+ const recentFailures = recentResults.slice(-10).filter(r => !r.success);
124
+ const failureRate = recentFailures.length / Math.min(recentResults.length, 10);
125
+ // Build recommendation
126
+ let strategy;
127
+ let maxRetries;
128
+ let initialDelayMs;
129
+ let confidence;
130
+ const reasons = [];
131
+ // Base recommendation on flakiness score
132
+ if (flakiness.score >= 90) {
133
+ strategy = RetryStrategy.NONE;
134
+ maxRetries = 0;
135
+ initialDelayMs = 0;
136
+ confidence = 0.9;
137
+ reasons.push('Test is highly reliable');
138
+ }
139
+ else if (flakiness.score >= 75) {
140
+ strategy = RetryStrategy.FIXED;
141
+ maxRetries = 2;
142
+ initialDelayMs = 1000;
143
+ confidence = 0.75;
144
+ reasons.push('Test is occasionally flaky');
145
+ }
146
+ else if (flakiness.score >= 50) {
147
+ strategy = RetryStrategy.ADAPTIVE;
148
+ maxRetries = 3;
149
+ initialDelayMs = 1000;
150
+ confidence = 0.85;
151
+ reasons.push('Test is often flaky');
152
+ }
153
+ else {
154
+ strategy = RetryStrategy.INTELLIGENT;
155
+ maxRetries = 5;
156
+ initialDelayMs = 2000;
157
+ confidence = 0.9;
158
+ reasons.push('Test is very flaky, aggressive retry recommended');
159
+ }
160
+ // Adjust based on pattern
161
+ if (flakiness.patternType) {
162
+ reasons.push(`Pattern: ${flakiness.patternType}`);
163
+ switch (flakiness.patternType) {
164
+ case 'timing':
165
+ initialDelayMs = Math.max(initialDelayMs, 2000);
166
+ strategy = flakiness.score < 75 ? RetryStrategy.EXPONENTIAL : strategy;
167
+ break;
168
+ case 'external_dependency':
169
+ initialDelayMs = Math.max(initialDelayMs, 3000);
170
+ break;
171
+ case 'selector_issue':
172
+ strategy = RetryStrategy.FIXED;
173
+ maxRetries = Math.min(maxRetries, 3);
174
+ break;
175
+ }
176
+ }
177
+ // Adjust based on recent failure rate
178
+ if (failureRate > 0.5) {
179
+ maxRetries = Math.min(maxRetries + 1, 5);
180
+ reasons.push(`High recent failure rate (${Math.round(failureRate * 100)}%)`);
181
+ }
182
+ else if (failureRate < 0.1 && flakiness.score >= 75) {
183
+ // For highly reliable tests (score >= 90), keep maxRetries at 0
184
+ if (flakiness.score < 90) {
185
+ maxRetries = Math.max(maxRetries - 1, 1);
186
+ }
187
+ reasons.push('Low recent failure rate');
188
+ }
189
+ return {
190
+ shouldRetry: maxRetries > 0,
191
+ strategy,
192
+ maxRetries,
193
+ initialDelayMs,
194
+ confidence,
195
+ reason: reasons.join('; '),
196
+ pattern: flakiness.patternType
197
+ };
198
+ }
199
+ /**
200
+ * Check if test should be skipped (too flaky)
201
+ */
202
+ shouldSkipTest(testId) {
203
+ const flakiness = this.flakinessHistory.get(testId);
204
+ if (!flakiness)
205
+ return false;
206
+ // Skip if score is very low and has many runs
207
+ return flakiness.score < 30 && flakiness.totalRuns >= 10;
208
+ }
209
+ /**
210
+ * Get flakiness history
211
+ */
212
+ getFlakinessHistory() {
213
+ return new Map(this.flakinessHistory);
214
+ }
215
+ /**
216
+ * Clear all history
217
+ */
218
+ clearHistory() {
219
+ this.flakinessHistory.clear();
220
+ this.testHistory.clear();
221
+ }
222
+ }
223
+ /**
224
+ * Create a flakiness-aware retry engine
225
+ */
226
+ export function createFlakinessAwareRetryEngine() {
227
+ return new FlakinessAwareRetryEngine();
228
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * QA360 Smart Retry Module (F8)
3
+ *
4
+ * Intelligent retry strategies based on flakiness scoring and pattern detection.
5
+ * Completes the flakiness system: Detection → Scoring → Quarantine → Smart Retry
6
+ *
7
+ * @module retry
8
+ */
9
+ export { RetryStrategy, DEFAULT_RETRY_CONFIG } from './types.js';
10
+ export type { RetryAttempt, RetryResult, RetryConfig, RetryRecommendation, RetryHistoryRecord, RetryStatistics } from './types.js';
11
+ export { SmartRetryEngine, createSmartRetryEngine, type TestExecutor } from './retry-engine.js';
12
+ export { FlakinessAwareRetryEngine, createFlakinessAwareRetryEngine, type FlakinessAwareRetryConfig } from './flakiness-integration.js';
13
+ export { RetryVault } from './vault.js';
14
+ export type { FlakinessResult, FlakinessCategory, TestResult as FlakinessTestResult } from '../flakiness/index.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * QA360 Smart Retry Module (F8)
3
+ *
4
+ * Intelligent retry strategies based on flakiness scoring and pattern detection.
5
+ * Completes the flakiness system: Detection → Scoring → Quarantine → Smart Retry
6
+ *
7
+ * @module retry
8
+ */
9
+ // Types
10
+ export { RetryStrategy, DEFAULT_RETRY_CONFIG } from './types.js';
11
+ // Core engine
12
+ export { SmartRetryEngine, createSmartRetryEngine } from './retry-engine.js';
13
+ // Flakiness integration
14
+ export { FlakinessAwareRetryEngine, createFlakinessAwareRetryEngine } from './flakiness-integration.js';
15
+ // Vault integration
16
+ export { RetryVault } from './vault.js';
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Smart Retry Engine
3
+ *
4
+ * Core retry logic with multiple strategies and adaptive behavior.
5
+ */
6
+ import type { RetryConfig, RetryResult, RetryRecommendation } from './types.js';
7
+ /**
8
+ * Test execution function type
9
+ */
10
+ export type TestExecutor<T = unknown> = () => Promise<T>;
11
+ /**
12
+ * Smart Retry Engine
13
+ */
14
+ export declare class SmartRetryEngine {
15
+ private config;
16
+ constructor(config?: Partial<RetryConfig>);
17
+ /**
18
+ * Execute a test with retry logic
19
+ */
20
+ executeWithRetry(testId: string, executor: TestExecutor, context?: {
21
+ testName?: string;
22
+ gate?: string;
23
+ flakinessScore?: number;
24
+ patternType?: string;
25
+ }): Promise<RetryResult>;
26
+ /**
27
+ * Get retry recommendation based on flakiness and pattern
28
+ */
29
+ getRetryRecommendation(params: {
30
+ flakinessScore?: number;
31
+ patternType?: string;
32
+ errorType?: string;
33
+ errorCount?: number;
34
+ recentAttempts?: number;
35
+ }): RetryRecommendation;
36
+ /**
37
+ * Calculate delay before retry attempt
38
+ */
39
+ private calculateDelay;
40
+ /**
41
+ * Get effective strategy based on context
42
+ */
43
+ private getEffectiveStrategy;
44
+ /**
45
+ * Calculate intelligent delay based on common patterns
46
+ */
47
+ private getIntelligentDelay;
48
+ /**
49
+ * Apply jitter to delay to avoid thundering herd
50
+ */
51
+ private applyJitter;
52
+ /**
53
+ * Check if error type is non-retriable
54
+ */
55
+ private isNonRetriableError;
56
+ /**
57
+ * Check if error is an assertion failure
58
+ */
59
+ private isAssertionError;
60
+ /**
61
+ * Check if error is a timeout
62
+ */
63
+ private isTimeoutError;
64
+ /**
65
+ * Delay for specified milliseconds
66
+ */
67
+ private delay;
68
+ /**
69
+ * Update retry configuration
70
+ */
71
+ updateConfig(config: Partial<RetryConfig>): void;
72
+ /**
73
+ * Get current configuration
74
+ */
75
+ getConfig(): RetryConfig;
76
+ }
77
+ /**
78
+ * Create a smart retry engine
79
+ */
80
+ export declare function createSmartRetryEngine(config?: Partial<RetryConfig>): SmartRetryEngine;