qa360 1.4.5 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/ai.d.ts +41 -0
  3. package/dist/commands/ai.js +499 -0
  4. package/dist/commands/ask.js +12 -12
  5. package/dist/commands/coverage.d.ts +8 -0
  6. package/dist/commands/coverage.js +252 -0
  7. package/dist/commands/explain.d.ts +27 -0
  8. package/dist/commands/explain.js +630 -0
  9. package/dist/commands/flakiness.d.ts +73 -0
  10. package/dist/commands/flakiness.js +435 -0
  11. package/dist/commands/generate.d.ts +66 -0
  12. package/dist/commands/generate.js +438 -0
  13. package/dist/commands/init.d.ts +56 -9
  14. package/dist/commands/init.js +217 -10
  15. package/dist/commands/monitor.d.ts +27 -0
  16. package/dist/commands/monitor.js +225 -0
  17. package/dist/commands/ollama.d.ts +40 -0
  18. package/dist/commands/ollama.js +301 -0
  19. package/dist/commands/pack.d.ts +37 -9
  20. package/dist/commands/pack.js +240 -141
  21. package/dist/commands/regression.d.ts +8 -0
  22. package/dist/commands/regression.js +340 -0
  23. package/dist/commands/repair.d.ts +26 -0
  24. package/dist/commands/repair.js +307 -0
  25. package/dist/commands/retry.d.ts +43 -0
  26. package/dist/commands/retry.js +275 -0
  27. package/dist/commands/run.d.ts +8 -3
  28. package/dist/commands/run.js +45 -31
  29. package/dist/commands/slo.d.ts +8 -0
  30. package/dist/commands/slo.js +327 -0
  31. package/dist/core/adapters/playwright-native-api.d.ts +183 -0
  32. package/dist/core/adapters/playwright-native-api.js +461 -0
  33. package/dist/core/adapters/playwright-ui.d.ts +7 -0
  34. package/dist/core/adapters/playwright-ui.js +29 -1
  35. package/dist/core/ai/anthropic-provider.d.ts +50 -0
  36. package/dist/core/ai/anthropic-provider.js +211 -0
  37. package/dist/core/ai/deepseek-provider.d.ts +81 -0
  38. package/dist/core/ai/deepseek-provider.js +254 -0
  39. package/dist/core/ai/index.d.ts +60 -0
  40. package/dist/core/ai/index.js +18 -0
  41. package/dist/core/ai/llm-client.d.ts +45 -0
  42. package/dist/core/ai/llm-client.js +7 -0
  43. package/dist/core/ai/mock-provider.d.ts +49 -0
  44. package/dist/core/ai/mock-provider.js +121 -0
  45. package/dist/core/ai/ollama-provider.d.ts +78 -0
  46. package/dist/core/ai/ollama-provider.js +192 -0
  47. package/dist/core/ai/openai-provider.d.ts +48 -0
  48. package/dist/core/ai/openai-provider.js +188 -0
  49. package/dist/core/ai/provider-factory.d.ts +160 -0
  50. package/dist/core/ai/provider-factory.js +269 -0
  51. package/dist/core/auth/api-key-provider.d.ts +16 -0
  52. package/dist/core/auth/api-key-provider.js +63 -0
  53. package/dist/core/auth/aws-iam-provider.d.ts +35 -0
  54. package/dist/core/auth/aws-iam-provider.js +177 -0
  55. package/dist/core/auth/azure-ad-provider.d.ts +15 -0
  56. package/dist/core/auth/azure-ad-provider.js +99 -0
  57. package/dist/core/auth/basic-auth-provider.d.ts +26 -0
  58. package/dist/core/auth/basic-auth-provider.js +111 -0
  59. package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
  60. package/dist/core/auth/gcp-adc-provider.js +126 -0
  61. package/dist/core/auth/index.d.ts +238 -0
  62. package/dist/core/auth/index.js +82 -0
  63. package/dist/core/auth/jwt-provider.d.ts +19 -0
  64. package/dist/core/auth/jwt-provider.js +160 -0
  65. package/dist/core/auth/manager.d.ts +84 -0
  66. package/dist/core/auth/manager.js +230 -0
  67. package/dist/core/auth/oauth2-provider.d.ts +17 -0
  68. package/dist/core/auth/oauth2-provider.js +114 -0
  69. package/dist/core/auth/totp-provider.d.ts +31 -0
  70. package/dist/core/auth/totp-provider.js +134 -0
  71. package/dist/core/auth/ui-login-provider.d.ts +26 -0
  72. package/dist/core/auth/ui-login-provider.js +198 -0
  73. package/dist/core/cache/index.d.ts +7 -0
  74. package/dist/core/cache/index.js +6 -0
  75. package/dist/core/cache/lru-cache.d.ts +203 -0
  76. package/dist/core/cache/lru-cache.js +397 -0
  77. package/dist/core/coverage/analyzer.d.ts +101 -0
  78. package/dist/core/coverage/analyzer.js +415 -0
  79. package/dist/core/coverage/collector.d.ts +74 -0
  80. package/dist/core/coverage/collector.js +459 -0
  81. package/dist/core/coverage/config.d.ts +37 -0
  82. package/dist/core/coverage/config.js +156 -0
  83. package/dist/core/coverage/index.d.ts +11 -0
  84. package/dist/core/coverage/index.js +15 -0
  85. package/dist/core/coverage/types.d.ts +267 -0
  86. package/dist/core/coverage/types.js +6 -0
  87. package/dist/core/coverage/vault.d.ts +95 -0
  88. package/dist/core/coverage/vault.js +405 -0
  89. package/dist/core/dashboard/assets.d.ts +6 -0
  90. package/dist/core/dashboard/assets.js +690 -0
  91. package/dist/core/dashboard/index.d.ts +6 -0
  92. package/dist/core/dashboard/index.js +5 -0
  93. package/dist/core/dashboard/server.d.ts +72 -0
  94. package/dist/core/dashboard/server.js +354 -0
  95. package/dist/core/dashboard/types.d.ts +70 -0
  96. package/dist/core/dashboard/types.js +5 -0
  97. package/dist/core/discoverer/index.d.ts +115 -0
  98. package/dist/core/discoverer/index.js +250 -0
  99. package/dist/core/flakiness/index.d.ts +228 -0
  100. package/dist/core/flakiness/index.js +384 -0
  101. package/dist/core/generation/code-formatter.d.ts +111 -0
  102. package/dist/core/generation/code-formatter.js +307 -0
  103. package/dist/core/generation/code-generator.d.ts +144 -0
  104. package/dist/core/generation/code-generator.js +293 -0
  105. package/dist/core/generation/generator.d.ts +40 -0
  106. package/dist/core/generation/generator.js +76 -0
  107. package/dist/core/generation/index.d.ts +30 -0
  108. package/dist/core/generation/index.js +28 -0
  109. package/dist/core/generation/pack-generator.d.ts +107 -0
  110. package/dist/core/generation/pack-generator.js +416 -0
  111. package/dist/core/generation/prompt-builder.d.ts +132 -0
  112. package/dist/core/generation/prompt-builder.js +672 -0
  113. package/dist/core/generation/source-analyzer.d.ts +213 -0
  114. package/dist/core/generation/source-analyzer.js +657 -0
  115. package/dist/core/generation/test-optimizer.d.ts +117 -0
  116. package/dist/core/generation/test-optimizer.js +328 -0
  117. package/dist/core/generation/types.d.ts +214 -0
  118. package/dist/core/generation/types.js +4 -0
  119. package/dist/core/index.d.ts +23 -1
  120. package/dist/core/index.js +39 -0
  121. package/dist/core/pack/validator.js +31 -1
  122. package/dist/core/pack-v2/index.d.ts +9 -0
  123. package/dist/core/pack-v2/index.js +8 -0
  124. package/dist/core/pack-v2/loader.d.ts +62 -0
  125. package/dist/core/pack-v2/loader.js +231 -0
  126. package/dist/core/pack-v2/migrator.d.ts +56 -0
  127. package/dist/core/pack-v2/migrator.js +455 -0
  128. package/dist/core/pack-v2/validator.d.ts +61 -0
  129. package/dist/core/pack-v2/validator.js +577 -0
  130. package/dist/core/regression/detector.d.ts +107 -0
  131. package/dist/core/regression/detector.js +497 -0
  132. package/dist/core/regression/index.d.ts +9 -0
  133. package/dist/core/regression/index.js +11 -0
  134. package/dist/core/regression/trend-analyzer.d.ts +102 -0
  135. package/dist/core/regression/trend-analyzer.js +345 -0
  136. package/dist/core/regression/types.d.ts +222 -0
  137. package/dist/core/regression/types.js +7 -0
  138. package/dist/core/regression/vault.d.ts +87 -0
  139. package/dist/core/regression/vault.js +289 -0
  140. package/dist/core/repair/engine/fixer.d.ts +24 -0
  141. package/dist/core/repair/engine/fixer.js +226 -0
  142. package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
  143. package/dist/core/repair/engine/suggestion-engine.js +187 -0
  144. package/dist/core/repair/index.d.ts +10 -0
  145. package/dist/core/repair/index.js +13 -0
  146. package/dist/core/repair/repairer.d.ts +90 -0
  147. package/dist/core/repair/repairer.js +284 -0
  148. package/dist/core/repair/types.d.ts +91 -0
  149. package/dist/core/repair/types.js +6 -0
  150. package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
  151. package/dist/core/repair/utils/error-analyzer.js +264 -0
  152. package/dist/core/retry/flakiness-integration.d.ts +60 -0
  153. package/dist/core/retry/flakiness-integration.js +228 -0
  154. package/dist/core/retry/index.d.ts +14 -0
  155. package/dist/core/retry/index.js +16 -0
  156. package/dist/core/retry/retry-engine.d.ts +80 -0
  157. package/dist/core/retry/retry-engine.js +296 -0
  158. package/dist/core/retry/types.d.ts +178 -0
  159. package/dist/core/retry/types.js +52 -0
  160. package/dist/core/retry/vault.d.ts +77 -0
  161. package/dist/core/retry/vault.js +304 -0
  162. package/dist/core/runner/e2e-helpers.d.ts +102 -0
  163. package/dist/core/runner/e2e-helpers.js +153 -0
  164. package/dist/core/runner/phase3-runner.d.ts +101 -2
  165. package/dist/core/runner/phase3-runner.js +559 -24
  166. package/dist/core/self-healing/assertion-healer.d.ts +97 -0
  167. package/dist/core/self-healing/assertion-healer.js +371 -0
  168. package/dist/core/self-healing/engine.d.ts +122 -0
  169. package/dist/core/self-healing/engine.js +538 -0
  170. package/dist/core/self-healing/index.d.ts +10 -0
  171. package/dist/core/self-healing/index.js +11 -0
  172. package/dist/core/self-healing/selector-healer.d.ts +103 -0
  173. package/dist/core/self-healing/selector-healer.js +372 -0
  174. package/dist/core/self-healing/types.d.ts +152 -0
  175. package/dist/core/self-healing/types.js +6 -0
  176. package/dist/core/slo/config.d.ts +107 -0
  177. package/dist/core/slo/config.js +360 -0
  178. package/dist/core/slo/index.d.ts +11 -0
  179. package/dist/core/slo/index.js +15 -0
  180. package/dist/core/slo/sli-calculator.d.ts +92 -0
  181. package/dist/core/slo/sli-calculator.js +364 -0
  182. package/dist/core/slo/slo-tracker.d.ts +148 -0
  183. package/dist/core/slo/slo-tracker.js +379 -0
  184. package/dist/core/slo/types.d.ts +281 -0
  185. package/dist/core/slo/types.js +7 -0
  186. package/dist/core/slo/vault.d.ts +102 -0
  187. package/dist/core/slo/vault.js +427 -0
  188. package/dist/core/tui/index.d.ts +7 -0
  189. package/dist/core/tui/index.js +6 -0
  190. package/dist/core/tui/monitor.d.ts +92 -0
  191. package/dist/core/tui/monitor.js +271 -0
  192. package/dist/core/tui/renderer.d.ts +33 -0
  193. package/dist/core/tui/renderer.js +218 -0
  194. package/dist/core/tui/types.d.ts +63 -0
  195. package/dist/core/tui/types.js +5 -0
  196. package/dist/core/types/pack-v2.d.ts +425 -0
  197. package/dist/core/types/pack-v2.js +8 -0
  198. package/dist/core/vault/index.d.ts +116 -0
  199. package/dist/core/vault/index.js +400 -5
  200. package/dist/core/watch/index.d.ts +7 -0
  201. package/dist/core/watch/index.js +6 -0
  202. package/dist/core/watch/watch-mode.d.ts +213 -0
  203. package/dist/core/watch/watch-mode.js +389 -0
  204. package/dist/index.js +68 -68
  205. package/dist/utils/config.d.ts +5 -0
  206. package/dist/utils/config.js +136 -0
  207. package/package.json +5 -1
  208. package/dist/core/adapters/playwright-api.d.ts +0 -82
  209. package/dist/core/adapters/playwright-api.js +0 -264
