Description
Hello everyone!
I am experiencing inconsistent behaviour when using async/sync fixtures. Our tests using pyppeteer
(Python wrapper around Google's Puppeteer library). Almost all pyppeteer
methods are async. A common code will look like so:
from pyppeteer import launch
browser = await launch()
page = await browser.newPage()
await page.goto('http://example.com')
await page.screenshot({'path': 'example.png'})
await browser.close()
So in order to be able to run async tests, I'm using pytest-asyncio
(and there actually an integration bug between pytest-asyncio
and pyppeteer
. A bug was opened on the pytest-asyncio
that explains the issue). The above share a common code that should get executed before every test:
browser = await launch()
page = await browser.newPage()
and at the end of each test:
await browser.close()
So obviously, a fixture is needed here.
@pytest.fixture()
async def page():
browser = await launch()
page = await browser.newPage()
yield page
await browser.close()
The above will work properly if using a normal fixture (like seen in the sftp client example on the official documentation), and while it's a bit confusing yield returns a value and not an iterator - there no problem with using the fixture. But unlike yield
in a non-async fixture, the yield here will not return the value of page
, but instead will return an async-generator. So the following test will fail:
@pytest.mark.asyncio
async def test_some_test(page)
await page.goto('http://example.com')
with the following error: AttributeError: 'async_generator' object has no attribute 'goto'
. The only way around it is to manually iterate over async generator so the test will look like so:
@pytest.mark.asyncio
async def test_some_test(page)
async for x in page:
await page.goto('http://example.com')
It that the right way of doing it? because it seems a bit cumbersome and contradict how yield works on non-async methods.
Thanks!