Search code examples
pythonpytestpytest-html

Pytest HTML report: how to get the name of the report file?


I am using pytest with pytest-html module to generate an HTML test report.

In the tear-down stage I automatically open the generated HTML report in the browser with webbrowser.open('file:///path_to_report.html') — this works fine, but I am running the test with different arguments and for each set of arguments I am setting a different report file via command line arguments:

pytest -v mytest.py::TestClassName --html=report_localhost.html

My tear-down code looks like this:

@pytest.fixture(scope='class')
def config(request):
    claz = request.cls
    claz.host = request.config.getoption("--host", default=HOST_DEFAULT)
    ...

    def teardown_env():
        print('destroying test harness')
        webbrowser.open("file:///path_to_report_localhost.html")

    request.addfinalizer(teardown_env)

    return "prepare_env"

The question is how to access the report file name from the tear-down hook in the test so that instead of hard-coding it I can use whatever path was passed in as command line argument, i.e. --html=report_for_host_xyz.html?

⚠️ Update

Using a class-scoped fixture for displaying the generated HTML is not the correct approach because pytest-html hooks the report generation into the session finalizer scope which means that by the time the class finalizer is called the report is still not generated and you might need to refresh the browser page to actually see the report. And if it seems to work it's only because the browser window might take some extra seconds to open which might allow the report generation to finish by the time the file is loaded in the browser.

The correct way to do it is explained in this answer and boils down to using the pytest_unconfigure hook.


Solution

  • You can put a breakpoint in the fixture, and look into request.config.option object — this is where pytest puts all the argparsed's keys.

    The one that you look for is request.config.option.htmlpath.

    @pytest.fixture(scope='class')
    def config(request):
        claz = request.cls
        claz.host = request.config.getoption("--host", default=HOST_DEFAULT)
    
        yield 100   # a value of the fixture for the tests
    
        print('destroying test harness')
        webbrowser.open("file:///{}".format(request.config.option.htmlpath))
    

    Or you can do the same as for the --host key:

    @pytest.fixture(scope='class')
    def config(request):
        claz = request.cls
        claz.host = request.config.getoption("--host", default=HOST_DEFAULT)
    
        yield 100   # a value of the fixture for the tests
    
        print('destroying test harness')
        webbrowser.open("file:///{}".format(request.config.getoption("--html")))