Skip to content

Commit f03b9d9

Browse files
committed
Added the CSS specification for the video class. It is pretty much a duplicate of the image css.
Code for the video extra has been extracted to a function to clean up a bit the if/elif/elif that is starting to get pretty big. Maybe the other conditions could be extracted to their own method to clean up a bit. Once again, there seems to be a lot of code duplication with image, so we may want to refactor images, videos, and audio as a media type and have some kind of template method. Basic unit tests were added to make sure that the extra was correctly added to the report when the extra was requested.
1 parent 8de28f6 commit f03b9d9

File tree

3 files changed

+75
-32
lines changed

3 files changed

+75
-32
lines changed

pytest_html/plugin.py

+31-32
Original file line numberDiff line numberDiff line change
@@ -236,38 +236,7 @@ def append_extra_html(self, extra, extra_index, test_index):
236236
href = extra.get("content")
237237

238238
elif extra.get("format") == extras.FORMAT_VIDEO:
239-
video_base = (
240-
'<video controls>\n<source src={} type="video/mp4">\n</video>'
241-
)
242-
content = extra.get("content")
243-
try:
244-
is_uri_or_path = content.startswith(("file", "http")) or isfile(
245-
content
246-
)
247-
except ValueError:
248-
# On Windows, os.path.isfile throws this exception when
249-
# passed a b64 encoded image.
250-
is_uri_or_path = False
251-
if is_uri_or_path:
252-
if self.self_contained:
253-
warnings.warn(
254-
"Self-contained HTML report "
255-
"includes link to external "
256-
"resource: {}".format(content)
257-
)
258-
259-
html_div = html.div(raw(video_base.format(extra.get("content"))))
260-
elif self.self_contained:
261-
src = "data:{};base64,{}".format(extra.get("mime_type"), content)
262-
html_div = html.div(raw(video_base.format(src)))
263-
else:
264-
content = b64decode(content.encode("utf-8"))
265-
href = src = self.create_asset(
266-
content, extra_index, test_index, extra.get("extension"), "wb"
267-
)
268-
269-
html_div = html.a(video_base.format(src), href=href)
270-
self.additional_html.append(html.div(html_div, class_="video"))
239+
self._append_video(extra, extra_index, test_index)
271240

272241
if href is not None:
273242
self.links_html.append(
@@ -310,6 +279,36 @@ def append_log_html(self, report, additional_html):
310279
log.append("No log output captured.")
311280
additional_html.append(log)
312281

282+
def _append_video(self, extra, extra_index, test_index):
283+
video_base = '<video controls><source src="{}" type="video/mp4"></video>'
284+
content = extra.get("content")
285+
try:
286+
is_uri_or_path = content.startswith(("file", "http")) or isfile(content)
287+
except ValueError:
288+
# On Windows, os.path.isfile throws this exception when
289+
# passed a b64 encoded image.
290+
is_uri_or_path = False
291+
if is_uri_or_path:
292+
if self.self_contained:
293+
warnings.warn(
294+
"Self-contained HTML report "
295+
"includes link to external "
296+
"resource: {}".format(content)
297+
)
298+
299+
html_div = html.div(raw(video_base.format(extra.get("content"))))
300+
elif self.self_contained:
301+
src = "data:{};base64,{}".format(extra.get("mime_type"), content)
302+
html_div = html.div(raw(video_base.format(src)))
303+
else:
304+
content = b64decode(content.encode("utf-8"))
305+
href = src = self.create_asset(
306+
content, extra_index, test_index, extra.get("extension"), "wb"
307+
)
308+
309+
html_div = html.a(video_base.format(src), href=href)
310+
self.additional_html.append(html.div(html_div, class_="video"))
311+
313312
def _appendrow(self, outcome, report):
314313
result = self.TestResult(outcome, report, self.logfile, self.config)
315314
if result.row_table is not None:

pytest_html/resources/style.css

+13
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ div.image {
113113
div.image img {
114114
width: 320px
115115
}
116+
div.video {
117+
border: 1px solid #e6e6e6;
118+
float: right;
119+
height: 240px;
120+
margin-left: 5px;
121+
overflow: hidden;
122+
width: 320px
123+
}
124+
div.video video {
125+
overflow: hidden;
126+
width: 320px;
127+
height: 240px;
128+
}
116129
.collapsed {
117130
display: none;
118131
}

testing/test_pytest_html.py

+31
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,37 @@ def test_extra_image_windows(self, mocker, testdir):
418418
self.test_extra_image(testdir, "image/png", "png")
419419
assert mock_isfile.call_count == 1
420420

421+
@pytest.mark.parametrize(
422+
"mime_type, extension", [("video/mp4", "mp4")],
423+
)
424+
def test_extra_video(self, testdir, mime_type, extension):
425+
content = str(random.random())
426+
testdir.makeconftest(
427+
f"""
428+
import pytest
429+
@pytest.hookimpl(hookwrapper=True)
430+
def pytest_runtest_makereport(item, call):
431+
outcome = yield
432+
report = outcome.get_result()
433+
if report.when == 'call':
434+
from pytest_html import extras
435+
report.extra = [extras.{extension}('{content}')]
436+
"""
437+
)
438+
testdir.makepyfile("def test_pass(): pass")
439+
result, html = run(testdir, "report.html", "--self-contained-html")
440+
assert result.ret == 0
441+
src = f"data:{mime_type};base64,{content}"
442+
assert (
443+
f'<video controls><source src="{src}" type="{mime_type}"></video>' in html
444+
)
445+
446+
def test_extra_video_windows(self, mocker, testdir):
447+
mock_isfile = mocker.patch("pytest_html.plugin.isfile")
448+
mock_isfile.side_effect = ValueError("stat: path too long for Windows")
449+
self.test_extra_video(testdir, "video/mp4", "mp4")
450+
assert mock_isfile.call_count == 1
451+
421452
@pytest.mark.parametrize(
422453
"content", [("u'\u0081'"), ("'foo'"), ("b'\\xe2\\x80\\x93'")]
423454
)

0 commit comments

Comments
 (0)