pytest-html extras customizing code understanding

1k views Asked by At

I'm trying to customize report.html of pytest using pytest-html plugin.

I searched up many sites(including pytest-html documentation) and found that the code below is commonly used.(The code is in conftest.py)

(https://pytest-html.readthedocs.io/en/latest/user_guide.html#extra-content)

@pytest.hookimpl(hookwrapper = True)
def pytest_runtest_makereport(item, call):
    pytest_html = item.config.pluginmanager.getplugin("html")
    outcome = yield
    report = outcome.get_result()
    extra = getattr(report, "extra", [])
    if report.outcome == "call":
        #always add url to report
        xfail = hasattr(report, "wasxfail")
        if (report.skipped and xfail) or (report.failed and not xfail):
            extra.append(pytest_html.extras.url("http://www.google.com/"))
            extra.append(pytest_html.extras.text('Hi', name = 'TEXT'))
            # only add additional html on failure
            # extra.append(pytest_html.extras.html("<div>Additional HTML</div>"))
        report.extra = extra

However, I have no idea of each lines.

No one explained what the line does actually.

Why does the script allocates yield keyword to outcome with out any variable(e.g. yield 1), and what does yield.get_result() actually do?

Also, I have no idea of xfail("wasxfail").

I found that @pytest.xfail makes the test function fail in the pytest run, but I think it has nothing to do with the above code.

Why don't we use 'fail' not 'xfail'?

Anyway, what I need is

First, the meaning of each line and what it does.

Second, I wanna set different message in the report.html depending on the pass/fail.

I tried python report.outcome == 'failed', report.outcome == 'passed' to divide conditions, but it didn't work.

Third, when adding the text not url, it becomes tag and helps redirecting the page containing the text.

However, if I click the page in the html, it opens about:blank page not the desired one.

Using right click and open in new tab redirects to the desired one.

Any help is welcomed. Thanks.


+ I have more questions, I tried

if report.passed:
    extra.append(pytest_html.extras.url("https://www.google.com/")
report.extra = extra

It attaches 3 same links in the report.html(Results table) How can I handle it?

+ I could log a message when test is failed like msg = 'hi', pytest.fail(msg) However, I cannot get a clue to do it when the test is passed.

1

There are 1 answers

5
dosas On BEST ANSWER

Trying to answer as many lines as possible.

Pytest uses generators to iterate over the report steps.

The function pytest_runtest_makereport iterates over every result.when (not .outcome, this is a bug in the documentation) which according to pytest are as follows: 'collect', 'setup', 'call', and 'teardown'.

The get_result is how pytest implements its hooks.

The confusion about failed and xfail (expected to fail) is how you define a test failure: It is an error if it was skipped but was expected to fail or if it failed but was not expected to fail.

The thing with the about:blank could also be a bug.

What you want to use your if statements on is not the call info but the report:

if report.failed:
    do_stuff()
if report.passed:
    do_stuff_different()

One way to get more info about code and its context would be to debug it using breakpoint().

So the snippet you are looking for is:

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    pytest_html = item.config.pluginmanager.getplugin("html")
    outcome = yield
    report = outcome.get_result()
    extra = getattr(report, "extra", [])
    if report.when == "call":
        xfail = hasattr(report, "wasxfail")
        if (report.skipped and xfail) or (report.failed and not xfail):
            extra.append(pytest_html.extras.url("http://www.google.com/"))
        if report.passed:
            extra.append(pytest_html.extras.url("http://www.stackoverflow.com/"))
        report.extra = extra