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,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Code Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates test code using LLM providers.
|
|
5
|
+
* Orchestrates prompt building and LLM calls.
|
|
6
|
+
*/
|
|
7
|
+
import { OllamaProvider } from '../ai/index.js';
|
|
8
|
+
import { PromptBuilder } from './prompt-builder.js';
|
|
9
|
+
import { CodeFormatter } from './code-formatter.js';
|
|
10
|
+
/**
|
|
11
|
+
* Code Generator class
|
|
12
|
+
*/
|
|
13
|
+
export class CodeGenerator {
|
|
14
|
+
provider;
|
|
15
|
+
formatter;
|
|
16
|
+
options;
|
|
17
|
+
defaultOptions = {
|
|
18
|
+
ollama: {},
|
|
19
|
+
model: 'auto', // Let provider choose best model
|
|
20
|
+
temperature: 0.3, // Lower temperature for code generation
|
|
21
|
+
maxTokens: 8192,
|
|
22
|
+
timeout: 30000, // 30 seconds default timeout
|
|
23
|
+
formatCode: true,
|
|
24
|
+
optimize: false,
|
|
25
|
+
outputDir: './tests/generated',
|
|
26
|
+
promptOptions: {
|
|
27
|
+
includeComments: true,
|
|
28
|
+
includeDetailedAssertions: true,
|
|
29
|
+
includeRetryLogic: true,
|
|
30
|
+
codeStyle: 'clean',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
// Runtime guard: validate options before proceeding
|
|
35
|
+
if (options.timeout !== undefined && (options.timeout < 100 || options.timeout > 600000)) {
|
|
36
|
+
throw new Error(`CODE_GENERATOR: timeout must be between 100ms and 600000ms (10 minutes), got ${options.timeout}ms`);
|
|
37
|
+
}
|
|
38
|
+
if (options.temperature !== undefined && (options.temperature < 0 || options.temperature > 1)) {
|
|
39
|
+
throw new Error(`CODE_GENERATOR: temperature must be between 0 and 1, got ${options.temperature}`);
|
|
40
|
+
}
|
|
41
|
+
this.options = { ...this.defaultOptions, ...options };
|
|
42
|
+
// Initialize OllamaProvider
|
|
43
|
+
this.provider = new OllamaProvider(this.options.ollama);
|
|
44
|
+
this.formatter = new CodeFormatter();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate tests from a source
|
|
48
|
+
*/
|
|
49
|
+
async generateFromSource(source, context) {
|
|
50
|
+
const startTime = Date.now();
|
|
51
|
+
try {
|
|
52
|
+
// Build prompt
|
|
53
|
+
const promptBuilder = new PromptBuilder(this.options.promptOptions);
|
|
54
|
+
const builtPrompt = await promptBuilder.buildFromSource(source);
|
|
55
|
+
// Generate code with timeout
|
|
56
|
+
const response = await this.withTimeout(this.provider.generate({
|
|
57
|
+
prompt: builtPrompt.user,
|
|
58
|
+
systemPrompt: builtPrompt.system,
|
|
59
|
+
temperature: this.options.temperature,
|
|
60
|
+
maxTokens: this.options.maxTokens,
|
|
61
|
+
jsonMode: false, // We want code, not JSON
|
|
62
|
+
}));
|
|
63
|
+
// Extract code from response
|
|
64
|
+
const code = this.extractCode(response.content);
|
|
65
|
+
// Parse multiple test files if present
|
|
66
|
+
const tests = this.parseGeneratedTests(code, context);
|
|
67
|
+
// Format if requested
|
|
68
|
+
if (this.options.formatCode) {
|
|
69
|
+
for (const test of tests) {
|
|
70
|
+
test.code = this.formatter.format(test.code, test.language);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Calculate file paths
|
|
74
|
+
for (const test of tests) {
|
|
75
|
+
test.filePath = this.getFilePath(test, context);
|
|
76
|
+
test.metadata = {
|
|
77
|
+
generatedAt: new Date().toISOString(),
|
|
78
|
+
model: response.model,
|
|
79
|
+
tokensUsed: response.usage.totalTokens,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
tests,
|
|
85
|
+
metadata: {
|
|
86
|
+
duration: Date.now() - startTime,
|
|
87
|
+
model: response.model,
|
|
88
|
+
tokensUsed: response.usage.totalTokens,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
// Distinguish timeout from other errors
|
|
94
|
+
const isTimeout = error instanceof Error && error.name === 'QA360TimeoutError';
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
tests: [],
|
|
98
|
+
errors: isTimeout
|
|
99
|
+
? [`TIMEOUT: LLM generation exceeded ${this.options.timeout}ms limit`]
|
|
100
|
+
: [error instanceof Error ? error.message : String(error)],
|
|
101
|
+
metadata: {
|
|
102
|
+
duration: Date.now() - startTime,
|
|
103
|
+
model: this.options.model,
|
|
104
|
+
tokensUsed: 0,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Wrap a promise with timeout
|
|
111
|
+
* Throws QA360TimeoutError on timeout
|
|
112
|
+
*/
|
|
113
|
+
async withTimeout(promise) {
|
|
114
|
+
const controller = new AbortController();
|
|
115
|
+
const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
|
|
116
|
+
try {
|
|
117
|
+
// Note: OllamaProvider doesn't support AbortSignal natively
|
|
118
|
+
// We race the promise against a timeout
|
|
119
|
+
return await Promise.race([
|
|
120
|
+
promise,
|
|
121
|
+
new Promise((_, reject) => setTimeout(() => {
|
|
122
|
+
const err = new Error(`TIMEOUT: Operation exceeded ${this.options.timeout}ms`);
|
|
123
|
+
err.name = 'QA360TimeoutError';
|
|
124
|
+
reject(err);
|
|
125
|
+
}, this.options.timeout)),
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
clearTimeout(timeoutId);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generate tests from OpenAPI spec
|
|
134
|
+
*/
|
|
135
|
+
async generateFromOpenAPI(specPath, context = {}) {
|
|
136
|
+
return this.generateFromSource({ type: 'openapi', urlOrPath: specPath }, context);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Generate tests from HAR file
|
|
140
|
+
*/
|
|
141
|
+
async generateFromHAR(filePath, context = {}) {
|
|
142
|
+
return this.generateFromSource({ type: 'har', filePath }, context);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Generate tests from URL
|
|
146
|
+
*/
|
|
147
|
+
async generateFromUrl(url, context = {}) {
|
|
148
|
+
return this.generateFromSource({ type: 'url', url }, context);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Generate tests from spec
|
|
152
|
+
*/
|
|
153
|
+
async generateFromSpec(spec, context = {}) {
|
|
154
|
+
return this.generateFromSource({ type: 'spec', spec }, context);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Generate tests from description
|
|
158
|
+
*/
|
|
159
|
+
async generateFromDescription(description, context = {}) {
|
|
160
|
+
return this.generateFromSource({ type: 'description', description }, context);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Generate tests from code
|
|
164
|
+
*/
|
|
165
|
+
async generateFromCode(code, language, context = {}) {
|
|
166
|
+
return this.generateFromSource({ type: 'code', code, language }, context);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Extract code from LLM response
|
|
170
|
+
* Handles markdown code blocks and plain code
|
|
171
|
+
*/
|
|
172
|
+
extractCode(response) {
|
|
173
|
+
// Check for markdown code blocks
|
|
174
|
+
const codeBlockRegex = /```(?:typescript|javascript|ts|js|go|python)?\n([\s\S]+?)```/g;
|
|
175
|
+
const matches = Array.from(response.matchAll(codeBlockRegex));
|
|
176
|
+
if (matches.length > 0) {
|
|
177
|
+
// Return all code blocks concatenated
|
|
178
|
+
return matches.map(m => m[1].trim()).join('\n\n');
|
|
179
|
+
}
|
|
180
|
+
// No code blocks found, return as-is
|
|
181
|
+
return response.trim();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Parse generated tests into separate files
|
|
185
|
+
*/
|
|
186
|
+
parseGeneratedTests(code, context) {
|
|
187
|
+
const tests = [];
|
|
188
|
+
// Try to split by describe blocks or test suites
|
|
189
|
+
const suiteRegex = /(?:test\.describe|describe|suite)\s*\(\s*['"]([^'"]+)['"]/g;
|
|
190
|
+
const matches = Array.from(code.matchAll(suiteRegex));
|
|
191
|
+
if (matches.length > 1) {
|
|
192
|
+
// Multiple test suites found
|
|
193
|
+
let lastIndex = 0;
|
|
194
|
+
const framework = context.framework || 'playwright';
|
|
195
|
+
const language = context.language || 'typescript';
|
|
196
|
+
for (let i = 0; i < matches.length; i++) {
|
|
197
|
+
const match = matches[i];
|
|
198
|
+
const nextMatch = matches[i + 1];
|
|
199
|
+
const startIndex = match.index || 0;
|
|
200
|
+
const endIndex = nextMatch?.index || code.length;
|
|
201
|
+
const suiteCode = code.substring(startIndex, endIndex).trim();
|
|
202
|
+
const suiteName = match[1];
|
|
203
|
+
tests.push({
|
|
204
|
+
name: suiteName,
|
|
205
|
+
code: suiteCode,
|
|
206
|
+
language,
|
|
207
|
+
framework,
|
|
208
|
+
filePath: '', // Will be set later
|
|
209
|
+
summary: this.summarizeCode(suiteCode),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// Single test file
|
|
215
|
+
const framework = context.framework || 'playwright';
|
|
216
|
+
const language = context.language || 'typescript';
|
|
217
|
+
tests.push({
|
|
218
|
+
name: context.projectName || 'generated-tests',
|
|
219
|
+
code,
|
|
220
|
+
language,
|
|
221
|
+
framework,
|
|
222
|
+
filePath: '',
|
|
223
|
+
summary: this.summarizeCode(code),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return tests;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Summarize code
|
|
230
|
+
*/
|
|
231
|
+
summarizeCode(code) {
|
|
232
|
+
const lines = code.split('\n').length;
|
|
233
|
+
// Count test functions
|
|
234
|
+
const testMatches = code.match(/\b(test|it)\s*\(/g) || [];
|
|
235
|
+
const testCount = testMatches.length;
|
|
236
|
+
// Count assertions
|
|
237
|
+
const assertMatches = code.match(/\b(expect|assert)\b/g) || [];
|
|
238
|
+
const assertionCount = assertMatches.length;
|
|
239
|
+
return {
|
|
240
|
+
lines,
|
|
241
|
+
testCount,
|
|
242
|
+
assertionCount,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get file path for generated test
|
|
247
|
+
*/
|
|
248
|
+
getFilePath(test, context) {
|
|
249
|
+
const outputDir = context.outputDir || this.options.outputDir;
|
|
250
|
+
const name = test.name.toLowerCase().replace(/\s+/g, '-');
|
|
251
|
+
let extension = 'ts';
|
|
252
|
+
if (test.language === 'javascript' || test.language === 'js') {
|
|
253
|
+
extension = 'js';
|
|
254
|
+
}
|
|
255
|
+
else if (test.language === 'go') {
|
|
256
|
+
extension = 'go';
|
|
257
|
+
}
|
|
258
|
+
else if (test.language === 'python') {
|
|
259
|
+
extension = 'py';
|
|
260
|
+
}
|
|
261
|
+
// Determine subdirectory based on test type
|
|
262
|
+
let subdir = '';
|
|
263
|
+
if (test.framework === 'playwright') {
|
|
264
|
+
subdir = test.name.includes('API') || test.name.includes('api') ? 'api' : 'ui';
|
|
265
|
+
}
|
|
266
|
+
else if (test.framework === 'k6') {
|
|
267
|
+
subdir = 'performance';
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
subdir = 'unit';
|
|
271
|
+
}
|
|
272
|
+
return `${outputDir}/${subdir}/${name}.${extension}`;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Check if generator is available
|
|
276
|
+
*/
|
|
277
|
+
async isAvailable() {
|
|
278
|
+
return this.provider.isAvailable();
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* List available models
|
|
282
|
+
*/
|
|
283
|
+
async listModels() {
|
|
284
|
+
return this.provider.models;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Convenience function to generate tests
|
|
289
|
+
*/
|
|
290
|
+
export async function generateTests(source, options) {
|
|
291
|
+
const generator = new CodeGenerator(options);
|
|
292
|
+
return generator.generateFromSource(source, {});
|
|
293
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Test Generator - Convenience Functions
|
|
3
|
+
*
|
|
4
|
+
* High-level functions for test generation.
|
|
5
|
+
* These are the main entry points for the generation module.
|
|
6
|
+
*/
|
|
7
|
+
import { type CodeGeneratorOptions, type GenerationResult } from './code-generator.js';
|
|
8
|
+
import { type OptimizationOptions } from './test-optimizer.js';
|
|
9
|
+
import type { GenerationSource } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Generate tests from various sources with optimization
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateTests(source: GenerationSource, options?: CodeGeneratorOptions & {
|
|
14
|
+
optimize?: boolean;
|
|
15
|
+
optimizationOptions?: OptimizationOptions;
|
|
16
|
+
}): Promise<GenerationResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Generate API tests from OpenAPI spec
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateApiTestsFromOpenAPI(specPath: string, options?: CodeGeneratorOptions): Promise<GenerationResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Generate UI tests from URL
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateUiTestsFromUrl(url: string, options?: CodeGeneratorOptions): Promise<GenerationResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Generate performance tests
|
|
27
|
+
*/
|
|
28
|
+
export declare function generatePerfTests(specPath: string, options?: CodeGeneratorOptions): Promise<GenerationResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Generate unit tests from code
|
|
31
|
+
*/
|
|
32
|
+
export declare function generateUnitTests(code: string, language: string, options?: CodeGeneratorOptions): Promise<GenerationResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if Ollama is available for generation
|
|
35
|
+
*/
|
|
36
|
+
export declare function checkGenerationAvailability(): Promise<{
|
|
37
|
+
available: boolean;
|
|
38
|
+
models: string[];
|
|
39
|
+
recommended: string;
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Test Generator - Convenience Functions
|
|
3
|
+
*
|
|
4
|
+
* High-level functions for test generation.
|
|
5
|
+
* These are the main entry points for the generation module.
|
|
6
|
+
*/
|
|
7
|
+
import { CodeGenerator } from './code-generator.js';
|
|
8
|
+
import { TestOptimizer } from './test-optimizer.js';
|
|
9
|
+
/**
|
|
10
|
+
* Generate tests from various sources with optimization
|
|
11
|
+
*/
|
|
12
|
+
export async function generateTests(source, options = {}) {
|
|
13
|
+
const { optimize = false, optimizationOptions, ...generatorOptions } = options;
|
|
14
|
+
// Generate tests
|
|
15
|
+
const generator = new CodeGenerator(generatorOptions);
|
|
16
|
+
let result = await generator.generateFromSource(source, {});
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
// Optimize if requested
|
|
21
|
+
if (optimize) {
|
|
22
|
+
const optimizer = new TestOptimizer(optimizationOptions);
|
|
23
|
+
const optimization = optimizer.optimize(result.tests);
|
|
24
|
+
result.tests = optimization.optimized;
|
|
25
|
+
if (result.warnings) {
|
|
26
|
+
result.warnings.push(...optimization.improvements);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
result.warnings = optimization.improvements;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate API tests from OpenAPI spec
|
|
36
|
+
*/
|
|
37
|
+
export async function generateApiTestsFromOpenAPI(specPath, options) {
|
|
38
|
+
const generator = new CodeGenerator(options);
|
|
39
|
+
return generator.generateFromOpenAPI(specPath, { framework: 'playwright' });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate UI tests from URL
|
|
43
|
+
*/
|
|
44
|
+
export async function generateUiTestsFromUrl(url, options) {
|
|
45
|
+
const generator = new CodeGenerator(options);
|
|
46
|
+
return generator.generateFromUrl(url, { framework: 'playwright' });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate performance tests
|
|
50
|
+
*/
|
|
51
|
+
export async function generatePerfTests(specPath, options) {
|
|
52
|
+
const generator = new CodeGenerator(options);
|
|
53
|
+
return generator.generateFromOpenAPI(specPath, { framework: 'k6' });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate unit tests from code
|
|
57
|
+
*/
|
|
58
|
+
export async function generateUnitTests(code, language, options) {
|
|
59
|
+
const generator = new CodeGenerator(options);
|
|
60
|
+
return generator.generateFromCode(code, language, {
|
|
61
|
+
framework: language === 'typescript' ? 'vitest' : 'jest',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if Ollama is available for generation
|
|
66
|
+
*/
|
|
67
|
+
export async function checkGenerationAvailability() {
|
|
68
|
+
const generator = new CodeGenerator();
|
|
69
|
+
const available = await generator.isAvailable();
|
|
70
|
+
if (!available) {
|
|
71
|
+
return { available: false, models: [], recommended: 'deepseek-coder' };
|
|
72
|
+
}
|
|
73
|
+
const models = await generator.listModels();
|
|
74
|
+
const recommended = models.find(m => m.includes('deepseek') || m.includes('codellama') || m.includes('qwen')) || models[0] || 'deepseek-coder';
|
|
75
|
+
return { available, models, recommended };
|
|
76
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 AI Test Generation Module
|
|
3
|
+
*
|
|
4
|
+
* Generates test code from various sources using LLM.
|
|
5
|
+
* Phase 4 of AI Integration Roadmap.
|
|
6
|
+
*
|
|
7
|
+
* Components:
|
|
8
|
+
* - PromptBuilder: Build effective prompts for LLM
|
|
9
|
+
* - CodeGenerator: Generate test code from prompts
|
|
10
|
+
* - CodeFormatter: Format and validate generated code
|
|
11
|
+
* - TestOptimizer: Optimize generated tests
|
|
12
|
+
* - PackGenerator: Convert specs to QA360 pack YAML
|
|
13
|
+
* - SourceAnalyzer: Analyze source code for test requirements
|
|
14
|
+
*
|
|
15
|
+
* Supported Generators:
|
|
16
|
+
* - Playwright API tests (TypeScript)
|
|
17
|
+
* - Playwright UI tests (TypeScript)
|
|
18
|
+
* - K6 performance tests (JavaScript)
|
|
19
|
+
* - Vitest unit tests (TypeScript)
|
|
20
|
+
*/
|
|
21
|
+
export { PromptBuilder, PromptBuilderOptions, type BuiltPrompt } from './prompt-builder.js';
|
|
22
|
+
export { CodeGenerator, CodeGeneratorOptions, type GeneratedTestInternal, type GenerationResult } from './code-generator.js';
|
|
23
|
+
export { CodeFormatter, FormatterConfig, type FormatResult } from './code-formatter.js';
|
|
24
|
+
export { TestOptimizer, OptimizationOptions, type OptimizationResult } from './test-optimizer.js';
|
|
25
|
+
export { PackGenerator, generatePackFromApiSpec, generatePackFromUiSpec, generatePackFromPerfSpec } from './pack-generator.js';
|
|
26
|
+
export { SourceAnalyzer, analyzeSourceFile, analyzeSourceDirectory, generateTestSpec } from './source-analyzer.js';
|
|
27
|
+
export type { PackGeneratorOptions, PackGenerationResult } from './pack-generator.js';
|
|
28
|
+
export type { SourceAnalysis, SourceAnalyzerOptions, TestSuggestion } from './source-analyzer.js';
|
|
29
|
+
export type { TestSpec, ApiTestSpec, UiTestSpec, PerfTestSpec, UnitTestSpec, GenerationContext, GeneratedTest, GenerationSource, GenerationOptions, } from './types.js';
|
|
30
|
+
export { generateTests, generateApiTestsFromOpenAPI, generateUiTestsFromUrl, generatePerfTests, generateUnitTests, checkGenerationAvailability, } from './generator.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 AI Test Generation Module
|
|
3
|
+
*
|
|
4
|
+
* Generates test code from various sources using LLM.
|
|
5
|
+
* Phase 4 of AI Integration Roadmap.
|
|
6
|
+
*
|
|
7
|
+
* Components:
|
|
8
|
+
* - PromptBuilder: Build effective prompts for LLM
|
|
9
|
+
* - CodeGenerator: Generate test code from prompts
|
|
10
|
+
* - CodeFormatter: Format and validate generated code
|
|
11
|
+
* - TestOptimizer: Optimize generated tests
|
|
12
|
+
* - PackGenerator: Convert specs to QA360 pack YAML
|
|
13
|
+
* - SourceAnalyzer: Analyze source code for test requirements
|
|
14
|
+
*
|
|
15
|
+
* Supported Generators:
|
|
16
|
+
* - Playwright API tests (TypeScript)
|
|
17
|
+
* - Playwright UI tests (TypeScript)
|
|
18
|
+
* - K6 performance tests (JavaScript)
|
|
19
|
+
* - Vitest unit tests (TypeScript)
|
|
20
|
+
*/
|
|
21
|
+
export { PromptBuilder } from './prompt-builder.js';
|
|
22
|
+
export { CodeGenerator } from './code-generator.js';
|
|
23
|
+
export { CodeFormatter } from './code-formatter.js';
|
|
24
|
+
export { TestOptimizer } from './test-optimizer.js';
|
|
25
|
+
export { PackGenerator, generatePackFromApiSpec, generatePackFromUiSpec, generatePackFromPerfSpec } from './pack-generator.js';
|
|
26
|
+
export { SourceAnalyzer, analyzeSourceFile, analyzeSourceDirectory, generateTestSpec } from './source-analyzer.js';
|
|
27
|
+
// Convenience functions
|
|
28
|
+
export { generateTests, generateApiTestsFromOpenAPI, generateUiTestsFromUrl, generatePerfTests, generateUnitTests, checkGenerationAvailability, } from './generator.js';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Pack Generator
|
|
3
|
+
*
|
|
4
|
+
* Converts generated test specifications into QA360 pack YAML format.
|
|
5
|
+
* This bridges the gap between AI-generated tests and runnable QA360 packs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const generator = new PackGenerator();
|
|
10
|
+
* const packYaml = generator.generateFromApiSpec(apiSpec, {
|
|
11
|
+
* name: 'my-api-tests',
|
|
12
|
+
* version: 2
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import { PackConfigV2 } from '../types/pack-v2.js';
|
|
17
|
+
export type { TestSpec, ApiTestSpec, UiTestSpec, PerfTestSpec, UnitTestSpec, } from './types.js';
|
|
18
|
+
import type { TestSpec, ApiTestSpec, UiTestSpec, PerfTestSpec } from './types.js';
|
|
19
|
+
/**
|
|
20
|
+
* Pack generator options
|
|
21
|
+
*/
|
|
22
|
+
export interface PackGeneratorOptions {
|
|
23
|
+
/** Pack name */
|
|
24
|
+
name?: string;
|
|
25
|
+
/** Pack version (1 or 2) */
|
|
26
|
+
version?: 1 | 2;
|
|
27
|
+
/** Pack description */
|
|
28
|
+
description?: string;
|
|
29
|
+
/** Default timeout for tests */
|
|
30
|
+
timeout?: number;
|
|
31
|
+
/** Default retries */
|
|
32
|
+
retries?: number;
|
|
33
|
+
/** On failure behavior */
|
|
34
|
+
onFailure?: 'stop' | 'continue';
|
|
35
|
+
/** Include cache configuration */
|
|
36
|
+
enableCache?: boolean;
|
|
37
|
+
/** Cache TTL in milliseconds */
|
|
38
|
+
cacheTtl?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generated pack result
|
|
42
|
+
*/
|
|
43
|
+
export interface PackGenerationResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
yaml: string;
|
|
46
|
+
config: PackConfigV2;
|
|
47
|
+
warnings?: string[];
|
|
48
|
+
errors?: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pack Generator
|
|
52
|
+
*
|
|
53
|
+
* Converts test specifications into QA360 pack YAML format.
|
|
54
|
+
*/
|
|
55
|
+
export declare class PackGenerator {
|
|
56
|
+
private readonly defaults;
|
|
57
|
+
constructor(options?: PackGeneratorOptions);
|
|
58
|
+
/**
|
|
59
|
+
* Generate pack from API test specification
|
|
60
|
+
*/
|
|
61
|
+
generateFromApiSpec(spec: ApiTestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|
|
62
|
+
/**
|
|
63
|
+
* Generate pack from UI test specification
|
|
64
|
+
*/
|
|
65
|
+
generateFromUiSpec(spec: UiTestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|
|
66
|
+
/**
|
|
67
|
+
* Generate pack from performance test specification
|
|
68
|
+
*/
|
|
69
|
+
generateFromPerfSpec(spec: PerfTestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|
|
70
|
+
/**
|
|
71
|
+
* Generate pack from generic test specification
|
|
72
|
+
*/
|
|
73
|
+
generateFromSpec(spec: TestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|
|
74
|
+
/**
|
|
75
|
+
* Format endpoint as smoke test spec
|
|
76
|
+
*/
|
|
77
|
+
private formatEndpointSpec;
|
|
78
|
+
/**
|
|
79
|
+
* Format page action
|
|
80
|
+
*/
|
|
81
|
+
private formatPageAction;
|
|
82
|
+
/**
|
|
83
|
+
* Extract threshold value from thresholds array
|
|
84
|
+
*/
|
|
85
|
+
private extractThreshold;
|
|
86
|
+
/**
|
|
87
|
+
* Convert config to YAML string
|
|
88
|
+
* Note: This is a simple YAML generator. For production, use a proper YAML library.
|
|
89
|
+
*/
|
|
90
|
+
private toYaml;
|
|
91
|
+
/**
|
|
92
|
+
* Helper to indent object properties
|
|
93
|
+
*/
|
|
94
|
+
private indentObject;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Convenience function to generate pack from API spec
|
|
98
|
+
*/
|
|
99
|
+
export declare function generatePackFromApiSpec(spec: ApiTestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|
|
100
|
+
/**
|
|
101
|
+
* Convenience function to generate pack from UI spec
|
|
102
|
+
*/
|
|
103
|
+
export declare function generatePackFromUiSpec(spec: UiTestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|
|
104
|
+
/**
|
|
105
|
+
* Convenience function to generate pack from performance spec
|
|
106
|
+
*/
|
|
107
|
+
export declare function generatePackFromPerfSpec(spec: PerfTestSpec, options?: PackGeneratorOptions): PackGenerationResult;
|