Reputation: 410
I am trying to generate a self contained html report using pytest-html and selenium. I have been trying to imbedded screenshots into the report but they are not being displayed.
My conftest.py looks like this
@pytest.fixture()
def chrome_driver_init(request, path_to_chrome):
driver = webdriver.Chrome(options=opts, executable_path=path_to_chrome)
request.cls.driver = driver
page_object_init(request, driver)
driver.get(URL)
driver.maximize_window()
yield driver
driver.quit()
# Hook that takes a screenshot of the web browser for failed tests and adds it to the HTML report
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item):
pytest_html = item.config.pluginmanager.getplugin("html")
outcome = yield
report = outcome.get_result()
extra = getattr(report, "extra", [])
if report.when == "call":
feature_request = item.funcargs['request']
driver = feature_request.getfixturevalue('chrome_driver_init')
nodeid = item.nodeid
xfail = hasattr(report, "wasxfail")
if (report.skipped and xfail) or (report.failed and not xfail):
file_name = f'{nodeid}_{datetime.today().strftime("%Y-%m-%d_%H_%M")}.png'.replace("/", "_").replace("::", "_").replace(".py", "")
driver.save_screenshot("./reports/screenshots/"+file_name)
extra.append(pytest_html.extras.image("/screenshots/"+file_name))
report.extra = extra
I am convinced the problem is with the path to the image, and I have tried so many str combinations, os.path and pathlib but nothing has worked. The screenshot is being saved in the expected location and I can open it like any other image. Its just not displaying on the report.
<div class="image"><img src="data:image/png;base64,screenshots\scr_tests_test_example_TestExample_test_fail_example_2022-01-18_16_26.png"/></div>
EDIT: For addional clairification. I have tried to use absolute path in the extra.append
but it kept giving me a Cant Resolve File
error in the HTML file. My absoulte path was(with some personal details redacted) C:\Users\c.Me\OneDrive - Me\Documents\GitHub\project\build\reports\screenshots\filename.png
I have tried it with both '/' and '\'
Also my File structure
project
├───build
│ ├───reports
│ ├───screenshots
│ ├───filename.png
| ├───report.html
| ├───run.py # I am running the test suite from here
├───scr
| ├───settings.py
│ ├───tests
│ ├───confest.py
run.py
if __name__ == "__main__":
os.system(f"pytest --no-header -v ../scr/tests/ --html=./reports/Test_Report_{today}.html --self-contained-html")
For Prophet, may be bless me this day
To get the Cannot Resolve Directory
error my code is the following
file_name = f'{nodeid}_{datetime.today().strftime("%Y-%m-%d_%H_%M")}.png'.replace("/", "_").replace("::", "_").replace(".py", "")
img_path = os.path.join(REPORT_PATH, 'screenshots', file_name)
driver.save_screenshot(img_path)
extra.append(pytest_html.extras.image(img_path))
The variable REPORT_PATH
is imported from the settings.py (see directory tree above) and is created by
PROJ_PATH = Path(__file__).parent.parent
REPORT_PATH = PROJ_PATH.joinpath("build\reports")
also fun fact if I do img_path.replace("\\", "/")
the error changes to Cannot Resolve File
Upvotes: 4
Views: 4369
Reputation: 410
I have learned so much in this painful journey. Mostly I have learned I am an idiot. The problem was that I wanted to make a self contained HTML. Pytest-html does not work as expected with adding images to a self contained report. Before you can you have to convert the image into its text base64 version first. So the answers to all my owes was a single line of code.
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item):
pytest_html = item.config.pluginmanager.getplugin("html")
outcome = yield
report = outcome.get_result()
extra = getattr(report, "extra", [])
if report.when == "call":
feature_request = item.funcargs['request']
driver = feature_request.getfixturevalue('chrome_driver_init')
nodeid = item.nodeid
xfail = hasattr(report, "wasxfail")
if (report.skipped and xfail) or (report.failed and not xfail):
file_name = f'{nodeid}_{datetime.today().strftime("%Y-%m-%d_%H_%M")}.png'.replace("/", "_").replace("::", "_").replace(".py", "")
img_path = os.path.join(REPORT_PATH, "screenshots", file_name)
driver.save_screenshot(img_path)
screenshot = driver.get_screenshot_as_base64() # the hero
extra.append(pytest_html.extras.image(screenshot, ''))
report.extra = extra
Thank you Prophet for guiding on this pilgrimage. Now I must rest.
Upvotes: 10
Reputation: 33361
I'm not completely sure how it works with PyTest, however we have similar issue with Java Extent Manager.
There you have to pass the absolute path of the image file, not the relative path.
As I can see here the current working directory can be achieved as following:
import pathlib
pathlib.Path().resolve()
So, if I understand that correctly you should change your code from
extra.append(pytest_html.extras.image("/screenshots/"+file_name))
to
working_root = pathlib.Path().resolve()
extra.append(pytest_html.extras.image(working_root + "/screenshots/"+file_name))
UPD
I think you are missing a reports
subfolder here.
Instead of
working_root = pathlib.Path().resolve()
extra.append(pytest_html.extras.image(working_root + "/screenshots/"+file_name))
Try using
working_root = pathlib.Path().resolve()
extra.append(pytest_html.extras.image(working_root + "/reports/screenshots/"+file_name))
Upvotes: 2