diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 367bb412..ecb748c8 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -54,7 +54,7 @@ class ResponseDetails extends ConsumerWidget { .watch(selectedRequestModelProvider.select((value) => value?.message)); final responseModel = ref.watch(selectedRequestModelProvider .select((value) => value?.httpResponseModel)); - + return Column( children: [ ResponsePaneHeader( diff --git a/lib/services/ollama_service.dart b/lib/services/ollama_service.dart index fccade4d..e6e005bb 100644 --- a/lib/services/ollama_service.dart +++ b/lib/services/ollama_service.dart @@ -136,7 +136,6 @@ here is an example test case for the given:$exampleParams return generateResponse(prompt); } - /// Generate example parameter values based on parameter names Future> generateExampleParams({required dynamic requestModel, required dynamic responseModel,}) async { final ollamaService = OllamaService(); @@ -185,4 +184,118 @@ generate same to same type of test case url for test purpose } } + + + Future generateTestCases({required dynamic requestModel, required dynamic responseModel}) async { + final method = requestModel.httpRequestModel?.method + .toString() + .split('.') + .last + .toUpperCase() + ?? "GET"; + final endpoint = requestModel.httpRequestModel?.url ?? "Unknown endpoint"; + final headers = requestModel.httpRequestModel?.enabledHeadersMap ?? {}; + final parameters = requestModel.httpRequestModel?.enabledParamsMap ?? {}; + final body = requestModel.httpRequestModel?.body; + final statusCode = responseModel.statusCode ?? 200; + + // Extract example values from successful response + final responseBody = responseModel.body is String + ? jsonDecode(responseModel.body) + : responseModel.body; + final exampleValues = _extractExampleValues(parameters, responseBody); + + final prompt = ''' +Generate comprehensive test cases in JSON format for this API endpoint: + +API Details: +- Endpoint: $endpoint +- Method: $method +- Headers: ${headers.isNotEmpty ? jsonEncode(headers) : "None"} +- Parameters: ${parameters.isNotEmpty ? jsonEncode(parameters) : "None"} +- Successful Response Example (${statusCode}): ${jsonEncode(responseBody)} + +Test Case Requirements: +1. Structure tests in JSON format with arrays for different categories +2. Include valid parameter combinations from the actual request +3. Create edge cases using min/max values and boundary conditions +4. Generate invalid parameter combinations that trigger error responses +5. Include authentication failure scenarios if applicable +6. Mirror successful response structure in test expectations + +JSON Template: +{ + "test_cases": { + "valid": [ + { + "name": "Test valid request with typical parameters", + "parameters": { /* mirror actual parameter structure */ }, + "expected": { + "status_code": ${statusCode}, + "body_patterns": { /* key fields to validate */ } + } + } + ], + "edge_cases": [ + { + "name": "Test maximum limit boundary", + "parameters": { /* edge values */ }, + "expected": { /* status and response patterns */ } + } + ], + "invalid": [ + { + "name": "Test missing required parameter", + "parameters": { /* incomplete params */ }, + "expected": { + "status_code": 400, + "error_patterns": [ "missing field", "required" ] + } + } + ] + } +} + +Example Values from Current Implementation: +${jsonEncode(exampleValues)} + +Generation Guidelines: +- Use parameter names and structure from the actual request +- Base valid values on successful response patterns +- Derive edge cases from parameter types (e.g., string length, number ranges) +- Match error responses to observed API behavior +- Include authentication headers if present in original request +- Prioritize testing critical business logic endpoints + +Generate the JSON test suite following this structure and guidelines. +'''; + + return generateResponse(prompt); + } + + Map _extractExampleValues( Map parameters, dynamic responseBody) { + final examples = {}; + + // Extract parameter examples + examples['parameters'] = parameters.map((k, v) => + MapEntry(k, _deriveValuePattern(v))); + + // Extract response body patterns + if (responseBody is Map) { + examples['response_patterns'] = responseBody.map((k, v) => + MapEntry(k, _deriveValuePattern(v))); + } + + return examples; + } + + String _deriveValuePattern(dynamic value) { + if (value is num) return "{number}"; + if (value is String) { + if (DateTime.tryParse(value) != null) return "{datetime}"; + if (value.contains('@')) return "{email}"; + return "{string}"; + } + return "{value}"; + } } diff --git a/lib/widgets/chatbot_widget.dart b/lib/widgets/chatbot_widget.dart index 6f53fb1f..1e6f1d1c 100644 --- a/lib/widgets/chatbot_widget.dart +++ b/lib/widgets/chatbot_widget.dart @@ -75,6 +75,21 @@ setState(() { icon: const Icon(Icons.info_outline), label: const Text("Explain API"), ), + + if (showDebugButton) ...[ + const SizedBox(width: 8), + ElevatedButton.icon( + onPressed: () => _sendMessage("Debug API"), + icon: const Icon(Icons.bug_report), + label: const Text("Debug"), + ), + ], + const SizedBox(width: 8), + ElevatedButton.icon( + onPressed: () => _sendMessage("Generate Test Case"), + icon: const Icon(Icons.developer_mode), + label: const Text("Test Case"), + ), const Spacer(), ], ), @@ -140,7 +155,10 @@ const ChatBubble({super.key, required this.message, this.isUser = false}); : Theme.of(context).colorScheme.secondaryContainer, borderRadius: BorderRadius.circular(8), ), - child: Text(message), + child: MarkdownBody( + data: message, + selectable: true, // Allows copying text + ), ), ); }