microsoft / playwright-pytest

Pytest plugin to write end-to-end browser tests with Playwright.
https://playwright.dev/python/docs/test-runners
Apache License 2.0
440 stars 69 forks source link

[FEATURE] Expose Playwright async/await flavor #74

Open maratori opened 3 years ago

maratori commented 3 years ago

I need to run aiohttp server and use playwright in tests at the same time. Am I right that pytest-playwright right now can't help me with that?

It provides fixtures only for sync API. But I need async API. So I have to do something like that.

from aiohttp import web
from playwright.async_api import async_playwright

async def index_html(request):
    return web.Response(body="<html><body>Hello world</body></html>", content_type="text/html")

async def test_without_page_fixture_passes(aiohttp_server):
    app = web.Application()
    app.router.add_get("/", index_html)
    server = await aiohttp_server(app)
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        context = await browser.new_context()
        page = await context.new_page()
        await page.goto(str(server.make_url("/")))
        assert await page.text_content("body") == "Hello world"
mxschmitt commented 3 years ago

Exactly, currently the pytest plugin does only provide the sync APIs. So you need to launch browser etc. yourself, something similar to https://github.com/microsoft/playwright-python/blob/master/tests/async/conftest.py

Shall I rename this issue title into a feature request for providing also the async flavor?

maratori commented 3 years ago

Thanks.

Shall I rename this issue title into a feature request for providing also the async flavor?

Sure, go ahead.

dwiyatci commented 2 years ago

Exactly, currently the pytest plugin does only provide the sync APIs. So you need to launch browser etc. yourself, something similar to https://github.com/microsoft/playwright-python/blob/master/tests/async/conftest.py

Shall I rename this issue title into a feature request for providing also the async flavor?

@mxschmitt I'm on Playwright v1.17 and I did try to copy-paste all the fixtures in the file you pointed here (except the utils), but then I got:

E       fixture 'launch_arguments' not found
>       available fixtures: _verify_url, base_url, browser, browser_channel, browser_context_args, browser_factory, browser_name, browser_type, browser_type_launch_args, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, context, context_factory, delete_output_dir, device, doctest_namespace, event_loop, is_chromium, is_firefox, is_webkit, launch_browser, monkeypatch, page, password, playwright, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, report_name, selectors, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, username
>       use 'pytest --fixtures [testpath]' for help on them.

I quickly fixed it by changing launch_arguments to browser_type_launch_args, but then again, I got:

playwright = <async_generator object playwright at 0x111459d40>, browser_name = 'chromium'

    @pytest.fixture(scope="session")
    def browser_type(playwright, browser_name: str):
        if browser_name == "chromium":
>           return playwright.chromium
E           AttributeError: 'async_generator' object has no attribute 'chromium'

conftest.py:20: AttributeError

I'm pretty new to Python and pytest but I guess async_generator of playwright_object instead of playwright_object itself being "injected" to browser_type – any pointer on how I should remedy this? And is this async gonna be planned to be supported in the end? 😅 Thank you.

mxschmitt commented 2 years ago

@dwiyatci why do you prefer async over sync? Understanding this use-case for the testing scenario would us help to prioritize it.

dwiyatci commented 2 years ago

@mxschmitt I would like to implement a custom wait_for_network_settled function like this (https://github.com/microsoft/playwright/issues/7856#issuecomment-928074716), and I believe it'd be much easier if I could have asyncio in place.

fscherf commented 2 years ago

@mxschmitt: I want to use this plugin together with aiohttp-pytest, because my project is based on aiohttp. Thats the reason why @maratori and i prefer (in this case) async over sync.

baiyyee commented 2 years ago

any updates for this feature?

nathanielobrown commented 1 year ago

It is very odd that there are async/sync versions of Playwright Python but the integration with pytest only supports sync. If the primary purpose of Playwright is to write tests, but the async version cannot be used with the dominant test framework, then what is the async version's purpose? If the async version is intended for applications other than testing, then this is still odd as we'd likely want to use pytest to test that code.

On a more pragmatic level, as more and more applications are written using async libraries, more and more tests will need to be async. Also, having async tests allows us to use some cleaner semantics for things like processes that happen in parallel.

There's also the issue (https://github.com/microsoft/playwright-python/issues/1339#issuecomment-1355470204) I ran into that we can't even mix async/sync tests in the same test suite and use playwright-pytest.

@mxschmitt, do you have pointers on how hard this would be/what would need to be done?

mxschmitt commented 1 year ago

@nathanielobrown I totally agree that providing an async layer would be cool! The reason why we didn't do it yet was that its more idiomatic to write tests in sync mode (debugging, you don't need to install other pytest plugins, REPL just works etc).

Regarding how hard it is to implement, I think it hardly depends on the question how much code we want to duplicate. In general the pytest-playwright plugin is not a lot of code, to provide an async version, we could in theory just copy it and use the async version of Playwright and it should just work™️ . Something where I'm not sure about is if we need a dedicated plugin (PIP package) for the async version or if we can internally detect somehow if its async or sync and then do conditional logic. This requires some investigation.

(happy to accept patches for it, just not something we prioritise, since not a lot of users have requested it so far.)

nathanielobrown commented 1 year ago

@mxschmitt, that's great to hear there is no technical blocker. My initial thought would be to add new fixtures to the same package with _async suffixes, like page_async. Then users can mix/match/migrate to their hearts content. Auto detection would be cool, but even if there's a way to do that I feel like that would be more likely to cause issues and it's not to much load to just use different fixture names.

Also this fix (https://github.com/microsoft/playwright-python/issues/1339#issuecomment-1596985543) for the multiple event loops issue just worked from me and is topical.

I'll probably work something up locally and if it works well can create a PR.

m9810223 commented 1 year ago

Hey guys! I made a plugin https://github.com/m9810223/playwright-async-pytest that support async playwright for my projects. It refers to original plugin, welcome to use it if you need!

balazs-ita-epam commented 1 year ago

Waiting for the async feature in pytest!

blooser commented 5 months ago

Hey!

What is the status of the feature?

louisabraham commented 3 months ago

Hi! Any update? We need this as well :)

Lendemor commented 3 months ago

We also need this feature to fully adopt playwright in our integration tests.

balazs-ita-epam commented 1 month ago

Please prioritize higher to implement the python - Playwright with async.

mxschmitt commented 8 hours ago

While we prepare things for releasing it as a separate package, here are instructions to install it from source for now, curious to hear your thoughts!

  1. virtualenv env && source env/bin/activate
  2. pip install -e "git+https://github.com/microsoft/playwright-pytest#egg=pytest-playwright-asyncio&subdirectory=pytest-playwright-asyncio"
  3. playwright install
  4. Create test_foo.py
    
    import pytest

@pytest.mark.asyncio(loop_scope="session") async def test_foo(page): await page.goto("https://github.com")



I saw that https://github.com/m9810223/playwright-async-pytest is based on anyio, not sure whats the standard nowadays.
m9810223 commented 6 hours ago

That's great news! 🎉

@mxschmitt

I later modified https://github.com/m9810223/playwright-async-pytest to use anyio for the following reasons:

ref: https://github.com/m9810223/playwright-async-pytest/issues/8

mxschmitt commented 5 hours ago

I'm curious to what the community currently is mostly using when testing with Pytest. I tried to find anyio in this survey but didn't see any mentions. I understand the benefit of not having to wrap them into custom fixtures / mark them.

I think the mark issue is solved by this - thats what projects are usually using nowadays afaik.

Using anyio also allows compatibility with Python's built-in asyncio.

Do you mind elaborating on that?