Skip to content

Commit bcc5208

Browse files
committed
Update SeleniumBase Visual Testing
1 parent 5f4a611 commit bcc5208

File tree

2 files changed

+132
-57
lines changed

2 files changed

+132
-57
lines changed

seleniumbase/core/visual_helper.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from seleniumbase.core import log_helper
23
from seleniumbase.fixtures import constants
34

45
VISUAL_BASELINE_DIR = constants.VisualBaseline.STORAGE_FOLDER
@@ -17,3 +18,91 @@ def visual_baseline_folder_setup():
1718
os.makedirs(visual_baseline_path)
1819
except Exception:
1920
pass # Should only be reachable during multi-threaded runs
21+
22+
23+
def get_sbs_head():
24+
head = (
25+
'<head><meta charset="utf-8">'
26+
'<meta name="viewport" content="shrink-to-fit=no">'
27+
'<link rel="shortcut icon" href="%s">'
28+
"<title>Visual Comparison</title>"
29+
"</head>" % (constants.SideBySide.SIDE_BY_SIDE_PNG)
30+
)
31+
return head
32+
33+
34+
def get_sbs_table_row(baseline="baseline.png", diff="baseline_diff.png"):
35+
row = (
36+
'<tbody class="compare results-table-row">'
37+
'<tr style="background-color: #F4F4FE;">'
38+
'<td><img src="%s" width="100%%" /></td>'
39+
'<td><img src="%s" width="100%%" /></td>'
40+
"</tr></tbody>"
41+
"" % (baseline, diff)
42+
)
43+
return row
44+
45+
46+
def get_sbs_table_html(baseline="baseline.png", diff="baseline_diff.png"):
47+
table_html = (
48+
'<table border="3px solid #E6E6E6;" width="100%;" padding: 12px;'
49+
' font-size="16px;" text-align="left;" id="results-table"'
50+
' style="background-color: #FAFAFA;">'
51+
'<thead id="results-table-head">'
52+
"<tr>"
53+
'<th style="background-color: rgba(0, 128, 0, 0.25);"'
54+
' col="baseline">Baseline Screenshot</th>'
55+
'<th style="background-color: rgba(128, 0, 0, 0.25);"'
56+
' col="failure">Visual Diff Failure Screenshot</th>'
57+
"</tr></thead>"
58+
)
59+
row = get_sbs_table_row(baseline, diff)
60+
table_html += row
61+
table_html += "</table>"
62+
return table_html
63+
64+
65+
def get_sbs_gen_by():
66+
gen_by = (
67+
'<p><div>Generated by: <b><a href="https://seleniumbase.io/">'
68+
"SeleniumBase</a></b></div></p><p></p>"
69+
)
70+
return gen_by
71+
72+
73+
def get_sbs_header_text():
74+
header_text = "SeleniumBase Visual Comparison"
75+
return header_text
76+
77+
78+
def get_sbs_header():
79+
header_text = get_sbs_header_text()
80+
header = '<h3 align="center">%s</h3>' % header_text
81+
return header
82+
83+
84+
def get_sbs_footer():
85+
footer = "<br /><b>Last updated:</b> "
86+
timestamp, the_date, the_time = log_helper.get_master_time()
87+
last_updated = "%s at %s" % (the_date, the_time)
88+
footer = footer + "%s" % last_updated
89+
gen_by = get_sbs_gen_by()
90+
footer = footer + gen_by
91+
return footer
92+
93+
94+
def get_sbs_html(baseline="baseline.png", diff="baseline_diff.png"):
95+
head = get_sbs_head()
96+
header = get_sbs_header()
97+
table_html = get_sbs_table_html(baseline, diff)
98+
footer = get_sbs_footer()
99+
the_html = (
100+
'<html lang="en">'
101+
+ head
102+
+ '<body style="background-color: #FCFCF4;">'
103+
+ header
104+
+ table_html
105+
+ footer
106+
+ "</body>"
107+
)
108+
return the_html

seleniumbase/fixtures/base_case.py

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def __initialize_variables(self):
105105
self.__start_time_ms = None
106106
self.__requests_timeout = None
107107
self.__screenshot_count = 0
108+
self.__level_0_visual_f = False
108109
self.__will_be_skipped = False
109110
self.__passed_then_skipped = False
110111
self.__visual_baseline_copies = []
@@ -10957,56 +10958,10 @@ def __process_visual_baseline_logs(self):
1095710958
self.__create_log_path_as_needed(test_logpath)
1095810959
shutil.copy(latest_png_path, latest_copy_path)
1095910960
if len(self.__visual_baseline_copies) != 1:
10960-
return # Only possible when deferred visual asserts are used
10961-
head = (
10962-
'<head><meta charset="utf-8">'
10963-
'<meta name="viewport" content="shrink-to-fit=no">'
10964-
'<link rel="shortcut icon" href="%s">'
10965-
"<title>Visual Comparison</title>"
10966-
"</head>" % (constants.SideBySide.SIDE_BY_SIDE_PNG)
10967-
)
10968-
table_html = (
10969-
'<table border="3px solid #E6E6E6;" width="100%;" padding: 12px;'
10970-
' font-size="16px;" text-align="left;" id="results-table"'
10971-
' style="background-color: #FAFAFA;">'
10972-
'<thead id="results-table-head">'
10973-
"<tr>"
10974-
'<th style="background-color: rgba(0, 128, 0, 0.25);"'
10975-
' col="baseline">Baseline Screenshot</th>'
10976-
'<th style="background-color: rgba(128, 0, 0, 0.25);"'
10977-
' col="failure">Visual Diff Failure Screenshot</th>'
10978-
"</tr></thead>"
10979-
)
10980-
row = (
10981-
'<tbody class="compare results-table-row">'
10982-
'<tr style="background-color: #F4F4FE;">'
10983-
'<td><img src="%s" width="100%%" /></td>'
10984-
'<td><img src="%s" width="100%%" /></td>'
10985-
"</tr></tbody>"
10986-
"" % ("baseline.png", "baseline_diff.png")
10987-
)
10988-
header_text = "SeleniumBase Visual Comparison"
10989-
header = '<h3 align="center">%s</h3>' % header_text
10990-
table_html += row
10991-
table_html += "</table>"
10992-
footer = "<br /><b>Last updated:</b> "
10993-
timestamp, the_date, the_time = log_helper.get_master_time()
10994-
last_updated = "%s at %s" % (the_date, the_time)
10995-
footer = footer + "%s" % last_updated
10996-
gen_by = (
10997-
'<p><div>Generated by: <b><a href="https://seleniumbase.io/">'
10998-
"SeleniumBase</a></b></div></p><p></p>"
10999-
)
11000-
footer = footer + gen_by
11001-
the_html = (
11002-
'<html lang="en">'
11003-
+ head
11004-
+ '<body style="background-color: #FCFCF4;">'
11005-
+ header
11006-
+ table_html
11007-
+ footer
11008-
+ "</body>"
11009-
)
10961+
return # Skip the rest when deferred visual asserts are used
10962+
from seleniumbase.core import visual_helper
10963+
10964+
the_html = visual_helper.get_sbs_html()
1101010965
file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
1101110966
out_file = codecs.open(file_path, "w+", encoding="utf-8")
1101210967
out_file.writelines(the_html)
@@ -11120,15 +11075,15 @@ def check_window(
1112011075

1112111076
visual_helper.visual_baseline_folder_setup()
1112211077
baseline_dir = constants.VisualBaseline.STORAGE_FOLDER
11123-
visual_baseline_path = baseline_dir + "/" + test_id + "/" + name
11124-
page_url_file = visual_baseline_path + "/page_url.txt"
11078+
visual_baseline_path = os.path.join(baseline_dir, test_id, name)
11079+
page_url_file = os.path.join(visual_baseline_path, "page_url.txt")
1112511080
baseline_png = "baseline.png"
11126-
baseline_png_path = visual_baseline_path + "/%s" % baseline_png
11081+
baseline_png_path = os.path.join(visual_baseline_path, baseline_png)
1112711082
latest_png = "latest.png"
11128-
latest_png_path = visual_baseline_path + "/%s" % latest_png
11129-
level_1_file = visual_baseline_path + "/tags_level_1.txt"
11130-
level_2_file = visual_baseline_path + "/tags_level_2.txt"
11131-
level_3_file = visual_baseline_path + "/tags_level_3.txt"
11083+
latest_png_path = os.path.join(visual_baseline_path, latest_png)
11084+
level_1_file = os.path.join(visual_baseline_path, "tags_level_1.txt")
11085+
level_2_file = os.path.join(visual_baseline_path, "tags_level_2.txt")
11086+
level_3_file = os.path.join(visual_baseline_path, "tags_level_3.txt")
1113211087

1113311088
set_baseline = False
1113411089
if baseline or self.visual_baseline:
@@ -11188,6 +11143,7 @@ def check_window(
1118811143
)
1118911144
self.__visual_baseline_copies.append(baseline_copy_tuple)
1119011145

11146+
is_level_0_failure = False
1119111147
if not set_baseline:
1119211148
self.save_screenshot(
1119311149
latest_png, visual_baseline_path, selector="body"
@@ -11287,9 +11243,38 @@ def check_window(
1128711243
)
1128811244
except Exception as e:
1128911245
print(e) # Level-0 Dry Run (Only print the differences)
11246+
is_level_0_failure = True
1129011247
unittest.TestCase.maxDiff = None # Reset unittest.TestCase.maxDiff
1129111248
# Since the check passed, do not save an extra copy of the baseline
1129211249
del self.__visual_baseline_copies[-1] # .pop() returns the element
11250+
if is_level_0_failure:
11251+
# Generating the side_by_side.html file for Level-0 failures
11252+
test_logpath = os.path.join(self.log_path, self.__get_test_id())
11253+
if (
11254+
not os.path.exists(baseline_path)
11255+
or not os.path.exists(latest_png_path)
11256+
):
11257+
return
11258+
self.__level_0_visual_f = True
11259+
if not os.path.exists(test_logpath):
11260+
self.__create_log_path_as_needed(test_logpath)
11261+
baseline_copy_path = os.path.join(test_logpath, baseline_copy_name)
11262+
latest_copy_path = os.path.join(test_logpath, latest_copy_name)
11263+
if (
11264+
not os.path.exists(baseline_copy_path)
11265+
and not os.path.exists(latest_copy_path)
11266+
):
11267+
shutil.copy(baseline_path, baseline_copy_path)
11268+
shutil.copy(latest_png_path, latest_copy_path)
11269+
the_html = visual_helper.get_sbs_html(
11270+
baseline_copy_name, latest_copy_name
11271+
)
11272+
alpha_n_d_name = "".join([x if x.isalnum() else "_" for x in name])
11273+
side_by_side_name = "side_by_side_%s.html" % alpha_n_d_name
11274+
file_path = os.path.join(test_logpath, side_by_side_name)
11275+
out_file = codecs.open(file_path, "w+", encoding="utf-8")
11276+
out_file.writelines(the_html)
11277+
out_file.close()
1129311278

1129411279
############
1129511280

@@ -13102,6 +13087,7 @@ def __process_dashboard(self, has_exception, init=False):
1310213087
has_exception
1310313088
or self.save_screenshot_after_test
1310413089
or self.__screenshot_count > 0
13090+
or self.__level_0_visual_f
1310513091
or self.__will_be_skipped
1310613092
):
1310713093
sb_config._d_t_log_path[test_id] = os.path.join(log_dir, ft_id)

0 commit comments

Comments
 (0)