@@ -68,6 +68,11 @@ def parse_stats_file(file_path):
6868 if len (parts ) >= 3 :
6969 time_str = parts [0 ]
7070 test_path = " " .join (parts [2 :])
71+
72+ # Skip entries with "< 0.05 secs were omitted" or similar
73+ if "secs were omitted" in test_path :
74+ continue
75+
7176 try :
7277 time_seconds = float (time_str .rstrip ("s" ))
7378 slowest_tests .append ({"test" : test_path , "duration" : time_seconds })
@@ -94,26 +99,39 @@ def parse_durations_file(file_path):
9499 if os .path .exists (durations_file ):
95100 with open (durations_file , "r" ) as f :
96101 content = f .read ()
97-
102+
98103 # Skip the header line
99- for line in content .split (' \n ' )[1 :]:
104+ for line in content .split (" \n " )[1 :]:
100105 if line .strip ():
101106 # Format is typically: 10.37s call tests/path/to/test.py::TestClass::test_method
102107 parts = line .strip ().split ()
103108 if len (parts ) >= 3 :
104109 time_str = parts [0 ]
105- test_path = ' ' .join (parts [2 :])
110+ test_path = " " .join (parts [2 :])
111+
112+ # Skip entries with "< 0.05 secs were omitted" or similar
113+ if "secs were omitted" in test_path :
114+ continue
115+
106116 try :
107- time_seconds = float (time_str .rstrip ('s' ))
108- slowest_tests .append ({
109- "test" : test_path ,
110- "duration" : time_seconds
111- })
117+ time_seconds = float (time_str .rstrip ("s" ))
118+ slowest_tests .append ({"test" : test_path , "duration" : time_seconds })
112119 except ValueError :
113- pass
120+ # If time_str is not a valid float, it might be a different format
121+ # For example, some pytest formats show "< 0.05s" or similar
122+ if test_path .startswith ("<" ) and "secs were omitted" in test_path :
123+ # Extract the time value from test_path if it's in the format "< 0.05 secs were omitted"
124+ try :
125+ # This handles entries where the time is in the test_path itself
126+ dur_match = re .search (r"(\d+(?:\.\d+)?)" , test_path )
127+ if dur_match :
128+ time_seconds = float (dur_match .group (1 ))
129+ slowest_tests .append ({"test" : test_path , "duration" : time_seconds })
130+ except ValueError :
131+ pass
114132 except Exception as e :
115133 print (f"Error parsing durations file { file_path .replace ('_stats.txt' , '_durations.txt' )} : { e } " )
116-
134+
117135 return slowest_tests
118136
119137
@@ -248,7 +266,7 @@ def consolidate_reports(reports_dir):
248266
249267 # Parse stats
250268 stats = parse_stats_file (stats_file )
251-
269+
252270 # If no slowest tests found in stats file, try the durations file directly
253271 if not stats .get ("slowest_tests" ):
254272 stats ["slowest_tests" ] = parse_durations_file (stats_file )
@@ -300,34 +318,34 @@ def consolidate_reports(reports_dir):
300318 # Store results for this test suite
301319 results [base_name ] = {"stats" : stats , "failures" : failures }
302320
321+ # Filter out entries with "secs were omitted"
322+ filtered_slow_tests = [test for test in all_slow_tests if "secs were omitted" not in test ["test" ]]
323+
303324 # Sort all slow tests by duration (descending)
304- all_slow_tests .sort (key = lambda x : x ["duration" ], reverse = True )
325+ filtered_slow_tests .sort (key = lambda x : x ["duration" ], reverse = True )
305326
306327 # Get the number of slowest tests to show from environment variable or default to 10
307328 num_slowest_tests = int (os .environ .get ("SHOW_SLOWEST_TESTS" , "10" ))
308- top_slowest_tests = all_slow_tests [:num_slowest_tests ] if all_slow_tests else []
309-
329+ top_slowest_tests = filtered_slow_tests [:num_slowest_tests ] if filtered_slow_tests else []
330+
310331 # Calculate additional duration statistics
311332 total_duration = sum (test ["duration" ] for test in all_slow_tests )
312-
333+
313334 # Calculate duration per suite
314335 suite_durations = {}
315336 for test in all_slow_tests :
316337 suite_name = test ["suite" ]
317338 if suite_name not in suite_durations :
318339 suite_durations [suite_name ] = 0
319340 suite_durations [suite_name ] += test ["duration" ]
320-
341+
321342 # Removed duration categories
322343
323344 return {
324- "total_stats" : total_stats ,
325- "test_suites" : results ,
345+ "total_stats" : total_stats ,
346+ "test_suites" : results ,
326347 "slowest_tests" : top_slowest_tests ,
327- "duration_stats" : {
328- "total_duration" : total_duration ,
329- "suite_durations" : suite_durations
330- }
348+ "duration_stats" : {"total_duration" : total_duration , "suite_durations" : suite_durations },
331349 }
332350
333351
@@ -348,7 +366,7 @@ def generate_report(consolidated_data):
348366 # Get duration stats if available
349367 duration_stats = consolidated_data .get ("duration_stats" , {})
350368 total_duration = duration_stats .get ("total_duration" , 0 )
351-
369+
352370 summary_table = [
353371 ["Total Tests" , total ["tests" ]],
354372 ["Passed" , total ["passed" ]],
@@ -360,15 +378,15 @@ def generate_report(consolidated_data):
360378
361379 report .append (tabulate (summary_table , tablefmt = "pipe" ))
362380 report .append ("" )
363-
381+
364382 # Removed duration distribution section
365383
366384 # Add test suites summary
367385 report .append ("## Test Suites" )
368386
369387 # Include duration in test suites table if available
370388 suite_durations = consolidated_data .get ("duration_stats" , {}).get ("suite_durations" , {})
371-
389+
372390 if suite_durations :
373391 suites_table = [["Test Suite" , "Tests" , "Passed" , "Failed" , "Skipped" , "Success Rate" , "Duration (s)" ]]
374392 else :
@@ -382,11 +400,19 @@ def generate_report(consolidated_data):
382400 for suite_name , suite_data in sorted_suites :
383401 stats = suite_data ["stats" ]
384402 success_rate = f"{ (stats ['passed' ] / stats ['tests' ] * 100 ):.2f} %" if stats ["tests" ] > 0 else "N/A"
385-
403+
386404 if suite_durations :
387405 duration = suite_durations .get (suite_name , 0 )
388406 suites_table .append (
389- [suite_name , stats ["tests" ], stats ["passed" ], stats ["failed" ], stats ["skipped" ], success_rate , f"{ duration :.2f} " ]
407+ [
408+ suite_name ,
409+ stats ["tests" ],
410+ stats ["passed" ],
411+ stats ["failed" ],
412+ stats ["skipped" ],
413+ success_rate ,
414+ f"{ duration :.2f} " ,
415+ ]
390416 )
391417 else :
392418 suites_table .append (
@@ -403,6 +429,9 @@ def generate_report(consolidated_data):
403429
404430 slowest_table = [["Rank" , "Test" , "Duration (s)" , "Test Suite" ]]
405431 for i , test in enumerate (slowest_tests , 1 ):
432+ # Skip entries that don't contain actual test names
433+ if "< 0.05 secs were omitted" in test ["test" ]:
434+ continue
406435 slowest_table .append ([i , test ["test" ], f"{ test ['duration' ]:.2f} " , test ["suite" ]])
407436
408437 report .append (tabulate (slowest_table , headers = "firstrow" , tablefmt = "pipe" ))
@@ -541,15 +570,19 @@ def create_slack_payload(consolidated_data):
541570 # Add slowest tests summary
542571 slowest_tests = consolidated_data .get ("slowest_tests" , [])
543572 if slowest_tests :
573+ # Filter out "< 0.05 secs were omitted" entries
574+ filtered_tests = [test for test in slowest_tests if "secs were omitted" not in test ["test" ]]
575+
544576 # Take top 5 for Slack message to avoid clutter
545- top5_slowest = slowest_tests [:5 ]
577+ top5_slowest = filtered_tests [:5 ]
546578
547- slowest_message = "*Top 5 Slowest Tests:*\n "
548- for i , test in enumerate (top5_slowest , 1 ):
549- test_name = test ["test" ].split ("::" )[- 1 ] if "::" in test ["test" ] else test ["test" ]
550- slowest_message += f"{ i } . `{ test_name } ` - { test ['duration' ]:.2f} s ({ test ['suite' ]} )\n "
579+ if top5_slowest :
580+ slowest_message = "*Top 5 Slowest Tests:*\n "
581+ for i , test in enumerate (top5_slowest , 1 ):
582+ test_name = test ["test" ].split ("::" )[- 1 ] if "::" in test ["test" ] else test ["test" ]
583+ slowest_message += f"{ i } . `{ test_name } ` - { test ['duration' ]:.2f} s ({ test ['suite' ]} )\n "
551584
552- payload .append ({"type" : "section" , "text" : {"type" : "mrkdwn" , "text" : slowest_message }})
585+ payload .append ({"type" : "section" , "text" : {"type" : "mrkdwn" , "text" : slowest_message }})
553586
554587 # Add action button
555588 if os .environ .get ("GITHUB_RUN_ID" ):
0 commit comments