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.
- package/README.md +1 -1
- package/dist/commands/ai.d.ts +41 -0
- package/dist/commands/ai.js +499 -0
- package/dist/commands/ask.js +12 -12
- package/dist/commands/coverage.d.ts +8 -0
- package/dist/commands/coverage.js +252 -0
- package/dist/commands/explain.d.ts +27 -0
- package/dist/commands/explain.js +630 -0
- package/dist/commands/flakiness.d.ts +73 -0
- package/dist/commands/flakiness.js +435 -0
- package/dist/commands/generate.d.ts +66 -0
- package/dist/commands/generate.js +438 -0
- package/dist/commands/init.d.ts +56 -9
- package/dist/commands/init.js +217 -10
- package/dist/commands/monitor.d.ts +27 -0
- package/dist/commands/monitor.js +225 -0
- package/dist/commands/ollama.d.ts +40 -0
- package/dist/commands/ollama.js +301 -0
- package/dist/commands/pack.d.ts +37 -9
- package/dist/commands/pack.js +240 -141
- package/dist/commands/regression.d.ts +8 -0
- package/dist/commands/regression.js +340 -0
- package/dist/commands/repair.d.ts +26 -0
- package/dist/commands/repair.js +307 -0
- package/dist/commands/retry.d.ts +43 -0
- package/dist/commands/retry.js +275 -0
- package/dist/commands/run.d.ts +8 -3
- package/dist/commands/run.js +45 -31
- package/dist/commands/slo.d.ts +8 -0
- package/dist/commands/slo.js +327 -0
- package/dist/core/adapters/playwright-native-api.d.ts +183 -0
- package/dist/core/adapters/playwright-native-api.js +461 -0
- package/dist/core/adapters/playwright-ui.d.ts +7 -0
- package/dist/core/adapters/playwright-ui.js +29 -1
- package/dist/core/ai/anthropic-provider.d.ts +50 -0
- package/dist/core/ai/anthropic-provider.js +211 -0
- package/dist/core/ai/deepseek-provider.d.ts +81 -0
- package/dist/core/ai/deepseek-provider.js +254 -0
- package/dist/core/ai/index.d.ts +60 -0
- package/dist/core/ai/index.js +18 -0
- package/dist/core/ai/llm-client.d.ts +45 -0
- package/dist/core/ai/llm-client.js +7 -0
- package/dist/core/ai/mock-provider.d.ts +49 -0
- package/dist/core/ai/mock-provider.js +121 -0
- package/dist/core/ai/ollama-provider.d.ts +78 -0
- package/dist/core/ai/ollama-provider.js +192 -0
- package/dist/core/ai/openai-provider.d.ts +48 -0
- package/dist/core/ai/openai-provider.js +188 -0
- package/dist/core/ai/provider-factory.d.ts +160 -0
- package/dist/core/ai/provider-factory.js +269 -0
- package/dist/core/auth/api-key-provider.d.ts +16 -0
- package/dist/core/auth/api-key-provider.js +63 -0
- package/dist/core/auth/aws-iam-provider.d.ts +35 -0
- package/dist/core/auth/aws-iam-provider.js +177 -0
- package/dist/core/auth/azure-ad-provider.d.ts +15 -0
- package/dist/core/auth/azure-ad-provider.js +99 -0
- package/dist/core/auth/basic-auth-provider.d.ts +26 -0
- package/dist/core/auth/basic-auth-provider.js +111 -0
- package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
- package/dist/core/auth/gcp-adc-provider.js +126 -0
- package/dist/core/auth/index.d.ts +238 -0
- package/dist/core/auth/index.js +82 -0
- package/dist/core/auth/jwt-provider.d.ts +19 -0
- package/dist/core/auth/jwt-provider.js +160 -0
- package/dist/core/auth/manager.d.ts +84 -0
- package/dist/core/auth/manager.js +230 -0
- package/dist/core/auth/oauth2-provider.d.ts +17 -0
- package/dist/core/auth/oauth2-provider.js +114 -0
- package/dist/core/auth/totp-provider.d.ts +31 -0
- package/dist/core/auth/totp-provider.js +134 -0
- package/dist/core/auth/ui-login-provider.d.ts +26 -0
- package/dist/core/auth/ui-login-provider.js +198 -0
- package/dist/core/cache/index.d.ts +7 -0
- package/dist/core/cache/index.js +6 -0
- package/dist/core/cache/lru-cache.d.ts +203 -0
- package/dist/core/cache/lru-cache.js +397 -0
- package/dist/core/coverage/analyzer.d.ts +101 -0
- package/dist/core/coverage/analyzer.js +415 -0
- package/dist/core/coverage/collector.d.ts +74 -0
- package/dist/core/coverage/collector.js +459 -0
- package/dist/core/coverage/config.d.ts +37 -0
- package/dist/core/coverage/config.js +156 -0
- package/dist/core/coverage/index.d.ts +11 -0
- package/dist/core/coverage/index.js +15 -0
- package/dist/core/coverage/types.d.ts +267 -0
- package/dist/core/coverage/types.js +6 -0
- package/dist/core/coverage/vault.d.ts +95 -0
- package/dist/core/coverage/vault.js +405 -0
- package/dist/core/dashboard/assets.d.ts +6 -0
- package/dist/core/dashboard/assets.js +690 -0
- package/dist/core/dashboard/index.d.ts +6 -0
- package/dist/core/dashboard/index.js +5 -0
- package/dist/core/dashboard/server.d.ts +72 -0
- package/dist/core/dashboard/server.js +354 -0
- package/dist/core/dashboard/types.d.ts +70 -0
- package/dist/core/dashboard/types.js +5 -0
- package/dist/core/discoverer/index.d.ts +115 -0
- package/dist/core/discoverer/index.js +250 -0
- package/dist/core/flakiness/index.d.ts +228 -0
- package/dist/core/flakiness/index.js +384 -0
- package/dist/core/generation/code-formatter.d.ts +111 -0
- package/dist/core/generation/code-formatter.js +307 -0
- package/dist/core/generation/code-generator.d.ts +144 -0
- package/dist/core/generation/code-generator.js +293 -0
- package/dist/core/generation/generator.d.ts +40 -0
- package/dist/core/generation/generator.js +76 -0
- package/dist/core/generation/index.d.ts +30 -0
- package/dist/core/generation/index.js +28 -0
- package/dist/core/generation/pack-generator.d.ts +107 -0
- package/dist/core/generation/pack-generator.js +416 -0
- package/dist/core/generation/prompt-builder.d.ts +132 -0
- package/dist/core/generation/prompt-builder.js +672 -0
- package/dist/core/generation/source-analyzer.d.ts +213 -0
- package/dist/core/generation/source-analyzer.js +657 -0
- package/dist/core/generation/test-optimizer.d.ts +117 -0
- package/dist/core/generation/test-optimizer.js +328 -0
- package/dist/core/generation/types.d.ts +214 -0
- package/dist/core/generation/types.js +4 -0
- package/dist/core/index.d.ts +23 -1
- package/dist/core/index.js +39 -0
- package/dist/core/pack/validator.js +31 -1
- package/dist/core/pack-v2/index.d.ts +9 -0
- package/dist/core/pack-v2/index.js +8 -0
- package/dist/core/pack-v2/loader.d.ts +62 -0
- package/dist/core/pack-v2/loader.js +231 -0
- package/dist/core/pack-v2/migrator.d.ts +56 -0
- package/dist/core/pack-v2/migrator.js +455 -0
- package/dist/core/pack-v2/validator.d.ts +61 -0
- package/dist/core/pack-v2/validator.js +577 -0
- package/dist/core/regression/detector.d.ts +107 -0
- package/dist/core/regression/detector.js +497 -0
- package/dist/core/regression/index.d.ts +9 -0
- package/dist/core/regression/index.js +11 -0
- package/dist/core/regression/trend-analyzer.d.ts +102 -0
- package/dist/core/regression/trend-analyzer.js +345 -0
- package/dist/core/regression/types.d.ts +222 -0
- package/dist/core/regression/types.js +7 -0
- package/dist/core/regression/vault.d.ts +87 -0
- package/dist/core/regression/vault.js +289 -0
- package/dist/core/repair/engine/fixer.d.ts +24 -0
- package/dist/core/repair/engine/fixer.js +226 -0
- package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
- package/dist/core/repair/engine/suggestion-engine.js +187 -0
- package/dist/core/repair/index.d.ts +10 -0
- package/dist/core/repair/index.js +13 -0
- package/dist/core/repair/repairer.d.ts +90 -0
- package/dist/core/repair/repairer.js +284 -0
- package/dist/core/repair/types.d.ts +91 -0
- package/dist/core/repair/types.js +6 -0
- package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
- package/dist/core/repair/utils/error-analyzer.js +264 -0
- package/dist/core/retry/flakiness-integration.d.ts +60 -0
- package/dist/core/retry/flakiness-integration.js +228 -0
- package/dist/core/retry/index.d.ts +14 -0
- package/dist/core/retry/index.js +16 -0
- package/dist/core/retry/retry-engine.d.ts +80 -0
- package/dist/core/retry/retry-engine.js +296 -0
- package/dist/core/retry/types.d.ts +178 -0
- package/dist/core/retry/types.js +52 -0
- package/dist/core/retry/vault.d.ts +77 -0
- package/dist/core/retry/vault.js +304 -0
- package/dist/core/runner/e2e-helpers.d.ts +102 -0
- package/dist/core/runner/e2e-helpers.js +153 -0
- package/dist/core/runner/phase3-runner.d.ts +101 -2
- package/dist/core/runner/phase3-runner.js +559 -24
- package/dist/core/self-healing/assertion-healer.d.ts +97 -0
- package/dist/core/self-healing/assertion-healer.js +371 -0
- package/dist/core/self-healing/engine.d.ts +122 -0
- package/dist/core/self-healing/engine.js +538 -0
- package/dist/core/self-healing/index.d.ts +10 -0
- package/dist/core/self-healing/index.js +11 -0
- package/dist/core/self-healing/selector-healer.d.ts +103 -0
- package/dist/core/self-healing/selector-healer.js +372 -0
- package/dist/core/self-healing/types.d.ts +152 -0
- package/dist/core/self-healing/types.js +6 -0
- package/dist/core/slo/config.d.ts +107 -0
- package/dist/core/slo/config.js +360 -0
- package/dist/core/slo/index.d.ts +11 -0
- package/dist/core/slo/index.js +15 -0
- package/dist/core/slo/sli-calculator.d.ts +92 -0
- package/dist/core/slo/sli-calculator.js +364 -0
- package/dist/core/slo/slo-tracker.d.ts +148 -0
- package/dist/core/slo/slo-tracker.js +379 -0
- package/dist/core/slo/types.d.ts +281 -0
- package/dist/core/slo/types.js +7 -0
- package/dist/core/slo/vault.d.ts +102 -0
- package/dist/core/slo/vault.js +427 -0
- package/dist/core/tui/index.d.ts +7 -0
- package/dist/core/tui/index.js +6 -0
- package/dist/core/tui/monitor.d.ts +92 -0
- package/dist/core/tui/monitor.js +271 -0
- package/dist/core/tui/renderer.d.ts +33 -0
- package/dist/core/tui/renderer.js +218 -0
- package/dist/core/tui/types.d.ts +63 -0
- package/dist/core/tui/types.js +5 -0
- package/dist/core/types/pack-v2.d.ts +425 -0
- package/dist/core/types/pack-v2.js +8 -0
- package/dist/core/vault/index.d.ts +116 -0
- package/dist/core/vault/index.js +400 -5
- package/dist/core/watch/index.d.ts +7 -0
- package/dist/core/watch/index.js +6 -0
- package/dist/core/watch/watch-mode.d.ts +213 -0
- package/dist/core/watch/watch-mode.js +389 -0
- package/dist/index.js +68 -68
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +136 -0
- package/package.json +5 -1
- package/dist/core/adapters/playwright-api.d.ts +0 -82
- package/dist/core/adapters/playwright-api.js +0 -264
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Test Discoverer
|
|
3
|
+
*
|
|
4
|
+
* Automatically discovers and categorizes test files in a project.
|
|
5
|
+
* Supports Playwright, K6, Cypress, and other test frameworks.
|
|
6
|
+
*/
|
|
7
|
+
import { stat } from 'fs/promises';
|
|
8
|
+
import { relative } from 'path';
|
|
9
|
+
import { glob } from 'glob';
|
|
10
|
+
/**
|
|
11
|
+
* Test Discoverer
|
|
12
|
+
*
|
|
13
|
+
* Scans a project directory for test files and categorizes them
|
|
14
|
+
* by framework and type.
|
|
15
|
+
*/
|
|
16
|
+
export class TestDiscoverer {
|
|
17
|
+
rootDir;
|
|
18
|
+
defaultPatterns;
|
|
19
|
+
// Default test patterns
|
|
20
|
+
DEFAULT_PATTERNS = [
|
|
21
|
+
'tests/**/*',
|
|
22
|
+
'test/**/*',
|
|
23
|
+
'**/*.spec.ts',
|
|
24
|
+
'**/*.spec.js',
|
|
25
|
+
'**/*.test.ts',
|
|
26
|
+
'**/*.test.js',
|
|
27
|
+
'**/__tests__/**/*',
|
|
28
|
+
];
|
|
29
|
+
// Default exclusions
|
|
30
|
+
DEFAULT_EXCLUDES = [
|
|
31
|
+
'**/node_modules/**',
|
|
32
|
+
'**/dist/**',
|
|
33
|
+
'**/build/**',
|
|
34
|
+
'**/.next/**',
|
|
35
|
+
'**/.nuxt/**',
|
|
36
|
+
'**/coverage/**',
|
|
37
|
+
'**/*.d.ts',
|
|
38
|
+
];
|
|
39
|
+
constructor(options = {}) {
|
|
40
|
+
this.rootDir = options.rootDir || process.cwd();
|
|
41
|
+
this.defaultPatterns = options.patterns || this.DEFAULT_PATTERNS;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Discover all test files in the project
|
|
45
|
+
*/
|
|
46
|
+
async discover() {
|
|
47
|
+
const files = await this.findTestFiles();
|
|
48
|
+
const categorized = {
|
|
49
|
+
playwright: [],
|
|
50
|
+
k6: [],
|
|
51
|
+
cypress: [],
|
|
52
|
+
jest: [],
|
|
53
|
+
vitest: [],
|
|
54
|
+
other: [],
|
|
55
|
+
};
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
const category = this.categorizeFile(file);
|
|
58
|
+
categorized[category].push(file);
|
|
59
|
+
}
|
|
60
|
+
return categorized;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Find all test files using glob patterns
|
|
64
|
+
*/
|
|
65
|
+
async findTestFiles() {
|
|
66
|
+
const files = await glob(this.defaultPatterns, {
|
|
67
|
+
cwd: this.rootDir,
|
|
68
|
+
absolute: true,
|
|
69
|
+
ignore: this.DEFAULT_EXCLUDES,
|
|
70
|
+
});
|
|
71
|
+
const results = [];
|
|
72
|
+
for (const filePath of files) {
|
|
73
|
+
const statResult = await stat(filePath).catch(() => null);
|
|
74
|
+
if (!statResult?.isFile())
|
|
75
|
+
continue;
|
|
76
|
+
results.push({
|
|
77
|
+
path: filePath,
|
|
78
|
+
type: this.detectType(filePath),
|
|
79
|
+
framework: this.detectFramework(filePath),
|
|
80
|
+
relativePath: relative(this.rootDir, filePath),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Categorize a file into a test category
|
|
87
|
+
*/
|
|
88
|
+
categorizeFile(file) {
|
|
89
|
+
switch (file.framework) {
|
|
90
|
+
case 'playwright':
|
|
91
|
+
return 'playwright';
|
|
92
|
+
case 'k6':
|
|
93
|
+
return 'k6';
|
|
94
|
+
case 'cypress':
|
|
95
|
+
return 'cypress';
|
|
96
|
+
case 'jest':
|
|
97
|
+
return 'jest';
|
|
98
|
+
case 'vitest':
|
|
99
|
+
return 'vitest';
|
|
100
|
+
default:
|
|
101
|
+
return 'other';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Detect the test framework from file path and content
|
|
106
|
+
*/
|
|
107
|
+
detectFramework(filePath) {
|
|
108
|
+
const path = filePath.toLowerCase();
|
|
109
|
+
// Check by path patterns first
|
|
110
|
+
if (path.includes('playwright') || path.endsWith('.spec.ts') || path.endsWith('.spec.js')) {
|
|
111
|
+
return 'playwright';
|
|
112
|
+
}
|
|
113
|
+
if (path.includes('k6') || path.includes('perf') || path.includes('load')) {
|
|
114
|
+
return 'k6';
|
|
115
|
+
}
|
|
116
|
+
if (path.includes('cypress') || path.includes('.cy.')) {
|
|
117
|
+
return 'cypress';
|
|
118
|
+
}
|
|
119
|
+
if (path.includes('vitest')) {
|
|
120
|
+
return 'vitest';
|
|
121
|
+
}
|
|
122
|
+
if (path.includes('__tests__') || path.includes('.test.')) {
|
|
123
|
+
return 'jest';
|
|
124
|
+
}
|
|
125
|
+
return 'unknown';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Detect the type of test (api, ui, perf, etc.)
|
|
129
|
+
*/
|
|
130
|
+
detectType(filePath) {
|
|
131
|
+
const path = filePath.toLowerCase();
|
|
132
|
+
const name = filePath.toLowerCase();
|
|
133
|
+
// Detect by directory/file name
|
|
134
|
+
if (name.includes('api') || name.includes('endpoint')) {
|
|
135
|
+
return 'api';
|
|
136
|
+
}
|
|
137
|
+
if (name.includes('ui') || name.includes('e2e') || name.includes('ui-e2e')) {
|
|
138
|
+
return 'e2e';
|
|
139
|
+
}
|
|
140
|
+
if (name.includes('perf') || name.includes('performance') || name.includes('load')) {
|
|
141
|
+
return 'perf';
|
|
142
|
+
}
|
|
143
|
+
if (name.includes('security') || name.includes('sast')) {
|
|
144
|
+
return 'sast';
|
|
145
|
+
}
|
|
146
|
+
if (name.includes('a11y') || name.includes('accessibility')) {
|
|
147
|
+
return 'a11y';
|
|
148
|
+
}
|
|
149
|
+
if (name.includes('unit')) {
|
|
150
|
+
return 'unit';
|
|
151
|
+
}
|
|
152
|
+
if (name.includes('integration')) {
|
|
153
|
+
return 'integration';
|
|
154
|
+
}
|
|
155
|
+
// Default for framework-specific conventions
|
|
156
|
+
const framework = this.detectFramework(filePath);
|
|
157
|
+
switch (framework) {
|
|
158
|
+
case 'k6':
|
|
159
|
+
return 'perf';
|
|
160
|
+
case 'cypress':
|
|
161
|
+
return 'e2e';
|
|
162
|
+
default:
|
|
163
|
+
return 'unit';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Route a test file to the appropriate QA360 adapter
|
|
168
|
+
*/
|
|
169
|
+
routeToAdapter(test) {
|
|
170
|
+
switch (test.framework) {
|
|
171
|
+
case 'playwright':
|
|
172
|
+
if (test.type === 'api') {
|
|
173
|
+
return { adapter: 'playwright-api' };
|
|
174
|
+
}
|
|
175
|
+
return { adapter: 'playwright-ui' };
|
|
176
|
+
case 'k6':
|
|
177
|
+
return { adapter: 'k6-perf', config: { testType: test.type } };
|
|
178
|
+
case 'cypress':
|
|
179
|
+
return { adapter: 'cypress-ui' };
|
|
180
|
+
default:
|
|
181
|
+
return { adapter: 'generic', config: { testPath: test.path } };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Discover tests for a specific gate
|
|
186
|
+
*/
|
|
187
|
+
async discoverForGate(gate) {
|
|
188
|
+
const allTests = await this.discover();
|
|
189
|
+
switch (gate) {
|
|
190
|
+
case 'api_smoke':
|
|
191
|
+
return [
|
|
192
|
+
...allTests.playwright.filter(t => t.type === 'api'),
|
|
193
|
+
...allTests.jest.filter(t => t.type === 'api'),
|
|
194
|
+
...allTests.vitest.filter(t => t.type === 'api'),
|
|
195
|
+
];
|
|
196
|
+
case 'ui':
|
|
197
|
+
case 'e2e':
|
|
198
|
+
return [
|
|
199
|
+
...allTests.playwright.filter(t => t.type === 'e2e' || t.type === 'ui'),
|
|
200
|
+
...allTests.cypress.filter(t => t.type === 'e2e'),
|
|
201
|
+
];
|
|
202
|
+
case 'perf':
|
|
203
|
+
return allTests.k6;
|
|
204
|
+
case 'security':
|
|
205
|
+
case 'sast':
|
|
206
|
+
return [
|
|
207
|
+
...allTests.playwright.filter(t => t.path.includes('security')),
|
|
208
|
+
...allTests.other.filter(t => t.type === 'sast'),
|
|
209
|
+
];
|
|
210
|
+
default:
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get summary statistics of discovered tests
|
|
216
|
+
*/
|
|
217
|
+
async getSummary() {
|
|
218
|
+
const tests = await this.discover();
|
|
219
|
+
return {
|
|
220
|
+
total: this.countAll(tests),
|
|
221
|
+
byFramework: {
|
|
222
|
+
playwright: tests.playwright.length,
|
|
223
|
+
k6: tests.k6.length,
|
|
224
|
+
cypress: tests.cypress.length,
|
|
225
|
+
jest: tests.jest.length,
|
|
226
|
+
vitest: tests.vitest.length,
|
|
227
|
+
other: tests.other.length,
|
|
228
|
+
},
|
|
229
|
+
byType: this.countByType(tests),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
countAll(tests) {
|
|
233
|
+
return Object.values(tests).reduce((sum, arr) => sum + arr.length, 0);
|
|
234
|
+
}
|
|
235
|
+
countByType(tests) {
|
|
236
|
+
const counts = {};
|
|
237
|
+
for (const category of Object.values(tests)) {
|
|
238
|
+
for (const test of category) {
|
|
239
|
+
counts[test.type] = (counts[test.type] || 0) + 1;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return counts;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Create a test discoverer
|
|
247
|
+
*/
|
|
248
|
+
export function createTestDiscoverer(options) {
|
|
249
|
+
return new TestDiscoverer(options);
|
|
250
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Flakiness Detection Engine
|
|
3
|
+
*
|
|
4
|
+
* Detects and scores test flakiness using consecutive runs and pattern analysis.
|
|
5
|
+
* This is the core differentiator of QA360 - measuring test reliability.
|
|
6
|
+
*
|
|
7
|
+
* Scoring Categories:
|
|
8
|
+
* - Legendary (100): Never flaky - 100% reliable
|
|
9
|
+
* - Solid (90-99): Rarely flaky
|
|
10
|
+
* - Good (75-89): Occasionally flaky
|
|
11
|
+
* - Shaky (50-74): Often flaky - attention needed
|
|
12
|
+
* - Unstable (0-49): Very flaky - quarantine recommended
|
|
13
|
+
*
|
|
14
|
+
* @module flakiness
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Flakiness score category
|
|
18
|
+
*/
|
|
19
|
+
export declare enum FlakinessCategory {
|
|
20
|
+
LEGENDARY = "legendary",// 100
|
|
21
|
+
SOLID = "solid",// 90-99
|
|
22
|
+
GOOD = "good",// 75-89
|
|
23
|
+
SHAKY = "shaky",// 50-74
|
|
24
|
+
UNSTABLE = "unstable"
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Flakiness category metadata
|
|
28
|
+
*/
|
|
29
|
+
export declare const FLAKINESS_CATEGORIES: Record<FlakinessCategory, {
|
|
30
|
+
min: number;
|
|
31
|
+
max: number;
|
|
32
|
+
label: string;
|
|
33
|
+
emoji: string;
|
|
34
|
+
color: string;
|
|
35
|
+
description: string;
|
|
36
|
+
action: string;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Test result from a single run
|
|
40
|
+
*/
|
|
41
|
+
export interface TestResult {
|
|
42
|
+
/** Test identifier (unique per test) */
|
|
43
|
+
testId: string;
|
|
44
|
+
/** Test name/title */
|
|
45
|
+
testName: string;
|
|
46
|
+
/** File path */
|
|
47
|
+
filePath: string;
|
|
48
|
+
/** Gate name */
|
|
49
|
+
gate: string;
|
|
50
|
+
/** Whether the test passed */
|
|
51
|
+
success: boolean;
|
|
52
|
+
/** Duration in milliseconds */
|
|
53
|
+
durationMs: number;
|
|
54
|
+
/** Error type if failed */
|
|
55
|
+
errorType?: string;
|
|
56
|
+
/** Error message if failed */
|
|
57
|
+
errorMessage?: string;
|
|
58
|
+
/** Timestamp of run */
|
|
59
|
+
timestamp: number;
|
|
60
|
+
/** Environment (local, ci, staging) */
|
|
61
|
+
environment: string;
|
|
62
|
+
/** Git branch */
|
|
63
|
+
branch?: string;
|
|
64
|
+
/** Commit hash */
|
|
65
|
+
commitHash?: string;
|
|
66
|
+
/** CI run ID */
|
|
67
|
+
ciRunId?: string;
|
|
68
|
+
/** Tags (team, repo, etc.) */
|
|
69
|
+
tags?: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Flakiness detection result for a single test
|
|
73
|
+
*/
|
|
74
|
+
export interface FlakinessResult {
|
|
75
|
+
/** Test identifier */
|
|
76
|
+
testId: string;
|
|
77
|
+
/** Test name */
|
|
78
|
+
testName: string;
|
|
79
|
+
/** File path */
|
|
80
|
+
filePath: string;
|
|
81
|
+
/** Gate name */
|
|
82
|
+
gate: string;
|
|
83
|
+
/** Flakiness score (0-100) */
|
|
84
|
+
score: number;
|
|
85
|
+
/** Flakiness category */
|
|
86
|
+
category: FlakinessCategory;
|
|
87
|
+
/** Total number of runs analyzed */
|
|
88
|
+
totalRuns: number;
|
|
89
|
+
/** Number of successful runs */
|
|
90
|
+
successfulRuns: number;
|
|
91
|
+
/** Average duration in ms */
|
|
92
|
+
avgDurationMs: number;
|
|
93
|
+
/** Detected pattern type (if any) */
|
|
94
|
+
patternType?: string;
|
|
95
|
+
/** Suggested fix */
|
|
96
|
+
suggestedFix?: string;
|
|
97
|
+
/** Confidence in pattern detection (0-1) */
|
|
98
|
+
confidence?: number;
|
|
99
|
+
/** First seen timestamp */
|
|
100
|
+
firstSeen?: number;
|
|
101
|
+
/** Last seen timestamp */
|
|
102
|
+
lastSeen?: number;
|
|
103
|
+
/** Current streak (consecutive passes or failures) */
|
|
104
|
+
currentStreak?: number;
|
|
105
|
+
/** Streak type */
|
|
106
|
+
streakType?: 'pass' | 'fail';
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Flakiness detection options
|
|
110
|
+
*/
|
|
111
|
+
export interface FlakinessDetectionOptions {
|
|
112
|
+
/** Minimum runs before calculating score */
|
|
113
|
+
minRuns?: number;
|
|
114
|
+
/** Number of consecutive runs for detection */
|
|
115
|
+
consecutiveRuns?: number;
|
|
116
|
+
/** Time window in days (only consider runs within this window) */
|
|
117
|
+
timeWindowDays?: number;
|
|
118
|
+
/** Enable pattern detection */
|
|
119
|
+
enablePatternDetection?: boolean;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Default flakiness detection options
|
|
123
|
+
*/
|
|
124
|
+
export declare const DEFAULT_FLAKINESS_OPTIONS: Required<FlakinessDetectionOptions>;
|
|
125
|
+
/**
|
|
126
|
+
* Flakiness pattern types
|
|
127
|
+
*/
|
|
128
|
+
export declare enum FlakinessPattern {
|
|
129
|
+
TIMING = "timing",
|
|
130
|
+
RACE_CONDITION = "race_condition",
|
|
131
|
+
EXTERNAL_DEPENDENCY = "external_dependency",
|
|
132
|
+
ENVIRONMENT_SPECIFIC = "environment_specific",
|
|
133
|
+
SELECTOR_ISSUE = "selector_issue",
|
|
134
|
+
UNKNOWN = "unknown"
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Pattern detection result
|
|
138
|
+
*/
|
|
139
|
+
export interface PatternDetection {
|
|
140
|
+
/** Pattern type */
|
|
141
|
+
patternType: FlakinessPattern;
|
|
142
|
+
/** Pattern description */
|
|
143
|
+
description: string;
|
|
144
|
+
/** Suggested fix */
|
|
145
|
+
suggestedFix: string;
|
|
146
|
+
/** Confidence (0-1) */
|
|
147
|
+
confidence: number;
|
|
148
|
+
/** Whether auto-fix is possible */
|
|
149
|
+
autoFixPossible: boolean;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Calculate flakiness score from test results
|
|
153
|
+
* @param results Array of test results
|
|
154
|
+
* @returns Flakiness score (0-100)
|
|
155
|
+
*/
|
|
156
|
+
export declare function calculateFlakinessScore(results: TestResult[]): number;
|
|
157
|
+
/**
|
|
158
|
+
* Get flakiness category from score
|
|
159
|
+
* @param score Flakiness score (0-100)
|
|
160
|
+
* @returns Flakiness category
|
|
161
|
+
*/
|
|
162
|
+
export declare function getFlakinessCategory(score: number): FlakinessCategory;
|
|
163
|
+
/**
|
|
164
|
+
* Generate a unique test ID
|
|
165
|
+
* @param testName Test name
|
|
166
|
+
* @param filePath File path
|
|
167
|
+
* @returns Unique test ID
|
|
168
|
+
*/
|
|
169
|
+
export declare function generateTestId(testName: string, filePath: string): string;
|
|
170
|
+
/**
|
|
171
|
+
* Analyze test results for flakiness patterns
|
|
172
|
+
* @param results Array of test results for the same test
|
|
173
|
+
* @returns Pattern detection result or undefined
|
|
174
|
+
*/
|
|
175
|
+
export declare function detectFlakinessPattern(results: TestResult[]): PatternDetection | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Calculate consecutive streak (passes or failures)
|
|
178
|
+
* @param results Array of test results sorted by timestamp
|
|
179
|
+
* @returns Current streak info
|
|
180
|
+
*/
|
|
181
|
+
export declare function calculateStreak(results: TestResult[]): {
|
|
182
|
+
currentStreak: number;
|
|
183
|
+
streakType: 'pass' | 'fail';
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Format flakiness score for display
|
|
187
|
+
* @param score Flakiness score (0-100)
|
|
188
|
+
* @returns Formatted string with emoji
|
|
189
|
+
*/
|
|
190
|
+
export declare function formatFlakinessScore(score: number): string;
|
|
191
|
+
/**
|
|
192
|
+
* Flakiness Detection Engine
|
|
193
|
+
*
|
|
194
|
+
* Main class for detecting and scoring test flakiness
|
|
195
|
+
*/
|
|
196
|
+
export declare class FlakinessDetector {
|
|
197
|
+
private options;
|
|
198
|
+
constructor(options?: FlakinessDetectionOptions);
|
|
199
|
+
/**
|
|
200
|
+
* Analyze a single test's flakiness from its run history
|
|
201
|
+
* @param testId Test identifier
|
|
202
|
+
* @param results Array of test results (must be from the same test)
|
|
203
|
+
* @returns Flakiness result
|
|
204
|
+
*/
|
|
205
|
+
analyzeTest(testId: string, results: TestResult[]): FlakinessResult;
|
|
206
|
+
/**
|
|
207
|
+
* Analyze multiple tests and return flakiness results
|
|
208
|
+
* @param testResults Map of testId to array of results
|
|
209
|
+
* @returns Array of flakiness results
|
|
210
|
+
*/
|
|
211
|
+
analyzeAll(testResults: Map<string, TestResult[]>): FlakinessResult[];
|
|
212
|
+
/**
|
|
213
|
+
* Check if a test should be quarantined based on flakiness
|
|
214
|
+
* @param result Flakiness result
|
|
215
|
+
* @returns Whether to quarantine
|
|
216
|
+
*/
|
|
217
|
+
shouldQuarantine(result: FlakinessResult): boolean;
|
|
218
|
+
/**
|
|
219
|
+
* Get quarantine recommendation message
|
|
220
|
+
* @param result Flakiness result
|
|
221
|
+
* @returns Recommendation message
|
|
222
|
+
*/
|
|
223
|
+
getQuarantineRecommendation(result: FlakinessResult): string;
|
|
224
|
+
/**
|
|
225
|
+
* Calculate average duration
|
|
226
|
+
*/
|
|
227
|
+
private averageDuration;
|
|
228
|
+
}
|