@@ -0,0 +1,438 @@
1
+ /**
2
+ * QA360 Generate Command
3
+ *
4
+ * AI-powered test generation using Ollama.
5
+ * Generates tests from OpenAPI specs, HAR files, URLs, or code.
6
+ *
7
+ * Phase 4 - AI Test Generation
8
+ */
9
+ import { Command } from 'commander';
10
+ import chalk from 'chalk';
11
+ import ora from 'ora';
12
+ import { writeFileSync, mkdirSync, existsSync } from 'fs';
13
+ import { dirname, resolve } from 'path';
14
+ import { generateTests, generateApiTestsFromOpenAPI, generateUiTestsFromUrl, generatePerfTests, generateUnitTests, checkGenerationAvailability, } from '../core/index.js';
15
+ /**
16
+ * Create generate commands group
17
+ */
18
+ export function createGenerateCommands() {
19
+ const generateCmd = new Command('generate')
20
+ .description('AI-powered test generation (Phase 4)');
21
+ // Main generate command
22
+ generateCmd
23
+ .argument('<source>', 'Source: OpenAPI spec, HAR file, URL, or description')
24
+ .option('--type <type>', 'Source type: openapi, har, url, code')
25
+ .option('-o, --output <dir>', 'Output directory', './tests/generated')
26
+ .option('--framework <name>', 'Target framework: playwright, k6, vitest, jest')
27
+ .option('--model <name>', 'Ollama model to use')
28
+ .option('--optimize', 'Optimize generated tests')
29
+ .option('--no-format', 'Skip code formatting')
30
+ .action(async (source, options) => {
31
+ await generateCommand(source, options);
32
+ });
33
+ // API tests subcommand
34
+ generateCmd
35
+ .command('api <spec>')
36
+ .description('Generate API tests from OpenAPI spec')
37
+ .option('-o, --output <dir>', 'Output directory', './tests/api')
38
+ .option('--model <name>', 'Ollama model to use')
39
+ .option('--optimize', 'Optimize generated tests')
40
+ .action(async (spec, options) => {
41
+ await generateApiCommand(spec, options);
42
+ });
43
+ // UI tests subcommand
44
+ generateCmd
45
+ .command('ui <url>')
46
+ .description('Generate UI tests from URL')
47
+ .option('-o, --output <dir>', 'Output directory', './tests/ui')
48
+ .option('--model <name>', 'Ollama model to use')
49
+ .option('--optimize', 'Optimize generated tests')
50
+ .action(async (url, options) => {
51
+ await generateUiCommand(url, options);
52
+ });
53
+ // Performance tests subcommand
54
+ generateCmd
55
+ .command('perf <spec>')
56
+ .description('Generate performance tests from OpenAPI spec')
57
+ .option('-o, --output <dir>', 'Output directory', './tests/performance')
58
+ .option('--model <name>', 'Ollama model to use')
59
+ .option('--duration <time>', 'Test duration', '30s')
60
+ .option('--vus <number>', 'Virtual users', '10')
61
+ .action(async (spec, options) => {
62
+ await generatePerfCommand(spec, options);
63
+ });
64
+ // Unit tests subcommand
65
+ generateCmd
66
+ .command('unit <file>')
67
+ .description('Generate unit tests from source code')
68
+ .option('-l, --language <lang>', 'Source language (typescript, javascript, go, python)')
69
+ .option('-o, --output <dir>', 'Output directory', './tests/unit')
70
+ .option('--model <name>', 'Ollama model to use')
71
+ .option('--optimize', 'Optimize generated tests')
72
+ .action(async (file, options) => {
73
+ await generateUnitCommand(file, options);
74
+ });
75
+ // Check availability subcommand
76
+ generateCmd
77
+ .command('check')
78
+ .description('Check if Ollama is available for generation')
79
+ .action(async () => {
80
+ await checkCommand();
81
+ });
82
+ return generateCmd;
83
+ }
84
+ /**
85
+ * Generate tests command handler
86
+ */
87
+ export async function generateCommand(source, options = {}) {
88
+ const spinner = ora('Initializing QA360 AI Test Generator...').start();
89
+ try {
90
+ // Check Ollama availability
91
+ const { available, models, recommended } = await checkGenerationAvailability();
92
+ if (!available) {
93
+ spinner.fail('Ollama not available');
94
+ console.log(chalk.red('\nOllama is not running'));
95
+ console.log(chalk.yellow('\nStart Ollama:'));
96
+ console.log(chalk.gray(' ollama serve'));
97
+ console.log(chalk.yellow('\nInstall Ollama:'));
98
+ console.log(chalk.gray(' brew install ollama # macOS'));
99
+ console.log(chalk.gray(' # Or visit: https://ollama.com\n'));
100
+ return;
101
+ }
102
+ spinner.succeed('Connected to Ollama');
103
+ // Show using model
104
+ console.log(chalk.gray(`Using: ${options.model || recommended}\n`));
105
+ // Determine source type
106
+ const sourceType = options.type || detectSourceType(source);
107
+ // Build generation source
108
+ const generationSource = buildGenerationSource(source, sourceType, options);
109
+ // Generate tests
110
+ const genSpinner = ora(`Generating ${sourceType} tests...`).start();
111
+ const result = await generateTests(generationSource, {
112
+ model: options.model,
113
+ outputDir: options.output || './tests/generated',
114
+ formatCode: options.format !== false,
115
+ optimize: options.optimize,
116
+ promptOptions: {
117
+ includeComments: true,
118
+ includeDetailedAssertions: true,
119
+ includeRetryLogic: true,
120
+ codeStyle: 'clean',
121
+ },
122
+ });
123
+ if (!result.success) {
124
+ genSpinner.fail('Generation failed');
125
+ console.log(chalk.red('\nErrors:'));
126
+ for (const error of result.errors || []) {
127
+ console.log(chalk.red(` - ${error}`));
128
+ }
129
+ return;
130
+ }
131
+ genSpinner.succeed(`Generated ${result.tests.length} test files\n`);
132
+ // Save tests
133
+ const savedFiles = await saveTests(result.tests, options.output);
134
+ // Show summary
135
+ showGenerationSummary(result, savedFiles);
136
+ if (result.warnings && result.warnings.length > 0) {
137
+ console.log(chalk.yellow('\nWarnings:'));
138
+ for (const warning of result.warnings) {
139
+ console.log(chalk.yellow(` - ${warning}`));
140
+ }
141
+ }
142
+ console.log(chalk.green('\nTest generation complete!'));
143
+ }
144
+ catch (error) {
145
+ spinner.fail('Generation error');
146
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
147
+ }
148
+ }
149
+ /**
150
+ * Generate API tests from OpenAPI spec
151
+ */
152
+ export async function generateApiCommand(specPath, options = {}) {
153
+ const spinner = ora('Generating API tests from OpenAPI spec...').start();
154
+ try {
155
+ const result = await generateApiTestsFromOpenAPI(specPath, {
156
+ model: options.model,
157
+ outputDir: options.output || './tests/api',
158
+ formatCode: true,
159
+ optimize: options.optimize,
160
+ });
161
+ if (!result.success) {
162
+ spinner.fail('Generation failed');
163
+ for (const error of result.errors || []) {
164
+ console.log(chalk.red(` - ${error}`));
165
+ }
166
+ return;
167
+ }
168
+ spinner.succeed(`Generated ${result.tests.length} API test files\n`);
169
+ const savedFiles = await saveTests(result.tests, options.output || './tests/api');
170
+ showGenerationSummary(result, savedFiles);
171
+ }
172
+ catch (error) {
173
+ spinner.fail('Generation error');
174
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
175
+ }
176
+ }
177
+ /**
178
+ * Generate UI tests from URL
179
+ */
180
+ export async function generateUiCommand(url, options = {}) {
181
+ const spinner = ora('Generating UI tests from URL...').start();
182
+ try {
183
+ const result = await generateUiTestsFromUrl(url, {
184
+ model: options.model,
185
+ outputDir: options.output || './tests/ui',
186
+ formatCode: true,
187
+ optimize: options.optimize,
188
+ });
189
+ if (!result.success) {
190
+ spinner.fail('Generation failed');
191
+ for (const error of result.errors || []) {
192
+ console.log(chalk.red(` - ${error}`));
193
+ }
194
+ return;
195
+ }
196
+ spinner.succeed(`Generated ${result.tests.length} UI test files\n`);
197
+ const savedFiles = await saveTests(result.tests, options.output || './tests/ui');
198
+ showGenerationSummary(result, savedFiles);
199
+ }
200
+ catch (error) {
201
+ spinner.fail('Generation error');
202
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
203
+ }
204
+ }
205
+ /**
206
+ * Generate performance tests
207
+ */
208
+ export async function generatePerfCommand(specPath, options = {}) {
209
+ const spinner = ora('Generating performance tests...').start();
210
+ try {
211
+ const result = await generatePerfTests(specPath, {
212
+ model: options.model,
213
+ outputDir: options.output || './tests/performance',
214
+ formatCode: true,
215
+ optimize: false, // Don't optimize perf tests
216
+ });
217
+ if (!result.success) {
218
+ spinner.fail('Generation failed');
219
+ for (const error of result.errors || []) {
220
+ console.log(chalk.red(` - ${error}`));
221
+ }
222
+ return;
223
+ }
224
+ spinner.succeed(`Generated ${result.tests.length} performance test files\n`);
225
+ const savedFiles = await saveTests(result.tests, options.output || './tests/performance');
226
+ showGenerationSummary(result, savedFiles);
227
+ }
228
+ catch (error) {
229
+ spinner.fail('Generation error');
230
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
231
+ }
232
+ }
233
+ /**
234
+ * Generate unit tests from code
235
+ */
236
+ export async function generateUnitCommand(filePath, options = {}) {
237
+ const spinner = ora('Generating unit tests...').start();
238
+ try {
239
+ // Read source code
240
+ const { readFileSync } = await import('fs');
241
+ const code = readFileSync(filePath, 'utf-8');
242
+ const language = options.language || detectLanguage(filePath);
243
+ const result = await generateUnitTests(code, language, {
244
+ model: options.model,
245
+ outputDir: options.output || './tests/unit',
246
+ formatCode: true,
247
+ optimize: options.optimize,
248
+ });
249
+ if (!result.success) {
250
+ spinner.fail('Generation failed');
251
+ for (const error of result.errors || []) {
252
+ console.log(chalk.red(` - ${error}`));
253
+ }
254
+ return;
255
+ }
256
+ spinner.succeed(`Generated ${result.tests.length} unit test files\n`);
257
+ const savedFiles = await saveTests(result.tests, options.output || './tests/unit');
258
+ showGenerationSummary(result, savedFiles);
259
+ }
260
+ catch (error) {
261
+ spinner.fail('Generation error');
262
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
263
+ }
264
+ }
265
+ /**
266
+ * Detect source type from string
267
+ */
268
+ function detectSourceType(source) {
269
+ if (source.endsWith('.json') || source.endsWith('.yaml') || source.endsWith('.yml')) {
270
+ return 'openapi';
271
+ }
272
+ if (source.endsWith('.har')) {
273
+ return 'har';
274
+ }
275
+ if (source.startsWith('http://') || source.startsWith('https://')) {
276
+ return 'url';
277
+ }
278
+ return 'code';
279
+ }
280
+ /**
281
+ * Detect language from file path
282
+ */
283
+ function detectLanguage(filePath) {
284
+ const ext = filePath.split('.').pop()?.toLowerCase();
285
+ const languageMap = {
286
+ 'ts': 'typescript',
287
+ 'tsx': 'typescript',
288
+ 'js': 'javascript',
289
+ 'jsx': 'javascript',
290
+ 'go': 'go',
291
+ 'py': 'python',
292
+ 'rs': 'rust',
293
+ };
294
+ return languageMap[ext || ''] || 'typescript';
295
+ }
296
+ /**
297
+ * Build generation source from input
298
+ */
299
+ function buildGenerationSource(source, type, options) {
300
+ switch (type) {
301
+ case 'openapi':
302
+ return { type: 'openapi', urlOrPath: source };
303
+ case 'har':
304
+ return { type: 'har', filePath: source };
305
+ case 'url':
306
+ return { type: 'url', url: source };
307
+ case 'code':
308
+ return { type: 'description', description: source };
309
+ default:
310
+ return { type: 'description', description: source };
311
+ }
312
+ }
313
+ /**
314
+ * Save generated tests to files
315
+ */
316
+ async function saveTests(tests, outputDir) {
317
+ const savedFiles = [];
318
+ for (const test of tests) {
319
+ const filePath = resolve(test.filePath);
320
+ // Create directory if needed
321
+ const dir = dirname(filePath);
322
+ if (!existsSync(dir)) {
323
+ mkdirSync(dir, { recursive: true });
324
+ }
325
+ // Write file
326
+ writeFileSync(filePath, test.code, 'utf-8');
327
+ savedFiles.push(filePath);
328
+ }
329
+ return savedFiles;
330
+ }
331
+ /**
332
+ * Show generation summary
333
+ */
334
+ function showGenerationSummary(result, savedFiles) {
335
+ console.log(chalk.bold('\nGeneration Summary\n'));
336
+ // Metadata
337
+ console.log(chalk.gray(` Duration: ${result.metadata.duration}ms`));
338
+ console.log(chalk.gray(` Tokens: ${result.metadata.tokensUsed}\n`));
339
+ // Tests
340
+ console.log(chalk.bold(' Generated Tests:'));
341
+ let totalTests = 0;
342
+ let totalAssertions = 0;
343
+ for (const test of result.tests) {
344
+ console.log(chalk.cyan(` - ${test.name}`));
345
+ console.log(chalk.gray(` Framework: ${test.framework}`));
346
+ console.log(chalk.gray(` Language: ${test.language}`));
347
+ console.log(chalk.gray(` Tests: ${test.summary.testCount}`));
348
+ if (test.summary.assertionCount) {
349
+ console.log(chalk.gray(` Assertions: ${test.summary.assertionCount}`));
350
+ }
351
+ console.log(chalk.gray(` Lines: ${test.summary.lines}`));
352
+ console.log(chalk.gray(` File: ${test.filePath}\n`));
353
+ totalTests += test.summary.testCount || 0;
354
+ totalAssertions += test.summary.assertionCount || 0;
355
+ }
356
+ console.log(chalk.bold(' Totals:'));
357
+ console.log(chalk.green(` Files: ${result.tests.length}`));
358
+ console.log(chalk.green(` Test Cases: ${totalTests}`));
359
+ console.log(chalk.green(` Assertions: ${totalAssertions}\n`));
360
+ // Saved files
361
+ console.log(chalk.bold(' Saved Files:'));
362
+ for (const file of savedFiles) {
363
+ console.log(chalk.gray(` - ${file}`));
364
+ }
365
+ console.log('');
366
+ }
367
+ /**
368
+ * Build system prompt for test type
369
+ */
370
+ export function buildSystemPrompt(type) {
371
+ const prompts = {
372
+ api: `You are an expert API test generator. Generate comprehensive Playwright API tests in TypeScript.
373
+
374
+ Requirements:
375
+ - Use test.describe() for grouping
376
+ - Include happy path and error cases
377
+ - Add proper assertions for status codes and response schemas
378
+ - Handle authentication properly
379
+ - Use fetch() or axios for HTTP requests`,
380
+ ui: `You are an expert UI/E2E test generator. Generate comprehensive Playwright UI tests in TypeScript.
381
+
382
+ Requirements:
383
+ - Use test.describe() for grouping
384
+ - Include page object pattern where appropriate
385
+ - Add explicit waits (waitForSelector, waitForURL)
386
+ - Test user interactions and assertions
387
+ - Handle dynamic content properly`,
388
+ perf: `You are an expert performance test generator. Generate K6 performance tests in JavaScript.
389
+
390
+ Requirements:
391
+ - Define realistic scenarios
392
+ - Add thresholds for response times
393
+ - Use proper load stages (ramp up, sustain, ramp down)
394
+ - Include error rate checks
395
+ - Model realistic user behavior`,
396
+ unit: `You are an expert unit test generator. Generate Vitest tests in TypeScript.
397
+
398
+ Requirements:
399
+ - Test all functions/classes
400
+ - Include edge cases and error conditions
401
+ - Mock external dependencies
402
+ - Use describe/it blocks
403
+ - Aim for high coverage`,
404
+ };
405
+ return prompts[type] || prompts.api;
406
+ }
407
+ /**
408
+ * Check if generation is available
409
+ */
410
+ export async function checkCommand() {
411
+ const spinner = ora('Checking AI generation availability...').start();
412
+ try {
413
+ const { available, models, recommended } = await checkGenerationAvailability();
414
+ if (!available) {
415
+ spinner.fail('Ollama not available');
416
+ console.log(chalk.red('\nOllama is not running'));
417
+ console.log(chalk.yellow('\nStart Ollama:'));
418
+ console.log(chalk.gray(' ollama serve'));
419
+ console.log(chalk.yellow('\nInstall Ollama:'));
420
+ console.log(chalk.gray(' brew install ollama # macOS'));
421
+ console.log(chalk.gray(' # Or visit: https://ollama.com\n'));
422
+ return;
423
+ }
424
+ spinner.succeed('AI generation is available!\n');
425
+ console.log(chalk.bold(' Available Models:'));
426
+ for (const model of models) {
427
+ const isRecommended = model === recommended || model.includes(recommended);
428
+ const icon = isRecommended ? '*' : ' ';
429
+ const color = isRecommended ? chalk.green : chalk.gray;
430
+ console.log(color(` ${icon} ${model}`));
431
+ }
432
+ console.log(chalk.green(`\nReady to generate tests using: ${recommended}\n`));
433
+ }
434
+ catch (error) {
435
+ spinner.fail('Availability check failed');
436
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
437
+ }
438
+ }
@@ -5,6 +5,7 @@
5
5
  * qa360 init
