Akshayram1 commited on
Commit
3715844
Β·
verified Β·
1 Parent(s): 6f1f3f3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -121
app.py CHANGED
@@ -50,103 +50,173 @@ def call_openai_chat(messages, model="gpt-4o-mini", max_tokens=3000):
50
  return f"OpenAI API Error: {str(e)}"
51
 
52
  def parse_test_cases_to_dataframe(text_response):
53
- """Enhanced parsing with better regex patterns"""
54
  try:
55
  test_cases = []
56
 
57
- # Enhanced regex patterns for better extraction
58
- test_case_pattern = r'(?:Test Case|TC)\s*(?:ID|#)?\s*:?\s*([^\n]+)'
59
- title_pattern = r'(?:Title|Test Case Title|Name)\s*:?\s*([^\n]+)'
60
- precondition_pattern = r'(?:Precondition|Pre-condition|Prerequisites?)\s*:?\s*([^\n]+)'
61
- steps_pattern = r'(?:Test Steps?|Steps|Procedure)\s*:?\s*((?:[^\n]*\n?)*?)(?=Expected|Priority|Test Case|$)'
62
- expected_pattern = r'(?:Expected Result|Expected|Result)\s*:?\s*([^\n]+)'
63
- priority_pattern = r'(?:Priority|Severity)\s*:?\s*([^\n]+)'
64
- test_data_pattern = r'(?:Test Data|Data)\s*:?\s*([^\n]+)'
65
 
66
- # Split into test case blocks more accurately
67
- blocks = re.split(r'\n\s*(?=(?:Test Case|TC)\s*(?:ID|#|\d+))', text_response, flags=re.IGNORECASE)
 
 
 
 
 
 
 
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  for i, block in enumerate(blocks):
70
- if len(block.strip()) < 30:
71
  continue
72
 
 
73
  test_case = {}
74
 
75
- # Extract components with fallbacks
76
- id_match = re.search(test_case_pattern, block, re.IGNORECASE)
77
- test_case['Test_Case_ID'] = id_match.group(1).strip() if id_match else f"TC_{len(test_cases)+1:03d}"
78
 
79
- title_match = re.search(title_pattern, block, re.IGNORECASE)
80
- test_case['Title'] = title_match.group(1).strip() if title_match else f"Test Case {len(test_cases)+1}"
 
 
 
 
 
 
81
 
82
- precond_match = re.search(precondition_pattern, block, re.IGNORECASE)
83
- test_case['Preconditions'] = precond_match.group(1).strip() if precond_match else "N/A"
 
84
 
85
- steps_match = re.search(steps_pattern, block, re.IGNORECASE | re.DOTALL)
86
- test_case['Test_Steps'] = steps_match.group(1).strip() if steps_match else "Steps not specified"
87
-
88
- expected_match = re.search(expected_pattern, block, re.IGNORECASE)
89
- test_case['Expected_Results'] = expected_match.group(1).strip() if expected_match else "Expected result not specified"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
- priority_match = re.search(priority_pattern, block, re.IGNORECASE)
92
- test_case['Priority'] = priority_match.group(1).strip() if priority_match else "Medium"
 
93
 
94
- data_match = re.search(test_data_pattern, block, re.IGNORECASE)
95
- test_case['Test_Data'] = data_match.group(1).strip() if data_match else "N/A"
 
 
 
 
 
 
 
 
 
