Skip to content

Instantly share code, notes, and snippets.

@adiralashiva8
Created September 9, 2025 03:18
Show Gist options
  • Save adiralashiva8/c3283328815abe3b8c5e893c0861bea4 to your computer and use it in GitHub Desktop.
Save adiralashiva8/c3283328815abe3b8c5e893c0861bea4 to your computer and use it in GitHub Desktop.
Generate custom summary report from robotframework output.xml
from collections import defaultdict
from robot.api import ExecutionResult
from robot.result.model import Keyword
from robot.result.visitor import ResultVisitor
from collections import Counter
def generate_html_report(test_stats, tag_stats, failed_modules, failure_message_counts, failure_message_by_module_counts, failure_keywords_counts, output_file):
with open(output_file, 'w') as f:
f.write("<html><body>")
f.write("<h2>ServiceNow Project Status:</h2>")
f.write("<h2></h2>")
f.write("<table style='text-align:center' width='60%' border='1' cellspacing='2' cellpadding='10'><tr style='background:#5F9EA0'><th>Total</th><th>Pass</th><th>Fail</th><th>Pass%</th></tr>")
test_text = f"""
<tr>
<td>{test_stats[0]}</td>
<td style='color:green'>{test_stats[1]}</td>
<td style='color:red'>{test_stats[2]}</td>
<td style='color:green'>{test_stats[3]}</td>
</tr>
"""
f.write(test_text)
f.write("</table></br>")
f.write("<h3>Tag Stats By Owner:</h3>")
f.write("<table style='text-align:center' width='60%' border='1' cellspacing='2' cellpadding='10'><tr style='background:#5F9EA0'><th>Tag</th><th>Total</th><th>Pass</th><th>Fail</th><th>Pass%</th></tr>")
for tag, values in tag_stats.items():
text = f"""
<tr>
<td style='text-align:left'>{values['name']}</td>
<td>{values['total']}</td>
<td style='color:green'>{values['pass']}</td>
<td style='color:red'>{values['fail']}</td>
<td style='color:green'>{values['pass_percentage']}</td>
</tr>
"""
f.write(text)
f.write("</table>")
f.write("<h3>Top 15 Failed Modules:</h3>")
f.write("<table style='text-align:center' width='60%' border='1' cellspacing='2' cellpadding='10'><tr style='background:#5F9EA0'><th>Tag</th><th>Total</th><th>Pass</th><th>Fail</th><th>Pass%</th></tr>")
for tag, values in failed_modules.items():
if list(failed_modules.keys()).index(tag) >= 15:
break
text = f"""
<tr>
<td style='text-align:left'>{values['name']}</td>
<td>{values['total']}</td>
<td style='color:green'>{values['pass']}</td>
<td style='color:red'>{values['fail']}</td>
<td style='color:green'>{values['pass_percentage']}</td>
</tr>
"""
f.write(text)
f.write("</table>")
f.write(f"<h3>Top 15 Common Failures In Module:</h3>")
f.write("<table style='text-align:center' width='60%' border='1' cellspacing='2' cellpadding='10'><tr style='background:#5F9EA0'><th>Error Message</th><th>Module</th><th>Count</th></tr>")
for (message, module), count in failure_message_by_module_counts.items():
if list(failure_message_by_module_counts.keys()).index((message, module)) >= 15:
break
message = message.replace("$","$$")
text = f"""
<tr>
<td style='text-align:left'>{message}</td>
<td style='text-align:left'>{module}</td>
<td style='text-align:middle'>{count}</td>
</tr>
"""
f.write(text)
f.write("</table>")
f.write(f"<h3>Top 15 Common Failures:</h3>")
f.write("<table style='text-align:center' width='60%' border='1' cellspacing='2' cellpadding='10'><tr style='background:#5F9EA0'><th>Error Message</th><th>Count</th></tr>")
for message, count in failure_message_counts.items():
if list(failure_message_counts.keys()).index(message) >= 15:
break
message = message.replace("$","$$")
text = f"""
<tr>
<td style='text-align:left'>{message}</td>
<td style='text-align:middle'>{count}</td>
</tr>
"""
f.write(text)
f.write("</table>")
f.write(f"<h3>Top 15 Failed Keywords:</h3>")
f.write("<table style='text-align:center' width='60%' border='1' cellspacing='2' cellpadding='10'><tr style='background:#5F9EA0'><th>Keyword Name</th><th>Count</th></tr>")
for keyword, count in failure_keywords_counts.items():
if list(failure_keywords_counts.keys()).index(keyword) >= 15:
break
text = f"""
<tr>
<td style='text-align:left'>{keyword}</td>
<td style='text-align:middle'>{count}</td>
</tr>
"""
f.write(text)
f.write("</table>")
f.write("<p style='font-style:italic'>***Note: This is an auto generated report through Jenkins, please refer logs for detailed results </p>")
f.write("</body></html>")
result = ExecutionResult('output.xml')
stats = result.statistics
owner_tags = ['u1', 'u2', 'u3']
exclude_tags = ['high','uat', 'low', 'medium', 'debug', 'veryhigh', 'smoke', 'regression','flaky', 'applicationbug', 'servicecatalog', 'businesshours']
test_stats = [stats.total.total, stats.total.passed, stats.total.failed, round((stats.total.passed/stats.total.total)*100,2)]
tags = stats.tags
tag_stats = defaultdict(lambda: {'pass': 0, 'fail': 0, 'total': 0})
module_tag_stats = defaultdict(lambda: {'pass': 0, 'fail': 0, 'total': 0})
for tag in tags:
if "itdft-" not in str(tag.name).lower():
if str(tag.name).lower() in owner_tags:
tag_stats[tag.name]['name'] = str(tag.name).lower()
tag_stats[tag.name]['total'] = tag.total
tag_stats[tag.name]['pass'] = tag.passed
tag_stats[tag.name]['fail'] = tag.failed
tag_stats[tag.name]['pass_percentage'] = round((tag.passed/tag.total)*100,2)
if str(tag.name).lower() not in owner_tags:
if str(tag.name).lower() in exclude_tags:
continue
module_tag_stats[tag.name]['name'] = str(tag.name).lower()
module_tag_stats[tag.name]['total'] = tag.total
module_tag_stats[tag.name]['pass'] = tag.passed
module_tag_stats[tag.name]['fail'] = tag.failed
module_tag_stats[tag.name]['pass_percentage'] = round((tag.passed/tag.total)*100,2)
tag_stats = dict(sorted(tag_stats.items(), key=lambda item: item[1]['fail'], reverse=True))
module_tag_stats = dict(sorted(module_tag_stats.items(), key=lambda item: item[1]['fail'], reverse=True))
failure_message = []
failure_keywords = []
failure_message_by_module = []
class FailMessage(ResultVisitor):
text_to_replace = [
"*HTML*", "Several failures occurred:", "<span class=\"merge\">Test has been re-executed and results merged.</span>",
"<span class=\"new-status\">New status:</span>", "<span class=\"fail\">FAIL</span>",
"<span class=\"new-message\">New message:</span>", "<br>", "<hr>",
"<span class=\"old-status\">Old status:</span> <span class=\"old-message\">Old message:</span>"
]
def visit_test(self, test):
if test.status == 'FAIL':
error_message = str(test.message)
error_message = error_message.split("<table>")[0]
for text in self.text_to_replace:
error_message = error_message.replace(text, "")
failure_message.append(error_message.strip())
# Remove owner_tags and exclude_tags from test.tags
my_tags = [tag for tag in test.tags if str(tag).lower() not in owner_tags and str(tag).lower() not in exclude_tags]
my_tags = [tag for tag in my_tags if not str(tag).upper().startswith("ITDFT-")]
failure_message_by_module.append((error_message.strip(), (my_tags[0]).lower() if my_tags else ""))
class FailKeyword(ResultVisitor):
def visit_keyword(self, keyword):
if keyword.status == 'FAIL':
failure_keywords.append(str(keyword).strip())
for child in keyword.body:
if isinstance(child, Keyword):
self.visit_keyword(child)
result.visit(FailMessage())
result.visit(FailKeyword())
failure_message_counts = Counter(failure_message)
failure_message_by_module_counts = Counter(failure_message_by_module)
failed_keywords_counts = Counter(failure_keywords)
# Print the top 10 failed keywords
failed_keywords_counts = dict(sorted(failed_keywords_counts.items(), key=lambda item: item[1], reverse=True))
# Print the top 10 most common failures
failure_message_counts = dict(sorted(failure_message_counts.items(), key=lambda item: item[1], reverse=True))
# Print the top 10 most common failures
failure_message_module_counts = dict(sorted(failure_message_by_module_counts.items(), key=lambda item: item[1], reverse=True))
generate_html_report(test_stats, tag_stats, module_tag_stats, failure_message_counts, failure_message_module_counts, failed_keywords_counts, 'summary.html')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment