2020-01-07 14:42:55 +00:00
|
|
|
import base64
|
|
|
|
import filecmp
|
2020-01-09 14:25:45 +00:00
|
|
|
import shutil
|
|
|
|
from datetime import datetime
|
2020-01-07 14:42:55 +00:00
|
|
|
from distutils.dir_util import copy_tree
|
|
|
|
from itertools import zip_longest
|
2020-01-09 14:25:45 +00:00
|
|
|
from pathlib import Path
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
import dominate
|
2020-01-09 14:25:45 +00:00
|
|
|
from dominate.tags import a, div, h1, h2, hr, i, img, p, table, td, th, tr
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
from . import download
|
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
REPORTS_PATH = Path(__file__).parent.resolve() / "reports"
|
|
|
|
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
def _image(src):
|
|
|
|
with td():
|
|
|
|
if src:
|
|
|
|
# open image file
|
2020-01-09 14:32:11 +00:00
|
|
|
image = src.read_bytes()
|
2020-01-07 14:42:55 +00:00
|
|
|
# encode image as base64
|
2020-01-09 14:32:11 +00:00
|
|
|
image = base64.b64encode(image)
|
2020-01-07 14:42:55 +00:00
|
|
|
# convert output to str
|
|
|
|
image = image.decode()
|
|
|
|
# img(src=src.relative_to(fixture_test_path))
|
|
|
|
img(src="data:image/png;base64, " + image)
|
|
|
|
else:
|
|
|
|
i("missing")
|
|
|
|
|
|
|
|
|
|
|
|
def _header(test_name, expected_hash, actual_hash):
|
|
|
|
h1(test_name)
|
|
|
|
with div():
|
|
|
|
if actual_hash == expected_hash:
|
|
|
|
p(
|
|
|
|
"This test succeeded on UI comparison.",
|
|
|
|
style="color: green; font-weight: bold;",
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
p(
|
|
|
|
"This test failed on UI comparison.",
|
|
|
|
style="color: red; font-weight: bold;",
|
|
|
|
)
|
|
|
|
p("Expected: ", expected_hash)
|
|
|
|
p("Actual: ", actual_hash)
|
|
|
|
hr()
|
|
|
|
|
|
|
|
|
|
|
|
def _write(fixture_test_path, doc, filename):
|
|
|
|
(fixture_test_path / filename).write_text(doc.render())
|
|
|
|
return fixture_test_path / filename
|
|
|
|
|
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
def _report_links(tests, status):
|
|
|
|
if status not in ("failed", "passed"):
|
|
|
|
raise ValueError("Different status than failed/passed is not yet supported.")
|
|
|
|
if not tests:
|
|
|
|
i("None!")
|
|
|
|
return
|
|
|
|
with table(border=1):
|
|
|
|
with tr():
|
|
|
|
th("Link to report")
|
|
|
|
for test in tests:
|
|
|
|
with tr():
|
|
|
|
td(a(test, href=REPORTS_PATH / status / (test + ".html")))
|
|
|
|
|
|
|
|
|
|
|
|
def clear_dir():
|
|
|
|
# delete and create the reports dir to clear previous entries
|
|
|
|
shutil.rmtree(REPORTS_PATH, ignore_errors=True)
|
|
|
|
REPORTS_PATH.mkdir()
|
|
|
|
(REPORTS_PATH / "failed").mkdir()
|
|
|
|
(REPORTS_PATH / "passed").mkdir()
|
|
|
|
|
|
|
|
|
|
|
|
def index(tests, status):
|
|
|
|
title = "UI Test report " + datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
doc = dominate.document(title=title)
|
|
|
|
|
|
|
|
with doc:
|
|
|
|
h1("UI Test report")
|
|
|
|
if status == 0:
|
|
|
|
p("All tests succeeded!", style="color: green; font-weight: bold;")
|
|
|
|
else:
|
|
|
|
p("Some tests failed!", style="color: red; font-weight: bold;")
|
|
|
|
hr()
|
|
|
|
|
|
|
|
h2("Failed", style="color: red;")
|
|
|
|
_report_links(tests["failed"], "failed")
|
|
|
|
|
|
|
|
h2("Passed", style="color: green;")
|
|
|
|
_report_links(tests["passed"], "passed")
|
|
|
|
|
|
|
|
return _write(REPORTS_PATH, doc, "index.html")
|
|
|
|
|
|
|
|
|
|
|
|
def failed(fixture_test_path, test_name, actual_hash, expected_hash):
|
2020-01-07 14:42:55 +00:00
|
|
|
doc = dominate.document(title=test_name)
|
|
|
|
recorded_path = fixture_test_path / "recorded"
|
|
|
|
actual_path = fixture_test_path / "actual"
|
|
|
|
|
|
|
|
if not recorded_path.exists():
|
|
|
|
recorded_path.mkdir()
|
|
|
|
download.fetch_recorded(expected_hash, recorded_path)
|
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
recorded_screens = sorted(recorded_path.iterdir())
|
|
|
|
actual_screens = sorted(actual_path.iterdir())
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
if not recorded_screens:
|
2020-01-07 14:42:55 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
with doc:
|
|
|
|
_header(test_name, expected_hash, actual_hash)
|
|
|
|
|
|
|
|
with table(border=1, width=600):
|
|
|
|
with tr():
|
|
|
|
th("Expected")
|
|
|
|
th("Actual")
|
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
for recorded, actual in zip_longest(recorded_screens, actual_screens):
|
|
|
|
if recorded and actual and filecmp.cmp(actual, recorded):
|
2020-01-07 14:42:55 +00:00
|
|
|
background = "white"
|
|
|
|
else:
|
|
|
|
background = "red"
|
|
|
|
with tr(bgcolor=background):
|
2020-01-09 14:25:45 +00:00
|
|
|
_image(recorded)
|
|
|
|
_image(actual)
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
return _write(REPORTS_PATH / "failed", doc, test_name + ".html")
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
def passed(fixture_test_path, test_name, actual_hash):
|
2020-01-07 14:42:55 +00:00
|
|
|
copy_tree(str(fixture_test_path / "actual"), str(fixture_test_path / "recorded"))
|
|
|
|
|
|
|
|
doc = dominate.document(title=test_name)
|
|
|
|
actual_path = fixture_test_path / "actual"
|
2020-01-09 14:25:45 +00:00
|
|
|
actual_screens = sorted(actual_path.iterdir())
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
with doc:
|
|
|
|
_header(test_name, actual_hash, actual_hash)
|
|
|
|
|
|
|
|
with table(border=1):
|
|
|
|
with tr():
|
|
|
|
th("Recorded")
|
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
for screen in actual_screens:
|
2020-01-07 14:42:55 +00:00
|
|
|
with tr():
|
2020-01-09 14:25:45 +00:00
|
|
|
_image(screen)
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
return _write(REPORTS_PATH / "passed", doc, test_name + ".html")
|