96
 
 
97
  test_case['Created_Date'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
98
  test_case['Status'] = "New"
99
 
100
  test_cases.append(test_case)
101
 
102
- # Enhanced fallback parsing
103
  if not test_cases:
104
- lines = [line.strip() for line in text_response.split('\n') if line.strip()]
105
- current_case = {}
106
-
107
- for line in lines:
108
- if any(keyword in line.lower() for keyword in ['test case', 'tc', 'scenario']):
109
- if current_case:
110
- test_cases.append(current_case)
111
- current_case = {
112
- 'Test_Case_ID': f"TC_{len(test_cases)+1:03d}",
113
- 'Title': line[:100],
114
- 'Preconditions': "N/A",
115
- 'Test_Steps': "",
116
- 'Expected_Results': "",
117
- 'Priority': "Medium",
118
- 'Test_Data': "N/A",
119
- 'Created_Date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
120
- 'Status': "New"
121
- }
122
- elif current_case:
123
- if not current_case.get('Test_Steps'):
124
- current_case['Test_Steps'] = line
125
- elif not current_case.get('Expected_Results'):
126
- current_case['Expected_Results'] = line
127
-
128
- if current_case:
129
- test_cases.append(current_case)
130
 
131
- return pd.DataFrame(test_cases) if test_cases else pd.DataFrame({
132
- 'Test_Case_ID': ['TC_001'],
133
- 'Title': ['Sample Test Case'],
134
- 'Preconditions': ['N/A'],
135
- 'Test_Steps': ['Parse failed - manual review needed'],
136
- 'Expected_Results': ['Manual review needed'],
137
- 'Priority': ['Medium'],
138
- 'Test_Data': ['N/A'],
139
- 'Created_Date': [datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
140
- 'Status': ['New']
141
- })
142
 
143
  except Exception as e:
 
144
  return pd.DataFrame({
145
  'Test_Case_ID': ['TC_001'],
146
  'Title': ['Parsing Error'],
147
  'Preconditions': ['N/A'],
148
- 'Test_Steps': [f'Error: {str(e)}'],
149
- 'Expected_Results': ['Manual review needed'],
150
  'Priority': ['High'],
151
  'Test_Data': ['N/A'],
152
  'Created_Date': [datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
@@ -251,75 +321,84 @@ def generate_test_cases_from_text(requirements, test_types, priority_level):
251
  """Enhanced test case generation with more specific prompts"""
252
 
253
  enhanced_prompt = f"""
254
- As an expert QA engineer, create comprehensive and detailed test cases for the following requirements:
255
-
256
  REQUIREMENTS:
257
  {requirements}
258
-
259
  INSTRUCTIONS:
260
  - Generate {test_types} test scenarios
261
  - Focus on {priority_level} priority tests
262
- - Follow standard test case format exactly
263
- - Include both positive and negative scenarios
264
- - Consider edge cases and boundary conditions
265
- - Make test steps clear and actionable
266
-
267
- FORMAT EACH TEST CASE AS:
268
- Test Case ID: TC_XXX
269
- Test Case Title: [Clear, descriptive title]
270
- Preconditions: [What must be true before testing]
271
  Test Steps:
272
- 1. [Clear step-by-step instructions]
273
- 2. [Each step should be specific and actionable]
274
- 3. [Include test data where applicable]
275
- Expected Results: [What should happen when test passes]
276
- Priority: [High/Medium/Low]
277
- Test Data: [Specific data needed for testing]
278
-
279
- Generate at least 5-8 comprehensive test cases covering different scenarios.
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  """
281
 
282
  messages = [{"role": "user", "content": enhanced_prompt}]
283
  response = call_openai_chat(messages, max_tokens=4000)
284
 
285
  if "Error:" in response:
286
- return response, None
287
 
288
  df = parse_test_cases_to_dataframe(response)
289
  csv_path = create_download_csv(df, "generated_test_cases")
290
 
291
- return response, csv_path
292
 
293
  def generate_test_cases_from_image(image, test_focus):
294
  """Enhanced image-based test case generation"""
295
 
 
 
 
296
  base64_image = encode_image(image)
297
 
298
  enhanced_prompt = f"""
299
- As an expert QA engineer, analyze this requirements image/mockup/wireframe and create comprehensive test cases.
300
-
301
  FOCUS AREA: {test_focus}
302
-
303
- INSTRUCTIONS:
304
- - Examine all UI elements, workflows, and user interactions visible
305
- - Consider usability, functionality, and user experience aspects
306
- - Generate test cases for different user scenarios
307
- - Include accessibility and responsive design considerations
308
- - Cover both happy path and error scenarios
309
-
310
- FORMAT EACH TEST CASE AS:
311
- Test Case ID: TC_XXX
312
- Test Case Title: [Clear, descriptive title]
313
  Preconditions: [Setup requirements]
314
  Test Steps:
315
- 1. [Detailed step-by-step instructions]
316
- 2. [Include specific UI elements to interact with]
317
- 3. [Specify expected user actions]
318
- Expected Results: [Expected behavior/outcome]
319
- Priority: [High/Medium/Low based on business impact]
320
- Test Data: [Required test data]
321
-
322
- Generate comprehensive test cases covering all visible functionality.
323
  """
324
 
325
  messages = [
@@ -335,12 +414,12 @@ def generate_test_cases_from_image(image, test_focus):
335
  response = call_openai_chat(messages, model="gpt-4o-mini", max_tokens=4000)
336
 
337
  if "Error:" in response:
338
- return response, None
339
 
340
  df = parse_test_cases_to_dataframe(response)
341
  csv_path = create_download_csv(df, "image_based_test_cases")
342
 
343
- return response, csv_path
344
 
345
  def optimize_test_cases(existing_cases, focus_areas, optimization_goal):
346
  """Enhanced test case optimization"""
@@ -676,15 +755,25 @@ def create_gradio_interface():
676
  with gr.Column():
677
  test_cases_output = gr.Textbox(
678
  label="Generated Test Cases",
679
- lines=15,
680
- max_lines=20
681
  )
682
- csv_download = gr.File(label="Download CSV")
 
 
 
 
 
 
 
 
 
 
683
 
684
  generate_btn.click(
685
  fn=generate_test_cases_from_text,
686
  inputs=[requirements_input, test_types, priority_level],
687
- outputs=[test_cases_output, csv_download]
688
  )
689
 
690
  with gr.TabItem("Image Requirements"):
@@ -704,15 +793,25 @@ def create_gradio_interface():
704
  with gr.Column():
705
  img_test_cases_output = gr.Textbox(
706
  label="Generated Test Cases",
707
- lines=15,
708
- max_lines=20
709
  )
710
- img_csv_download = gr.File(label="Download CSV")
 
 
 
 
 
 
 
 
 
 
711
 
712
  generate_img_btn.click(
713
  fn=generate_test_cases_from_image,
714
  inputs=[image_input, test_focus],
715
- outputs=[img_test_cases_output, img_csv_download]
716
  )
717
 
718
  # Test Case Optimization Tab
 
50
  return f"OpenAI API Error: {str(e)}"
51
 
52
  def parse_test_cases_to_dataframe(text_response):
53
+ """Improved parsing that handles various response formats"""
54
  try:
55
  test_cases = []
56
 
57
+ # First, try to split by common delimiters
58
+ # Look for patterns like "Test Case", "TC", numbers followed by periods, etc.
59
+ potential_blocks = []
 
 
 
 
 
60
 
61
+ # Split by various patterns that might indicate new test cases
62
+ split_patterns = [
63
+ r'\n(?=Test Case[:\s#]*\d+)',
64
+ r'\n(?=TC[:\s#]*\d+)',
65
+ r'\n(?=\d+\.?\s*Test)',
66
+ r'\n(?=#{1,3}\s*Test)',
67
+ r'\n(?=\*\*Test Case)',
68
+ r'\n(?=## Test Case)',
69
+ ]
70
 
71
+ blocks = [text_response] # Start with the whole text
72
+
73
+ for pattern in split_patterns:
74
+ new_blocks = []
75
+ for block in blocks:
76
+ new_blocks.extend(re.split(pattern, block, flags=re.IGNORECASE | re.MULTILINE))
77
+ blocks = [b for b in new_blocks if len(b.strip()) > 20]
78
+ if len(blocks) > 1: # If we found a good split, use it
79
+ break
80
+
81
+ # If we still have only one block, try a more aggressive split
82
+ if len(blocks) <= 1:
83
+ lines = text_response.split('\n')
84
+ current_block = []
85
+ blocks = []
86
+
87
+ for line in lines:
88
+ line = line.strip()
89
+ if not line:
90
+ continue
91
+
92
+ # Check if this line starts a new test case
93
+ if (re.match(r'(test case|tc)\s*[:#]?\s*\d+', line.lower()) or
94
+ re.match(r'\d+\.?\s*(test|scenario)', line.lower()) or
95
+ re.match(r'#{1,3}\s*test', line.lower()) or
96
+ '**Test Case' in line):
97
+
98
+ if current_block:
99
+ blocks.append('\n'.join(current_block))
100
+ current_block = []
101
+ current_block.append(line)
102
+ else:
103
+ current_block.append(line)
104
+
105
+ if current_block:
106
+ blocks.append('\n'.join(current_block))
107
+
108
+ # Parse each block
109
  for i, block in enumerate(blocks):
110
+ if len(block.strip()) < 20:
111
  continue
112
 
113
+ # Extract information using multiple strategies
114
  test_case = {}
115
 
116
+ # Strategy 1: Look for labeled fields
117
+ lines = [line.strip() for line in block.split('\n') if line.strip()]
 
118
 
119
+ # Initialize with defaults
120
+ test_case['Test_Case_ID'] = f"TC_{len(test_cases)+1:03d}"
121
+ test_case['Title'] = f"Test Case {len(test_cases)+1}"
122
+ test_case['Preconditions'] = "N/A"
123
+ test_case['Test_Steps'] = ""
124
+ test_case['Expected_Results'] = ""
125
+ test_case['Priority'] = "Medium"
126
+ test_case['Test_Data'] = "N/A"
127
 
128
+ # Parse line by line for labeled content
129
+ current_field = None
130
+ steps_lines = []
131
 
132
+ for line in lines:
133
+ line_lower = line.lower()
134
+
135
+ # Check for field labels
136
+ if any(label in line_lower for label in ['test case id', 'tc id', 'id:']):
137
+ test_case['Test_Case_ID'] = re.sub(r'.*?[:\-]\s*', '', line).strip()
138
+ current_field = None
139
+
140
+ elif any(label in line_lower for label in ['title:', 'test case title', 'name:']):
141
+ test_case['Title'] = re.sub(r'.*?[:\-]\s*', '', line).strip()
142
+ current_field = None
143
+
144
+ elif any(label in line_lower for label in ['precondition', 'prerequisite']):
145
+ test_case['Preconditions'] = re.sub(r'.*?[:\-]\s*', '', line).strip()
146
+ current_field = None
147
+
148
+ elif any(label in line_lower for label in ['test step', 'steps:', 'procedure']):
149
+ current_field = 'steps'
150
+ step_content = re.sub(r'.*?[:\-]\s*', '', line).strip()
151
+ if step_content:
152
+ steps_lines.append(step_content)
153
+
154
+ elif any(label in line_lower for label in ['expected result', 'expected:', 'result:']):
155
+ test_case['Expected_Results'] = re.sub(r'.*?[:\-]\s*', '', line).strip()
156
+ current_field = None
157
+
158
+ elif any(label in line_lower for label in ['priority:', 'severity:']):
159
+ test_case['Priority'] = re.sub(r'.*?[:\-]\s*', '', line).strip()
160
+ current_field = None
161
+
162
+ elif any(label in line_lower for label in ['test data:', 'data:']):
163
+ test_case['Test_Data'] = re.sub(r'.*?[:\-]\s*', '', line).strip()
164
+ current_field = None
165
+
166
+ else:
167
+ # If we're in the middle of collecting steps, add this line
168
+ if current_field == 'steps':
169
+ steps_lines.append(line)
170
+ elif not any(test_case.values()): # If nothing has been set yet, this might be the title
171
+ if len(line) > 5 and not line.startswith(('β€’', '-', '*', '1.', '2.')):
172
+ test_case['Title'] = line[:100]
173
 
174
+ # Combine steps
175
+ if steps_lines:
176
+ test_case['Test_Steps'] = '\n'.join(steps_lines)
177
 
178
+ # Fallback: if we couldn't parse properly, use the first few lines
179
+ if (test_case['Title'] == f"Test Case {len(test_cases)+1}" and
180
+ test_case['Test_Steps'] == "" and
181
+ test_case['Expected_Results'] == ""):
182
+
183
+ if len(lines) > 0:
184
+ test_case['Title'] = lines[0][:100]
185
+ if len(lines) > 1:
186
+ test_case['Test_Steps'] = '\n'.join(lines[1:min(len(lines), 4)])
187
+ if len(lines) > 4:
188
+ test_case['Expected_Results'] = lines[-1][:200]
189
 
190
+ # Add metadata
191
  test_case['Created_Date'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
192
  test_case['Status'] = "New"
193
 
194
  test_cases.append(test_case)
195
 
196
+ # Final fallback - create from raw text
197
  if not test_cases:
198
+ test_cases.append({
199
+ 'Test_Case_ID': 'TC_001',
200
+ 'Title': 'Generated Test Case',
201
+ 'Preconditions': 'N/A',
202
+ 'Test_Steps': text_response[:500] + "..." if len(text_response) > 500 else text_response,
203
+ 'Expected_Results': 'Review generated content',
204
+ 'Priority': 'Medium',
205
+ 'Test_Data': 'N/A',
206
+ 'Created_Date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
207
+ 'Status': 'Needs Review'
208
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
+ return pd.DataFrame(test_cases)
 
 
 
 
 
 
 
 
 
 
211
 
212
  except Exception as e:
213
+ # Error fallback
214
  return pd.DataFrame({
215
  'Test_Case_ID': ['TC_001'],
216
  'Title': ['Parsing Error'],
217
  'Preconditions': ['N/A'],
218
+ 'Test_Steps': [f'Error parsing response: {str(e)}\n\nOriginal text: {text_response[:300]}...'],
219
+ 'Expected_Results': ['Manual review required'],
220
  'Priority': ['High'],
221
  'Test_Data': ['N/A'],
222
  'Created_Date': [datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
 
321
  """Enhanced test case generation with more specific prompts"""
322
 
323
  enhanced_prompt = f"""
324
+ As an expert QA engineer, create comprehensive and detailed test cases for the following requirements.
325
+
326
  REQUIREMENTS:
327
  {requirements}
328
+
329
  INSTRUCTIONS:
330
  - Generate {test_types} test scenarios
331
  - Focus on {priority_level} priority tests
332
+ - Use EXACTLY this format for each test case
333
+ - Generate 5-8 test cases with clear separation
334
+
335
+ FORMAT EACH TEST CASE EXACTLY AS SHOWN:
336
+
337
+ Test Case ID: TC_001
338
+ Title: Login with valid credentials
339
+ Preconditions: User has a valid account, application is accessible
 
340
  Test Steps:
341
+ 1. Navigate to login page
342
+ 2. Enter valid username
343
+ 3. Enter valid password
344
+ 4. Click login button
345
+ Expected Results: User successfully logs in and redirects to dashboard
346
+ Priority: High
347
+ Test Data: username: testuser@example.com, password: Test123!
348
+
349
+ Test Case ID: TC_002
350
+ Title: Login with invalid credentials
351
+ Preconditions: Application is accessible
352
+ Test Steps:
353
+ 1. Navigate to login page
354
+ 2. Enter invalid username
355
+ 3. Enter invalid password
356
+ 4. Click login button
357
+ Expected Results: Error message displayed, user remains on login page
358
+ Priority: High
359
+ Test Data: username: invalid@test.com, password: wrongpass
360
+
361
+ Now generate test cases for the given requirements following this EXACT format.
362
  """
363
 
364
  messages = [{"role": "user", "content": enhanced_prompt}]
365
  response = call_openai_chat(messages, max_tokens=4000)
366
 
367
  if "Error:" in response:
368
+ return response, None, None
369
 
370
  df = parse_test_cases_to_dataframe(response)
371
  csv_path = create_download_csv(df, "generated_test_cases")
372
 
373
+ return response, df, csv_path
374
 
375
  def generate_test_cases_from_image(image, test_focus):
376
  """Enhanced image-based test case generation"""
377
 
378
+ if image is None:
379
+ return "Please upload an image first.", None, None
380
+
381
  base64_image = encode_image(image)
382
 
383
  enhanced_prompt = f"""
384
+ As an expert QA engineer, analyze this UI/wireframe/mockup image and create test cases.
385
+
386
  FOCUS AREA: {test_focus}
387
+
388
+ Use EXACTLY this format for each test case:
389
+
390
+ Test Case ID: TC_001
391
+ Title: [Clear descriptive title]
 
 
 
 
 
 
392
  Preconditions: [Setup requirements]
393
  Test Steps:
394
+ 1. [Step 1]
395
+ 2. [Step 2]
396
+ 3. [Step 3]
397
+ Expected Results: [Expected outcome]
398
+ Priority: [High/Medium/Low]
399
+ Test Data: [Required data]
400
+
401
+ Generate 5-8 test cases covering all visible UI elements and user flows.
402
  """
403
 
404
  messages = [
 
414
  response = call_openai_chat(messages, model="gpt-4o-mini", max_tokens=4000)
415
 
416
  if "Error:" in response:
417
+ return response, None, None
418
 
419
  df = parse_test_cases_to_dataframe(response)
420
  csv_path = create_download_csv(df, "image_based_test_cases")
421
 
422
+ return response, df, csv_path
423
 
424
  def optimize_test_cases(existing_cases, focus_areas, optimization_goal):
425
  """Enhanced test case optimization"""
 
755
  with gr.Column():
756
  test_cases_output = gr.Textbox(
757
  label="Generated Test Cases",
758
+ lines=10,
759
+ max_lines=15
760
  )
761
+
762
+ # Add a separate row for the dataframe and download
763
+ with gr.Row():
764
+ test_cases_table = gr.Dataframe(
765
+ label="πŸ“Š Test Cases Table",
766
+ interactive=False,
767
+ wrap=True
768
+ )
769
+
770
+ with gr.Row():
771
+ csv_download = gr.File(label="πŸ“₯ Download CSV")
772
 
773
  generate_btn.click(
774
  fn=generate_test_cases_from_text,
775
  inputs=[requirements_input, test_types, priority_level],
776
+ outputs=[test_cases_output, test_cases_table, csv_download]
777
  )
778
 
779
  with gr.TabItem("Image Requirements"):
 
793
  with gr.Column():
794
  img_test_cases_output = gr.Textbox(
795
  label="Generated Test Cases",
796
+ lines=10,
797
+ max_lines=15
798
  )
799
+
800
+ # Add separate row for table and download
801
+ with gr.Row():
802
+ img_test_cases_table = gr.Dataframe(
803
+ label="πŸ“Š Test Cases Table",
804
+ interactive=False,
805
+ wrap=True
806
+ )
807
+
808
+ with gr.Row():
809
+ img_csv_download = gr.File(label="πŸ“₯ Download CSV")
810
 
811
  generate_img_btn.click(
812
  fn=generate_test_cases_from_image,
813
  inputs=[image_input, test_focus],
814
+ outputs=[img_test_cases_output, img_test_cases_table, img_csv_download]
815
  )
816
 
817
  # Test Case Optimization Tab