Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make async functions support in pytest hooks #13059

Open
NadezhdaBel opened this issue Dec 14, 2024 · 2 comments
Open

Make async functions support in pytest hooks #13059

NadezhdaBel opened this issue Dec 14, 2024 · 2 comments

Comments

@NadezhdaBel
Copy link

What's the problem this feature will solve?

I'm trying to make scteenshots on test failture.
The ways I found in internet is to make it via pytest_runtest_makereport hook.

Somthing like:

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()

    if rep.when == "call" and rep.failed:
        page = item.funcargs["async_page"]
        full_path = "some_path"
        page.screenshot(path=f"{full_path}")
        logging.debug(f"Screenshot saved: {full_path}")

But I got an error: RuntimeWarning: coroutine 'Page.screenshot' was never awaited

The reason of error is that async_page fixture is async:

import pytest_asyncio
from playwright.async_api import Page, async_playwright
from typing import AsyncGenerator


@pytest_asyncio.fixture
async def async_page() -> AsyncGenerator[Page]:
    async with async_playwright() as playwright:
        browser = await playwright.chromium.launch(headless=False)
        context = await browser.new_context(viewport={"width": 1440, "height": 900})
        page = await context.new_page()

        yield page

Describe the solution you'd like

I'd like to have an option to call async functions in Pytest hook.
Or if there are any solutions already exiss, please tell me)

@RonnyPfannschmidt
Copy link
Member

This is pending/planned in pluggy and possibly needs recoloring of pytest core

Datasette currently uses the maybe async pattern as workaround

However that's less feasible in pytest due to function coloring

@NadezhdaBel
Copy link
Author

NadezhdaBel commented Dec 17, 2024

Thank you for the answer!
Maybe async pattern did not work in our case. But we found another way to solve this problem, I desided to post it here if someone else needed to make screenshot on failed tests for async Playwright:

  1. Call make screenshot in the separate async function:
from pathlib import Path
from playwright.async_api import Page

async def save_screenshot(page: Page, path: Path) -> None:
    await page.screenshot(path=str(path))
  1. Call this function in the pytest_runtest_makereport in the loop:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item):
    outcome = yield
    rep = outcome.get_result()

    if rep.when == "call" and rep.failed:
        page = item.funcargs["async_page"]
        full_path = "some_path"
        loop = asyncio.get_event_loop()
        loop.run_until_complete(save_screenshot(page, full_path))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants