Search code examples
pythonpytestplaywrightplaywright-python

Is it possible to yield a playwright object in a fixture for reuse?


I am learning how to use pytest and keep running into an issue with fixtures.

Below is the source from the test file:

import asyncio, pytest
from SingletonObject import SObject
from playwright.async_api import expect, async_playwright

@pytest.fixture
async def playwright_instance():
    async with async_playwright() as playwright:
        yield playwright

async def test_for_SObject_connectivity():
    async with async_playwright() as playwright_instance:
        # Create a single instance of SObject with the playwright instance passed in
        test = SObject(playwright_instance) 
        # Opens up a new tab and navigates it to a defined url
        await test.start() 
        # Ensures that the page is actually loaded to the defined url
        await expect(test.search_page).to_have_url("[specific url]")

I am trying to have the SObject represent a "website as a module" to perform searches and download files, so I need to pass in the playwright object specifically for testing.

The issue I keep having is pytest doesn't end up returning the playwright instance, instead it just passes the function signature itself which causes a error in SObject since it is trying to grab a variable from the playwright object. Based on the pytest fixtures documentation it should "just work," but I'm not that lucky.

Doing it like this:

async def test_for_SObject_connectivity():
    async with async_playwright() as playwright_instance:
        test = SObject(playwright_instance)
        ...

does work, but I wanted to see if a fixture could be used instead.

I know that Playwright has a pytest plugin that lets me pass in a playwright object (Testing Playwright) but when I try to run the test method with it Playright passed in the test fails with RunetimeError: Cannot run the event loop while another loops is running. If I try to run pytest without using the pytest-asyncio plugin it complains that I'm trying to run tests without the plugin.

Could it be an issue with running inside a with statement? Or running asynchronously?


Solution

  • Are you passing in the fixture to your test? Based on your function signature comment, I suspect not. You need to explicitly pass it in unless autouse=True is set on the fixture.

    Try this:

    async def test_for_SObject_connectivity(playwright_instance):
        test = SObject(playwright_instance) 
        # Opens up a new tab and navigates it to a defined url
        await test.start() 
        # Ensures that the page is actually loaded to the defined url
        await expect(test.search_page).to_have_url("[specific url]")