This commit is contained in:
Maxime Jacob 2020-02-05 17:15:36 -05:00
commit 753ca944ea
4 changed files with 103 additions and 27 deletions

View File

@ -7,6 +7,7 @@ FORMAT_IMAGE = "image"
FORMAT_JSON = "json"
FORMAT_TEXT = "text"
FORMAT_URL = "url"
FORMAT_VIDEO = "video"
def extra(content, format, name=None, mime_type=None, extension=None):
@ -49,3 +50,11 @@ def text(content, name="Text"):
def url(content, name="URL"):
return extra(content, FORMAT_URL, name)
def video(content, name="Video", mime_type="video/mp4", extension="mp4"):
return extra(content, FORMAT_VIDEO, name, mime_type, extension)
def mp4(content, name="Video"):
return video(content, name)

View File

@ -181,33 +181,7 @@ class HTMLReport:
def append_extra_html(self, extra, extra_index, test_index):
href = None
if extra.get("format") == extras.FORMAT_IMAGE:
content = extra.get("content")
try:
is_uri_or_path = content.startswith(("file", "http")) or isfile(
content
)
except ValueError:
# On Windows, os.path.isfile throws this exception when
# passed a b64 encoded image.
is_uri_or_path = False
if is_uri_or_path:
if self.self_contained:
warnings.warn(
"Self-contained HTML report "
"includes link to external "
"resource: {}".format(content)
)
html_div = html.a(html.img(src=content), href=content)
elif self.self_contained:
src = "data:{};base64,{}".format(extra.get("mime_type"), content)
html_div = html.img(src=src)
else:
content = b64decode(content.encode("utf-8"))
href = src = self.create_asset(
content, extra_index, test_index, extra.get("extension"), "wb"
)
html_div = html.a(html.img(src=src), href=href)
self.additional_html.append(html.div(html_div, class_="image"))
self._append_image(extra, extra_index, test_index)
elif extra.get("format") == extras.FORMAT_HTML:
self.additional_html.append(html.div(raw(extra.get("content"))))
@ -235,6 +209,9 @@ class HTMLReport:
elif extra.get("format") == extras.FORMAT_URL:
href = extra.get("content")
elif extra.get("format") == extras.FORMAT_VIDEO:
self._append_video(extra, extra_index, test_index)
if href is not None:
self.links_html.append(
html.a(
@ -276,6 +253,52 @@ class HTMLReport:
log.append("No log output captured.")
additional_html.append(log)
def _make_media_html_div(
self, extra, extra_index, test_index, base_extra_string, base_extra_class
):
content = extra.get("content")
try:
is_uri_or_path = content.startswith(("file", "http")) or isfile(content)
except ValueError:
# On Windows, os.path.isfile throws this exception when
# passed a b64 encoded image.
is_uri_or_path = False
if is_uri_or_path:
if self.self_contained:
warnings.warn(
"Self-contained HTML report "
"includes link to external "
f"resource: {content}"
)
html_div = html.a(
raw(base_extra_string.format(extra.get("content"))), href=content
)
elif self.self_contained:
src = f"data:{extra.get('mime_type')};base64,{content}"
html_div = raw(base_extra_string.format(src))
else:
content = b64decode(content.encode("utf-8"))
href = src = self.create_asset(
content, extra_index, test_index, extra.get("extension"), "wb"
)
html_div = html.a(class_=base_extra_class, target="_blank", href=href)
return html_div
def _append_image(self, extra, extra_index, test_index):
image_base = '<img src="{}"/>'
html_div = self._make_media_html_div(
extra, extra_index, test_index, image_base, "image"
)
self.additional_html.append(html.div(html_div, class_="image"))
def _append_video(self, extra, extra_index, test_index):
video_base = '<video controls><source src="{}" type="video/mp4"></video>'
html_div = self._make_media_html_div(
extra, extra_index, test_index, video_base, "video"
)
self.additional_html.append(html.div(html_div, class_="video"))
def _appendrow(self, outcome, report):
result = self.TestResult(outcome, report, self.logfile, self.config)
if result.row_table is not None:

View File

@ -113,6 +113,19 @@ div.image {
div.image img {
width: 320px
}
div.video {
border: 1px solid #e6e6e6;
float: right;
height: 240px;
margin-left: 5px;
overflow: hidden;
width: 320px
}
div.video video {
overflow: hidden;
width: 320px;
height: 240px;
}
.collapsed {
display: none;
}

View File

@ -418,6 +418,37 @@ class TestHTML:
self.test_extra_image(testdir, "image/png", "png")
assert mock_isfile.call_count == 1
@pytest.mark.parametrize(
"mime_type, extension", [("video/mp4", "mp4")],
)
def test_extra_video(self, testdir, mime_type, extension):
content = str(random.random())
testdir.makeconftest(
f"""
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.when == 'call':
from pytest_html import extras
report.extra = [extras.{extension}('{content}')]
"""
)
testdir.makepyfile("def test_pass(): pass")
result, html = run(testdir, "report.html", "--self-contained-html")
assert result.ret == 0
src = f"data:{mime_type};base64,{content}"
assert (
f'<video controls><source src="{src}" type="{mime_type}"></video>' in html
)
def test_extra_video_windows(self, mocker, testdir):
mock_isfile = mocker.patch("pytest_html.plugin.isfile")
mock_isfile.side_effect = ValueError("stat: path too long for Windows")
self.test_extra_video(testdir, "video/mp4", "mp4")
assert mock_isfile.call_count == 1
@pytest.mark.parametrize(
"content", [("u'\u0081'"), ("'foo'"), ("b'\\xe2\\x80\\x93'")]
)