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
|
2020-01-09 14:25:45 +00:00
|
|
|
from pathlib import Path
|
2022-01-28 18:26:03 +00:00
|
|
|
from typing import Dict
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
import dominate
|
2021-06-22 09:01:29 +00:00
|
|
|
import dominate.tags as t
|
2020-03-03 14:50:57 +00:00
|
|
|
from dominate.tags import div, h1, h2, hr, p, strong, table, th, tr
|
2020-02-18 09:20:02 +00:00
|
|
|
from dominate.util import text
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2020-03-03 14:50:57 +00:00
|
|
|
from . import download, html
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2022-01-28 15:02:17 +00:00
|
|
|
HERE = Path(__file__).resolve().parent
|
2021-06-22 09:01:29 +00:00
|
|
|
REPORTS_PATH = HERE / "reports" / "test"
|
|
|
|
|
|
|
|
STYLE = (HERE / "testreport.css").read_text()
|
|
|
|
SCRIPT = (HERE / "testreport.js").read_text()
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
ACTUAL_HASHES: Dict[str, str] = {}
|
2021-06-22 09:01:29 +00:00
|
|
|
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
def document(
|
|
|
|
title: str, actual_hash: str = None, index: bool = False
|
|
|
|
) -> dominate.document:
|
2021-06-22 09:01:29 +00:00
|
|
|
doc = dominate.document(title=title)
|
|
|
|
style = t.style()
|
|
|
|
style.add_raw_string(STYLE)
|
|
|
|
script = t.script()
|
|
|
|
script.add_raw_string(SCRIPT)
|
|
|
|
doc.head.add(style, script)
|
|
|
|
|
|
|
|
if actual_hash is not None:
|
|
|
|
doc.body["data-actual-hash"] = actual_hash
|
|
|
|
|
|
|
|
if index:
|
|
|
|
doc.body["data-index"] = True
|
|
|
|
|
|
|
|
return doc
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
def _header(test_name: str, expected_hash: str, actual_hash: str) -> None:
|
2020-01-07 14:42:55 +00:00
|
|
|
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()
|
|
|
|
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
def clear_dir() -> None:
|
2020-01-09 14:25:45 +00:00
|
|
|
# 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()
|
|
|
|
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
def index() -> Path:
|
2020-01-10 13:25:52 +00:00
|
|
|
passed_tests = list((REPORTS_PATH / "passed").iterdir())
|
|
|
|
failed_tests = list((REPORTS_PATH / "failed").iterdir())
|
2020-01-10 08:32:04 +00:00
|
|
|
|
2020-01-09 14:25:45 +00:00
|
|
|
title = "UI Test report " + datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
2021-06-22 09:01:29 +00:00
|
|
|
doc = document(title=title, index=True)
|
2020-01-09 14:25:45 +00:00
|
|
|
|
|
|
|
with doc:
|
|
|
|
h1("UI Test report")
|
2020-01-09 14:37:15 +00:00
|
|
|
if not failed_tests:
|
2020-01-09 14:25:45 +00:00
|
|
|
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;")
|
2021-06-22 09:01:29 +00:00
|
|
|
with p(id="file-hint"):
|
|
|
|
strong("Tip:")
|
|
|
|
text(" use ")
|
|
|
|
t.span("./tests/show_results.sh", style="font-family: monospace")
|
|
|
|
text(" to enable smart features.")
|
|
|
|
|
|
|
|
with div("Test colors", _class="script-hidden"):
|
|
|
|
with t.ul():
|
|
|
|
with t.li():
|
|
|
|
t.span("new", style="color: blue")
|
|
|
|
t.button("clear all", onclick="resetState('all')")
|
|
|
|
with t.li():
|
|
|
|
t.span("marked OK", style="color: grey")
|
|
|
|
t.button("clear", onclick="resetState('ok')")
|
|
|
|
with t.li():
|
|
|
|
t.span("marked BAD", style="color: darkred")
|
|
|
|
t.button("clear", onclick="resetState('bad')")
|
|
|
|
|
|
|
|
html.report_links(failed_tests, REPORTS_PATH, ACTUAL_HASHES)
|
2020-01-09 14:25:45 +00:00
|
|
|
|
|
|
|
h2("Passed", style="color: green;")
|
2020-03-03 14:50:57 +00:00
|
|
|
html.report_links(passed_tests, REPORTS_PATH)
|
2020-01-09 14:25:45 +00:00
|
|
|
|
2020-03-03 14:50:57 +00:00
|
|
|
return html.write(REPORTS_PATH, doc, "index.html")
|
2020-01-09 14:25:45 +00:00
|
|
|
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
def failed(
|
|
|
|
fixture_test_path: Path, test_name: str, actual_hash: str, expected_hash: str
|
|
|
|
) -> Path:
|
2021-06-22 09:01:29 +00:00
|
|
|
ACTUAL_HASHES[test_name] = actual_hash
|
|
|
|
|
|
|
|
doc = document(title=test_name, actual_hash=actual_hash)
|
2020-01-07 14:42:55 +00:00
|
|
|
recorded_path = fixture_test_path / "recorded"
|
|
|
|
actual_path = fixture_test_path / "actual"
|
|
|
|
|
2020-02-18 09:20:02 +00:00
|
|
|
download_failed = False
|
|
|
|
|
2020-01-07 14:42:55 +00:00
|
|
|
if not recorded_path.exists():
|
|
|
|
recorded_path.mkdir()
|
2020-02-18 09:20:02 +00:00
|
|
|
try:
|
|
|
|
download.fetch_recorded(expected_hash, recorded_path)
|
|
|
|
except Exception:
|
|
|
|
download_failed = True
|
2020-01-07 14:42:55 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
with doc:
|
|
|
|
_header(test_name, expected_hash, actual_hash)
|
|
|
|
|
2021-06-22 09:01:29 +00:00
|
|
|
with div(id="markbox", _class="script-hidden"):
|
|
|
|
p("Click a button to mark the test result as:")
|
|
|
|
with div(id="buttons"):
|
|
|
|
t.button("OK", id="mark-ok", onclick="markState('ok')")
|
|
|
|
t.button("BAD", id="mark-bad", onclick="markState('bad')")
|
|
|
|
|
2020-02-18 09:20:02 +00:00
|
|
|
if download_failed:
|
|
|
|
with p():
|
|
|
|
strong("WARNING:")
|
|
|
|
text(" failed to download recorded fixtures. Is this a new test case?")
|
|
|
|
|
2020-01-07 14:42:55 +00:00
|
|
|
with table(border=1, width=600):
|
|
|
|
with tr():
|
|
|
|
th("Expected")
|
|
|
|
th("Actual")
|
|
|
|
|
2020-03-03 14:50:57 +00:00
|
|
|
html.diff_table(recorded_screens, actual_screens)
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2020-03-03 14:50:57 +00:00
|
|
|
return html.write(REPORTS_PATH / "failed", doc, test_name + ".html")
|
2020-01-07 14:42:55 +00:00
|
|
|
|
|
|
|
|
2022-01-28 18:26:03 +00:00
|
|
|
def passed(fixture_test_path: Path, test_name: str, actual_hash: str) -> Path:
|
2020-01-07 14:42:55 +00:00
|
|
|
copy_tree(str(fixture_test_path / "actual"), str(fixture_test_path / "recorded"))
|
|
|
|
|
2021-06-22 09:01:29 +00:00
|
|
|
doc = document(title=test_name)
|
2020-01-07 14:42:55 +00:00
|
|
|
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-03-03 14:50:57 +00:00
|
|
|
html.image(screen)
|
2020-01-07 14:42:55 +00:00
|
|
|
|
2020-03-03 14:50:57 +00:00
|
|
|
return html.write(REPORTS_PATH / "passed", doc, test_name + ".html")
|