6
6
  * qa360 init --template api-basic
7
7
  * qa360 init --output custom-pack.yml
8
+ * qa360 init --beginner # Guided mode for first-time users
8
9
  */
9
10
  /**
10
11
  * CLI options for init command
@@ -14,6 +15,7 @@ export interface InitOptions {
14
15
  output?: string;
15
16
  force?: boolean;
16
17
  yes?: boolean;
18
+ beginner?: boolean;
17
19
  }
18
20
  /**
19
21
  * Available templates
@@ -23,40 +25,85 @@ export declare const TEMPLATES: {
23
25
  name: string;
24
26
  description: string;
25
27
  gates: string[];
28
+ icon: string;
26
29
  };
27
30
  'ui-basic': {
28
31
  name: string;
29
32
  description: string;
30
33
  gates: string[];
34
+ icon: string;
31
35
  };
32
36
  fullstack: {
33
37
  name: string;
34
38
  description: string;
35
39
  gates: string[];
40
+ icon: string;
36
41
  };
37
42
  security: {
38
43
  name: string;
39
44
  description: string;
40
45
  gates: string[];
46
+ icon: string;
41
47
  };
42
48
  complete: {
43
49
  name: string;
44
50
  description: string;
45
51
  gates: string[];
52
+ icon: string;
46
53
  };
47
54
  };
48
55
  /**
49
- * Gate descriptions
56
+ * Gate descriptions with beginner-friendly explanations
50
57
  */
