Merge branch 'master' of https://github.com/pytest-dev/pytest-html
This commit is contained in:
commit
753ca944ea
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'")]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue