I use the Playwright (sync) library to automate UI testing with Python. I wrote some test cases and everything worked fine like this. start_page is a fixture that handles opening the browser, logging in and navigating to the start page.
def test_my_test_case(start_page: Page):
page.goto(URL)
But when changing a test case to async like this:
@pytest.mark.asyncio
async def test_my_test_case(start_page: Page):
page.goto(URL)
I started getting this error:
Failed: [undefined]Failed: Unexpected err=RuntimeError("Task <Task pending name='Task-12' coro=<Page.goto() running at
...\\_page.py:495> cb=[SyncBase._sync.<locals>.<lambda>() at
...\\_sync_base.py:100]> got Future <Future pending> attached to a different loop"), type(err)=<class 'RuntimeError'>
In the Playwright library I found this code:
try:
self._loop = asyncio.get_running_loop()
except RuntimeError:
self._loop = asyncio.new_event_loop()
self._own_loop = True
While I have a fixture in my tests that creates an own event_loop:
@pytest.fixture(scope="module")
def event_loop():
nest_asyncio.apply()
loop = asyncio.new_event_loop()
yield loop
loop.close()
I figured out that I have to make loop the running loop so that Playwright uses the same loop as my tests. When I add asyncio._set_running_loop(loop)
like this:
@pytest.fixture(scope="module")
def event_loop():
nest_asyncio.apply()
loop = asyncio.new_event_loop()
>>> asyncio._set_running_loop(loop)
yield loop
loop.close()
Everything works fine, but this does not seem like a good practice.I can not call run as there is no function to call it on.
Any solutions?
I found a solution, I just had to switch to the async_api of playwright.
import asyncio
import nest_asyncio
import pytest
import pytest_asyncio
from playwright.async_api import async_playwright, Page
@pytest.fixture(scope="module")
def event_loop():
nest_asyncio.apply()
loop = asyncio.new_event_loop()
yield loop
loop.close()
@pytest_asyncio.fixture(scope="module")
@pytest.mark.asyncio
async def my_page() -> None:
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=False, slow_mo=500)
page = await browser.new_page()
yield page
await browser.close()
@pytest.mark.asyncio
async def test_my_test_case(my_page: Page):
await my_page.goto(URL)
I will update my existing tests and hope that everything works.