51
58
  export declare const GATE_DESCRIPTIONS: {
52
- api_smoke: string;
53
- ui: string;
54
- a11y: string;
55
- perf: string;
56
- sast: string;
57
- dast: string;
58
- secrets: string;
59
- deps: string;
59
+ api_smoke: {
60
+ short: string;
61
+ beginner: string;
62
+ example: string;
63
+ icon: string;
64
+ };
65
+ ui: {
66
+ short: string;
67
+ beginner: string;
68
+ example: string;
69
+ icon: string;
70
+ };
71
+ a11y: {
72
+ short: string;
73
+ beginner: string;
74
+ example: string;
75
+ icon: string;
76
+ };
77
+ perf: {
78
+ short: string;
79
+ beginner: string;
80
+ example: string;
81
+ icon: string;
82
+ };
83
+ sast: {
84
+ short: string;
85
+ beginner: string;
86
+ example: string;
87
+ icon: string;
88
+ };
89
+ dast: {
90
+ short: string;
91
+ beginner: string;
92
+ example: string;
93
+ icon: string;
94
+ };
95
+ secrets: {
96
+ short: string;
97
+ beginner: string;
98
+ example: string;
99
+ icon: string;
100
+ };
101
+ deps: {
102
+ short: string;
103
+ beginner: string;
104
+ example: string;
105
+ icon: string;
106
+ };
60
107
  };
61
108
  /**
62
109
  * Main init command