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,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Test Optimizer
|
|
3
|
+
*
|
|
4
|
+
* Optimizes generated tests for better quality and maintainability.
|
|
5
|
+
* Removes redundancy, improves assertions, and enhances performance.
|
|
6
|
+
*/
|
|
7
|
+
import type { GeneratedTest } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Optimization options
|
|
10
|
+
*/
|
|
11
|
+
export interface OptimizationOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Remove duplicate tests
|
|
14
|
+
*/
|
|
15
|
+
removeDuplicates?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Merge similar tests
|
|
18
|
+
*/
|
|
19
|
+
mergeSimilarTests?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Improve assertions
|
|
22
|
+
*/
|
|
23
|
+
improveAssertions?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Add performance optimizations
|
|
26
|
+
*/
|
|
27
|
+
addPerformanceOptimizations?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Reduce test flakiness
|
|
30
|
+
*/
|
|
31
|
+
reduceFlakiness?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Target maximum test count
|
|
34
|
+
*/
|
|
35
|
+
maxTestCount?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Optimization result
|
|
39
|
+
*/
|
|
40
|
+
export interface OptimizationResult {
|
|
41
|
+
optimized: GeneratedTest[];
|
|
42
|
+
removed: number;
|
|
43
|
+
merged: number;
|
|
44
|
+
improvements: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Test Optimizer class
|
|
48
|
+
*/
|
|
49
|
+
export declare class TestOptimizer {
|
|
50
|
+
private readonly options;
|
|
51
|
+
private readonly defaultOptions;
|
|
52
|
+
constructor(options?: OptimizationOptions);
|
|
53
|
+
/**
|
|
54
|
+
* Optimize generated tests
|
|
55
|
+
*/
|
|
56
|
+
optimize(tests: GeneratedTest[]): OptimizationResult;
|
|
57
|
+
/**
|
|
58
|
+
* Remove duplicate tests
|
|
59
|
+
*/
|
|
60
|
+
private removeDuplicateTests;
|
|
61
|
+
/**
|
|
62
|
+
* Merge similar test cases
|
|
63
|
+
*/
|
|
64
|
+
private mergeSimilarTestCases;
|
|
65
|
+
/**
|
|
66
|
+
* Improve test assertions
|
|
67
|
+
*/
|
|
68
|
+
private improveTestAssertions;
|
|
69
|
+
/**
|
|
70
|
+
* Add performance improvements
|
|
71
|
+
*/
|
|
72
|
+
private addPerformanceImprovements;
|
|
73
|
+
/**
|
|
74
|
+
* Reduce test flakiness
|
|
75
|
+
*/
|
|
76
|
+
private reduceTestFlakiness;
|
|
77
|
+
/**
|
|
78
|
+
* Prioritize tests by importance
|
|
79
|
+
*/
|
|
80
|
+
private prioritizeTests;
|
|
81
|
+
/**
|
|
82
|
+
* Create test signature for deduplication
|
|
83
|
+
*/
|
|
84
|
+
private createTestSignature;
|
|
85
|
+
/**
|
|
86
|
+
* Calculate similarity between two tests
|
|
87
|
+
*/
|
|
88
|
+
private calculateSimilarity;
|
|
89
|
+
/**
|
|
90
|
+
* Merge multiple tests into one
|
|
91
|
+
*/
|
|
92
|
+
private mergeTests;
|
|
93
|
+
/**
|
|
94
|
+
* Extract test cases from code
|
|
95
|
+
*/
|
|
96
|
+
private extractTestCases;
|
|
97
|
+
/**
|
|
98
|
+
* Enhance assertions in code
|
|
99
|
+
*/
|
|
100
|
+
private enhanceAssertions;
|
|
101
|
+
/**
|
|
102
|
+
* Optimize performance
|
|
103
|
+
*/
|
|
104
|
+
private optimizePerformance;
|
|
105
|
+
/**
|
|
106
|
+
* Add stability improvements
|
|
107
|
+
*/
|
|
108
|
+
private addStabilityImprovements;
|
|
109
|
+
/**
|
|
110
|
+
* Get optimization suggestions for a test
|
|
111
|
+
*/
|
|
112
|
+
getSuggestions(test: GeneratedTest): string[];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create optimizer with default config
|
|
116
|
+
*/
|
|
117
|
+
export declare function createOptimizer(options?: OptimizationOptions): TestOptimizer;
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Test Optimizer
|
|
3
|
+
*
|
|
4
|
+
* Optimizes generated tests for better quality and maintainability.
|
|
5
|
+
* Removes redundancy, improves assertions, and enhances performance.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Test Optimizer class
|
|
9
|
+
*/
|
|
10
|
+
export class TestOptimizer {
|
|
11
|
+
options;
|
|
12
|
+
defaultOptions = {
|
|
13
|
+
removeDuplicates: true,
|
|
14
|
+
mergeSimilarTests: true,
|
|
15
|
+
improveAssertions: true,
|
|
16
|
+
addPerformanceOptimizations: true,
|
|
17
|
+
reduceFlakiness: true,
|
|
18
|
+
maxTestCount: 100,
|
|
19
|
+
};
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.options = { ...this.defaultOptions, ...options };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Optimize generated tests
|
|
25
|
+
*/
|
|
26
|
+
optimize(tests) {
|
|
27
|
+
let optimized = [...tests];
|
|
28
|
+
const improvements = [];
|
|
29
|
+
let removed = 0;
|
|
30
|
+
let merged = 0;
|
|
31
|
+
// Remove duplicates
|
|
32
|
+
if (this.options.removeDuplicates) {
|
|
33
|
+
const before = optimized.length;
|
|
34
|
+
optimized = this.removeDuplicateTests(optimized);
|
|
35
|
+
removed = before - optimized.length;
|
|
36
|
+
if (removed > 0) {
|
|
37
|
+
improvements.push(`Removed ${removed} duplicate test(s)`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Merge similar tests
|
|
41
|
+
if (this.options.mergeSimilarTests) {
|
|
42
|
+
const before = optimized.length;
|
|
43
|
+
optimized = this.mergeSimilarTestCases(optimized);
|
|
44
|
+
merged = before - optimized.length;
|
|
45
|
+
if (merged > 0) {
|
|
46
|
+
improvements.push(`Merged ${merged} similar test(s)`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Improve assertions
|
|
50
|
+
if (this.options.improveAssertions) {
|
|
51
|
+
optimized = this.improveTestAssertions(optimized);
|
|
52
|
+
improvements.push('Improved assertions quality');
|
|
53
|
+
}
|
|
54
|
+
// Add performance optimizations
|
|
55
|
+
if (this.options.addPerformanceOptimizations) {
|
|
56
|
+
optimized = this.addPerformanceImprovements(optimized);
|
|
57
|
+
improvements.push('Added performance optimizations');
|
|
58
|
+
}
|
|
59
|
+
// Reduce flakiness
|
|
60
|
+
if (this.options.reduceFlakiness) {
|
|
61
|
+
optimized = this.reduceTestFlakiness(optimized);
|
|
62
|
+
improvements.push('Reduced test flakiness');
|
|
63
|
+
}
|
|
64
|
+
// Limit test count
|
|
65
|
+
if (this.options.maxTestCount && optimized.length > this.options.maxTestCount) {
|
|
66
|
+
const before = optimized.length;
|
|
67
|
+
optimized = this.prioritizeTests(optimized).slice(0, this.options.maxTestCount);
|
|
68
|
+
improvements.push(`Prioritized and kept ${this.options.maxTestCount} most important tests (${before - this.options.maxTestCount} removed)`);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
optimized,
|
|
72
|
+
removed,
|
|
73
|
+
merged,
|
|
74
|
+
improvements,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Remove duplicate tests
|
|
79
|
+
*/
|
|
80
|
+
removeDuplicateTests(tests) {
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
const unique = [];
|
|
83
|
+
for (const test of tests) {
|
|
84
|
+
// Create a signature based on test content
|
|
85
|
+
const signature = this.createTestSignature(test);
|
|
86
|
+
if (!seen.has(signature)) {
|
|
87
|
+
seen.add(signature);
|
|
88
|
+
unique.push(test);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return unique;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Merge similar test cases
|
|
95
|
+
*/
|
|
96
|
+
mergeSimilarTestCases(tests) {
|
|
97
|
+
const merged = [];
|
|
98
|
+
const used = new Set();
|
|
99
|
+
for (let i = 0; i < tests.length; i++) {
|
|
100
|
+
if (used.has(i))
|
|
101
|
+
continue;
|
|
102
|
+
const current = tests[i];
|
|
103
|
+
const similar = [current];
|
|
104
|
+
// Find similar tests
|
|
105
|
+
for (let j = i + 1; j < tests.length; j++) {
|
|
106
|
+
if (used.has(j))
|
|
107
|
+
continue;
|
|
108
|
+
const similarity = this.calculateSimilarity(current, tests[j]);
|
|
109
|
+
if (similarity.score > 0.7) {
|
|
110
|
+
similar.push(tests[j]);
|
|
111
|
+
used.add(j);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Merge similar tests or keep as-is
|
|
115
|
+
if (similar.length > 1) {
|
|
116
|
+
merged.push(this.mergeTests(similar));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
merged.push(current);
|
|
120
|
+
}
|
|
121
|
+
used.add(i);
|
|
122
|
+
}
|
|
123
|
+
return merged;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Improve test assertions
|
|
127
|
+
*/
|
|
128
|
+
improveTestAssertions(tests) {
|
|
129
|
+
return tests.map(test => ({
|
|
130
|
+
...test,
|
|
131
|
+
code: this.enhanceAssertions(test.code),
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Add performance improvements
|
|
136
|
+
*/
|
|
137
|
+
addPerformanceImprovements(tests) {
|
|
138
|
+
return tests.map(test => ({
|
|
139
|
+
...test,
|
|
140
|
+
code: this.optimizePerformance(test.code, test.framework),
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Reduce test flakiness
|
|
145
|
+
*/
|
|
146
|
+
reduceTestFlakiness(tests) {
|
|
147
|
+
return tests.map(test => ({
|
|
148
|
+
...test,
|
|
149
|
+
code: this.addStabilityImprovements(test.code, test.framework),
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Prioritize tests by importance
|
|
154
|
+
*/
|
|
155
|
+
prioritizeTests(tests) {
|
|
156
|
+
return tests.sort((a, b) => {
|
|
157
|
+
// Prefer tests with more assertions
|
|
158
|
+
const aAssertions = a.summary.assertionCount || 0;
|
|
159
|
+
const bAssertions = b.summary.assertionCount || 0;
|
|
160
|
+
if (aAssertions !== bAssertions) {
|
|
161
|
+
return bAssertions - aAssertions;
|
|
162
|
+
}
|
|
163
|
+
// Then prefer shorter tests (faster)
|
|
164
|
+
const aLines = a.summary.lines;
|
|
165
|
+
const bLines = b.summary.lines;
|
|
166
|
+
return aLines - bLines;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create test signature for deduplication
|
|
171
|
+
*/
|
|
172
|
+
createTestSignature(test) {
|
|
173
|
+
// Normalize code for comparison
|
|
174
|
+
const normalized = test.code
|
|
175
|
+
.replace(/\s+/g, ' ')
|
|
176
|
+
.replace(/\/\/.*$/gm, '') // Remove comments
|
|
177
|
+
.toLowerCase()
|
|
178
|
+
.trim();
|
|
179
|
+
// Simple hash of content
|
|
180
|
+
let hash = 0;
|
|
181
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
182
|
+
const char = normalized.charCodeAt(i);
|
|
183
|
+
hash = ((hash << 5) - hash) + char;
|
|
184
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
185
|
+
}
|
|
186
|
+
return `${test.name}-${Math.abs(hash)}`;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Calculate similarity between two tests
|
|
190
|
+
*/
|
|
191
|
+
calculateSimilarity(test1, test2) {
|
|
192
|
+
// Check framework match
|
|
193
|
+
if (test1.framework !== test2.framework) {
|
|
194
|
+
return { test1, test2, score: 0 };
|
|
195
|
+
}
|
|
196
|
+
// Compare structure
|
|
197
|
+
const words1 = new Set(test1.code.toLowerCase().split(/\W+/));
|
|
198
|
+
const words2 = new Set(test2.code.toLowerCase().split(/\W+/));
|
|
199
|
+
let intersection = 0;
|
|
200
|
+
for (const word of words1) {
|
|
201
|
+
if (words2.has(word) && word.length > 4) { // Only significant words
|
|
202
|
+
intersection++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const union = new Set([...words1, ...words2]).size;
|
|
206
|
+
const score = union > 0 ? intersection / union : 0;
|
|
207
|
+
return { test1, test2, score };
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Merge multiple tests into one
|
|
211
|
+
*/
|
|
212
|
+
mergeTests(tests) {
|
|
213
|
+
const base = tests[0];
|
|
214
|
+
const mergedName = `${base.name} (merged ${tests.length})`;
|
|
215
|
+
// Combine test code (simplified)
|
|
216
|
+
let mergedCode = base.code;
|
|
217
|
+
// Extract test cases from each and combine them
|
|
218
|
+
for (const test of tests.slice(1)) {
|
|
219
|
+
const testCases = this.extractTestCases(test.code);
|
|
220
|
+
for (const testCase of testCases) {
|
|
221
|
+
mergedCode += '\n\n' + testCase;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
...base,
|
|
226
|
+
name: mergedName,
|
|
227
|
+
code: mergedCode,
|
|
228
|
+
summary: {
|
|
229
|
+
lines: mergedCode.split('\n').length,
|
|
230
|
+
testCount: tests.reduce((sum, t) => sum + (t.summary.testCount || 0), 0),
|
|
231
|
+
assertionCount: tests.reduce((sum, t) => sum + (t.summary.assertionCount || 0), 0),
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Extract test cases from code
|
|
237
|
+
*/
|
|
238
|
+
extractTestCases(code) {
|
|
239
|
+
const cases = [];
|
|
240
|
+
// Match test() or it() blocks
|
|
241
|
+
const testRegex = /\b(test|it)\s*\(\s*['"]([^'"]+)['"][\s\S]*?\n\s*\}\s*\)/g;
|
|
242
|
+
let match;
|
|
243
|
+
while ((match = testRegex.exec(code)) !== null) {
|
|
244
|
+
cases.push(match[0]);
|
|
245
|
+
}
|
|
246
|
+
return cases;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Enhance assertions in code
|
|
250
|
+
*/
|
|
251
|
+
enhanceAssertions(code) {
|
|
252
|
+
let enhanced = code;
|
|
253
|
+
// Add status code checks for API tests
|
|
254
|
+
enhanced = enhanced.replace(/const response = await fetch\([^)]+\);\s*$/gm, '$&\n expect(response.status).toBeGreaterThanOrEqual(200);\n expect(response.status).toBeLessThan(300);');
|
|
255
|
+
// Add non-empty assertions for array responses
|
|
256
|
+
enhanced = enhanced.replace(/const data = await response\.json\(\);\s*$/gm, '$&\n expect(data).toBeDefined();');
|
|
257
|
+
// Add timeout for slow operations
|
|
258
|
+
enhanced = enhanced.replace(/\bwaitForURL\(/g, 'waitForURL(');
|
|
259
|
+
return enhanced;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Optimize performance
|
|
263
|
+
*/
|
|
264
|
+
optimizePerformance(code, framework) {
|
|
265
|
+
let optimized = code;
|
|
266
|
+
if (framework === 'playwright') {
|
|
267
|
+
// Add reuse of browser contexts where possible
|
|
268
|
+
optimized = optimized.replace(/test\.describe\(/g, 'test.describe.serial(');
|
|
269
|
+
// Suggest parallel test execution
|
|
270
|
+
if (!optimized.includes('test.describe.configure')) {
|
|
271
|
+
optimized = 'test.describe.configure({ mode: \'parallel\' });\n\n' + optimized;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Remove unnecessary waits
|
|
275
|
+
optimized = optimized.replace(/\bpage\.waitForTimeout\(\d+\)/g, '// waitForTimeout removed - use explicit waits instead');
|
|
276
|
+
return optimized;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Add stability improvements
|
|
280
|
+
*/
|
|
281
|
+
addStabilityImprovements(code, framework) {
|
|
282
|
+
let stable = code;
|
|
283
|
+
if (framework === 'playwright') {
|
|
284
|
+
// Replace waitFor with waitForSelector for more reliable waits
|
|
285
|
+
stable = stable.replace(/\bwaitFor\(/g, 'waitForSelector(');
|
|
286
|
+
// Add explicit waits for navigation
|
|
287
|
+
stable = stable.replace(/(\.click\([^)]+\))(?!.*waitFor)/g, '$1\n await page.waitForLoadState(\'networkidle\');');
|
|
288
|
+
}
|
|
289
|
+
// Add retry logic for API tests
|
|
290
|
+
if (framework === 'playwright' && (code.includes('fetch') || code.includes('axios'))) {
|
|
291
|
+
stable = stable.replace(/test\s*\(\s*['"]([^'"]+)['"]\s*,\s*async\s+/g, 'test(\'$1 (with retry)\', async ');
|
|
292
|
+
}
|
|
293
|
+
return stable;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Get optimization suggestions for a test
|
|
297
|
+
*/
|
|
298
|
+
getSuggestions(test) {
|
|
299
|
+
const suggestions = [];
|
|
300
|
+
// Check for missing assertions
|
|
301
|
+
if ((test.summary.assertionCount || 0) < (test.summary.testCount || 1)) {
|
|
302
|
+
suggestions.push('Consider adding more assertions for better coverage');
|
|
303
|
+
}
|
|
304
|
+
// Check for long tests
|
|
305
|
+
if (test.summary.lines > 200) {
|
|
306
|
+
suggestions.push('Test is very long - consider splitting into smaller tests');
|
|
307
|
+
}
|
|
308
|
+
// Check for console.log
|
|
309
|
+
if (test.code.includes('console.log')) {
|
|
310
|
+
suggestions.push('Remove console.log statements - use assertions instead');
|
|
311
|
+
}
|
|
312
|
+
// Check for hardcoded values
|
|
313
|
+
if (test.code.includes('123456') || test.code.includes('test@test')) {
|
|
314
|
+
suggestions.push('Use test fixtures instead of hardcoded values');
|
|
315
|
+
}
|
|
316
|
+
// Check for missing error handling
|
|
317
|
+
if (!test.code.includes('try') && !test.code.includes('catch')) {
|
|
318
|
+
suggestions.push('Consider adding error handling for robustness');
|
|
319
|
+
}
|
|
320
|
+
return suggestions;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Create optimizer with default config
|
|
325
|
+
*/
|
|
326
|
+
export function createOptimizer(options) {
|
|
327
|
+
return new TestOptimizer(options);
|
|
328
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for AI Test Generation
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base test specification
|
|
6
|
+
*/
|
|
7
|
+
export interface TestSpec {
|
|
8
|
+
type: 'api' | 'ui' | 'perf' | 'unit';
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* API test specification
|
|
15
|
+
*/
|
|
16
|
+
export interface ApiTestSpec extends TestSpec {
|
|
17
|
+
type: 'api';
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
endpoints: ApiEndpoint[];
|
|
20
|
+
auth?: AuthSpec;
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* API endpoint definition
|
|
25
|
+
*/
|
|
26
|
+
export interface ApiEndpoint {
|
|
27
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
28
|
+
path: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
body?: unknown;
|
|
32
|
+
queryParams?: Record<string, string>;
|
|
33
|
+
expectations?: ApiExpectation[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* API expectations
|
|
37
|
+
*/
|
|
38
|
+
export interface ApiExpectation {
|
|
39
|
+
status?: number | number[];
|
|
40
|
+
responseTime?: string;
|
|
41
|
+
hasBody?: boolean;
|
|
42
|
+
schema?: Record<string, unknown>;
|
|
43
|
+
contains?: string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* UI test specification
|
|
47
|
+
*/
|
|
48
|
+
export interface UiTestSpec extends TestSpec {
|
|
49
|
+
type: 'ui';
|
|
50
|
+
baseUrl: string;
|
|
51
|
+
pages: PageSpec[];
|
|
52
|
+
auth?: AuthSpec;
|
|
53
|
+
viewport?: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Page specification for UI tests
|
|
60
|
+
*/
|
|
61
|
+
export interface PageSpec {
|
|
62
|
+
name: string;
|
|
63
|
+
url: string;
|
|
64
|
+
actions: PageAction[];
|
|
65
|
+
assertions?: Assertion[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Page action
|
|
69
|
+
*/
|
|
70
|
+
export interface PageAction {
|
|
71
|
+
type: 'goto' | 'click' | 'fill' | 'select' | 'wait' | 'hover' | 'screenshot' | 'type' | 'check' | 'uncheck';
|
|
72
|
+
selector?: string;
|
|
73
|
+
value?: string;
|
|
74
|
+
timeout?: number;
|
|
75
|
+
options?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Assertion for UI tests
|
|
79
|
+
*/
|
|
80
|
+
export interface Assertion {
|
|
81
|
+
type: 'url' | 'title' | 'visible' | 'text' | 'attribute' | 'count';
|
|
82
|
+
selector?: string;
|
|
83
|
+
expected: string | number | boolean;
|
|
84
|
+
operator?: 'equals' | 'contains' | 'matches' | 'greaterThan' | 'lessThan';
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Performance test specification
|
|
88
|
+
*/
|
|
89
|
+
export interface PerfTestSpec extends TestSpec {
|
|
90
|
+
type: 'perf';
|
|
91
|
+
baseUrl: string;
|
|
92
|
+
scenarios: PerfScenario[];
|
|
93
|
+
options?: PerfOptions;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Performance scenario
|
|
97
|
+
*/
|
|
98
|
+
export interface PerfScenario {
|
|
99
|
+
name: string;
|
|
100
|
+
weight?: number;
|
|
101
|
+
requests: PerfRequest[];
|
|
102
|
+
thinkTime?: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Performance request
|
|
106
|
+
*/
|
|
107
|
+
export interface PerfRequest {
|
|
108
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
109
|
+
path: string;
|
|
110
|
+
headers?: Record<string, string>;
|
|
111
|
+
body?: unknown;
|
|
112
|
+
timeout?: number;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Performance test options
|
|
116
|
+
*/
|
|
117
|
+
export interface PerfOptions {
|
|
118
|
+
duration?: string;
|
|
119
|
+
rate?: number;
|
|
120
|
+
vus?: number;
|
|
121
|
+
maxVus?: number;
|
|
122
|
+
thresholds?: PerfThreshold[];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Performance thresholds
|
|
126
|
+
*/
|
|
127
|
+
export interface PerfThreshold {
|
|
128
|
+
metric: 'http_req_duration' | 'http_req_failed' | 'checks';
|
|
129
|
+
condition: string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Unit test specification
|
|
133
|
+
*/
|
|
134
|
+
export interface UnitTestSpec extends TestSpec {
|
|
135
|
+
type: 'unit';
|
|
136
|
+
source: {
|
|
137
|
+
language: 'typescript' | 'javascript' | 'python' | 'go' | 'rust';
|
|
138
|
+
filePath: string;
|
|
139
|
+
code?: string;
|
|
140
|
+
exports?: string[];
|
|
141
|
+
};
|
|
142
|
+
framework?: 'vitest' | 'jest' | 'pytest' | 'go test';
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Authentication specification
|
|
146
|
+
*/
|
|
147
|
+
export interface AuthSpec {
|
|
148
|
+
type: 'none' | 'bearer' | 'basic' | 'api_key' | 'oauth2' | 'jwt';
|
|
149
|
+
config?: Record<string, unknown>;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Generation context
|
|
153
|
+
*/
|
|
154
|
+
export interface GenerationContext {
|
|
155
|
+
projectName: string;
|
|
156
|
+
framework: 'playwright' | 'k6' | 'vitest' | 'jest';
|
|
157
|
+
language: 'typescript' | 'javascript' | 'go';
|
|
158
|
+
outputDir?: string;
|
|
159
|
+
options?: GenerationOptions;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generation options
|
|
163
|
+
*/
|
|
164
|
+
export interface GenerationOptions {
|
|
165
|
+
includeComments?: boolean;
|
|
166
|
+
includeAssertions?: boolean;
|
|
167
|
+
includeRetryLogic?: boolean;
|
|
168
|
+
optimize?: boolean;
|
|
169
|
+
targetCoverage?: number;
|
|
170
|
+
maxTests?: number;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Generated test result
|
|
174
|
+
*/
|
|
175
|
+
export interface GeneratedTest {
|
|
176
|
+
name: string;
|
|
177
|
+
code: string;
|
|
178
|
+
language: string;
|
|
179
|
+
framework: string;
|
|
180
|
+
filePath: string;
|
|
181
|
+
summary: {
|
|
182
|
+
lines: number;
|
|
183
|
+
testCount: number;
|
|
184
|
+
assertionCount?: number;
|
|
185
|
+
};
|
|
186
|
+
metadata?: {
|
|
187
|
+
generatedAt: string;
|
|
188
|
+
model: string;
|
|
189
|
+
tokensUsed: number;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Source for test generation
|
|
194
|
+
*/
|
|
195
|
+
export type GenerationSource = {
|
|
196
|
+
type: 'openapi';
|
|
197
|
+
urlOrPath: string;
|
|
198
|
+
} | {
|
|
199
|
+
type: 'har';
|
|
200
|
+
filePath: string;
|
|
201
|
+
} | {
|
|
202
|
+
type: 'url';
|
|
203
|
+
url: string;
|
|
204
|
+
} | {
|
|
205
|
+
type: 'spec';
|
|
206
|
+
spec: TestSpec;
|
|
207
|
+
} | {
|
|
208
|
+
type: 'description';
|
|
209
|
+
description: string;
|
|
210
|
+
} | {
|
|
211
|
+
type: 'code';
|
|
212
|
+
code: string;
|
|
213
|
+
language: string;
|
|
214
|
+
};
|
package/dist/core/index.d.ts
CHANGED
|
@@ -60,14 +60,36 @@ export declare class QA360Core {
|
|
|
60
60
|
export declare const VERSION = "0.9.0-core";
|
|
61
61
|
export * from './proof/index.js';
|
|
62
62
|
export { EvidenceVault } from './vault/index.js';
|
|
63
|
-
export type { RunRecord, GateRecord, FindingRecord } from './vault/index.js';
|
|
63
|
+
export type { RunRecord, GateRecord, FindingRecord, FlakinessRecord, FlakinessPatternRecord, QuarantineRecord } from './vault/index.js';
|
|
64
64
|
export { SecurityRedactor } from './security/redactor.js';
|
|
65
65
|
export { SecretsManager } from './secrets/manager.js';
|
|
66
66
|
export { SecretsCrypto } from './secrets/crypto.js';
|
|
67
67
|
export { PackValidator } from './pack/validator.js';
|
|
68
68
|
export { PackMigrator } from './pack/migrator.js';
|
|
69
69
|
export type { PackConfigV1 } from './types/pack-v1.js';
|
|
70
|
+
export * from './ai/index.js';
|
|
71
|
+
export * from './discoverer/index.js';
|
|
72
|
+
export * from './types/pack-v2.js';
|
|
73
|
+
export type { PackConfigV2, AuthConfigV2, AuthProfile, AuthTypeV2, AuthCacheConfig, GateConfigV2, GateBudgets, GateOptions, HooksConfig, Hook, ExecutionConfigV2, ResourceLimits, SecurityBudgets, PerformanceTargets } from './types/pack-v2.js';
|
|
74
|
+
export * from './pack-v2/index.js';
|
|
75
|
+
export { PackLoaderV2, PackValidatorV2, PackLoadResult } from './pack-v2/index.js';
|
|
76
|
+
export type { PackMigrationResultV2, ValidationError } from './pack-v2/index.js';
|
|
77
|
+
export * from './auth/index.js';
|
|
78
|
+
export * from './generation/index.js';
|
|
70
79
|
export { QA360Server } from './serve/server.js';
|
|
71
80
|
export type { ServeConfig } from './serve/server.js';
|
|
72
81
|
export { Phase3Runner } from './runner/phase3-runner.js';
|
|
73
82
|
export type { Phase3RunnerOptions, Phase3RunResult, GateResult } from './runner/phase3-runner.js';
|
|
83
|
+
export { PlaywrightNativeApiAdapter, createPlaywrightNativeApiAdapter } from './adapters/playwright-native-api.js';
|
|
84
|
+
export type { NativeApiTestConfig, NativeApiSmokeResult } from './adapters/playwright-native-api.js';
|
|
85
|
+
export * from './repair/index.js';
|
|
86
|
+
export * from './tui/index.js';
|
|
87
|
+
export * from './dashboard/index.js';
|
|
88
|
+
export * from './flakiness/index.js';
|
|
89
|
+
export * from './retry/index.js';
|
|
90
|
+
export * from './cache/index.js';
|
|
91
|
+
export * from './watch/index.js';
|
|
92
|
+
export * from './self-healing/index.js';
|
|
93
|
+
export * from './coverage/index.js';
|
|
94
|
+
export * from './slo/index.js';
|
|
95
|
+
export * from './regression/index.js';
|