Screenshots
Images attached while the tests ran, beside the suite and the error they belong to
%(attach_screenshot_details)%
No screenshots in this run
Hand attach the PNG bytes of a screenshot and it is kept against the
test that took it, with the suite and the error it belongs to beside it.
1Attach an image
attach takes the picture, not the browser, so every framework goes
through the same call - Selenium, Playwright, or anything else that can
produce a PNG.
from pytest_html_reporter import attach attach(data=driver.get_screenshot_as_png()) # Selenium attach(data=page.screenshot()) # Playwright attach(data=await page.screenshot()) # Playwright, async API
2Better: one hook, both drivers, failures onlyrecommended
The browser is already in item.funcargs, so a single hook covers
Selenium and Playwright at once - no fixture of its own, and nothing to
remember in each test. Running both? Add the fixture name to the table and
that framework is covered too.
# conftest.py import pytest from pytest_html_reporter import attach CAPTURE = { "driver": lambda driver: driver.get_screenshot_as_png(), # Selenium "page": lambda page: page.screenshot(), # Playwright } @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() if report.when != "call" or not report.failed: return for name, capture in CAPTURE.items(): handle = item.funcargs.get(name) if handle is not None: attach(data=capture(handle)) return
Put the hook in conftest.py. pytest picks one up from a test module
too, but only for that module's own tests - a conftest covers every test
under it. Drop the report.failed check to photograph every test.
3Async tests, and unittest
The hook above is synchronous, so an async Playwright test has nowhere
to await - attach from the body instead. A unittest suite attaches
from tearDown, which still runs while the driver is open.
async def test_home(page): # Playwright, async API try: assert await page.title() == "Example Domain" except AssertionError: attach(data=await page.screenshot()) raise def tearDown(self): # unittest attach(data=self.driver.get_screenshot_as_png()) self.driver.quit() # after, never before
Every image you attach is kept, whatever the test did - a screenshot of a pass
is a baseline worth having. Only the tests that called attach show up
here, so capturing failures alone is a matter of when you call it.