Created
September 9, 2025 03:18
-
-
Save adiralashiva8/c3283328815abe3b8c5e893c0861bea4 to your computer and use it in GitHub Desktop.
Generate custom summary report from robotframework output.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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