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
444 stars 69 forks source link

When I used fixture 'browser', why it didn't generate pictures and videos? #232

Closed floraachy closed 4 months ago

floraachy commented 4 months ago

I have configured pytest like this:

[pytest]
addopts =
    --tracing=on
    --screenshot=on
    --video=on

I write a new fixture 'user_page' in conftest, this page will load user cookies:

@pytest.fixture(scope="session")
def user_page(browser: Browser, base_url):
    """
    创建default_user_page, 加载default_user.json数据
    :return:
    """
    users = {
        "login": GLOBAL_VARS['default_user_login'],
        "password": GLOBAL_VARS['default_user_password']
    }
    if is_login_valid(users["login"]):
        context = browser.new_context(
            base_url=base_url,
            no_viewport=True,
            storage_state=is_login_valid(users["login"])
        )
        page = context.new_page()
    else:
        context = browser.new_context(
            base_url=base_url,
            no_viewport=True
        )
        page = page_login_save_cookies(users, context.new_page())

    yield page
    page.close()
    context.close()

When I run test, it didn't generate 'test_result' folder, and didn't generate pictures and videos.'

I want to know why it didn't generate pictures and videos?

mxschmitt commented 4 months ago

This is expected as of today. You need to use the new_context fixture:

@pytest.fixture(scope="session")
def user_page(new_context, base_url):
    """
    创建default_user_page, 加载default_user.json数据
    :return:
    """
    users = {
        "login": GLOBAL_VARS['default_user_login'],
        "password": GLOBAL_VARS['default_user_password']
    }
    if is_login_valid(users["login"]):
        context = new_context(
            base_url=base_url,
            no_viewport=True,
            storage_state=is_login_valid(users["login"])
        )
        page = context.new_page()
    else:
        context = new_context(
            base_url=base_url,
            no_viewport=True
        )
        page = page_login_save_cookies(users, context.new_page())

    yield page

then it should work.

floraachy commented 4 months ago

This is expected as of today. You need to use the new_context fixture:

@pytest.fixture(scope="session")
def user_page(new_context, base_url):
    """
    创建default_user_page, 加载default_user.json数据
    :return:
    """
    users = {
        "login": GLOBAL_VARS['default_user_login'],
        "password": GLOBAL_VARS['default_user_password']
    }
    if is_login_valid(users["login"]):
        context = new_context(
            base_url=base_url,
            no_viewport=True,
            storage_state=is_login_valid(users["login"])
        )
        page = context.new_page()
    else:
        context = new_context(
            base_url=base_url,
            no_viewport=True
        )
        page = page_login_save_cookies(users, context.new_page())

    yield page

then it should work.

If I used fixture 'new_context', It only can used as a function scope fixture, instead of sesssion scope fixture.

ScopeMismatch: You tried to access the 'function' scoped fixture 'new_context' with a 'session' scoped request object, involved factories
floraachy commented 4 months ago

This is expected as of today. You need to use the new_context fixture:

@pytest.fixture(scope="session")
def user_page(new_context, base_url):
    """
    创建default_user_page, 加载default_user.json数据
    :return:
    """
    users = {
        "login": GLOBAL_VARS['default_user_login'],
        "password": GLOBAL_VARS['default_user_password']
    }
    if is_login_valid(users["login"]):
        context = new_context(
            base_url=base_url,
            no_viewport=True,
            storage_state=is_login_valid(users["login"])
        )
        page = context.new_page()
    else:
        context = new_context(
            base_url=base_url,
            no_viewport=True
        )
        page = page_login_save_cookies(users, context.new_page())

    yield page

then it should work.

Also, new_context didn't have args: 'no_viewport', ’base_url'

    def _new_context(**kwargs: Any) -> BrowserContext:
>       context = browser.new_context(**browser_context_args, **kwargs)
E       TypeError: playwright.sync_api._generated.Browser.new_context() got multiple values for keyword argument 'no_viewport'

    def _new_context(**kwargs: Any) -> BrowserContext:
>       context = browser.new_context(**browser_context_args, **kwargs)
E       TypeError: playwright.sync_api._generated.Browser.new_context() got multiple values for keyword argument 'base_url'

This is the final code:

@pytest.fixture(scope="function")
def user_page(new_context):
    """
    创建default_user_page, 加载default_user.json数据
    :return:
    """
    users = {
        "login": GLOBAL_VARS['default_user_login'],
        "password": GLOBAL_VARS['default_user_password']
    }
    if is_login_valid(users["login"]):
        context = new_context(storage_state=is_login_valid(users["login"]))
        page = context.new_page()
    else:
        context = new_context()
        page = page_login_save_cookies(users, context.new_page())

    yield page
    page.close()
    context.close()

And another problem: when the case run success, it didn't generate picture. image

floraachy commented 4 months ago

I know the reason. I cannot close page and context in my own fixture.

This is the current code. This fixture only can use a function scope, instead of a session scope.

@pytest.fixture(scope="function")
def user_page(new_context):
    """
    创建default_user_page, 加载default_user.json数据
    :return:
    """
    users = {
        "login": GLOBAL_VARS['default_user_login'],
        "password": GLOBAL_VARS['default_user_password']
    }
    # 如果读取用户登录数据成功且用户cookies没有过期,则免登录
    if is_login_valid(users["login"]):
        context = new_context(storage_state=is_login_valid(users["login"]))
        page = context.new_page()
    else:
        # 读取用户登录数据失败或者已过期,需要登录
        context = new_context()
        page = page_login_save_cookies(users, context.new_page())

    yield page

Thank you for your answer.

mxschmitt commented 4 months ago

awesome, Playwright is all about test isolation so we recommend a new test context for each test (they are cheap to create).

If you experience issues with new_context, please let us know! Its a recent addition. Closing for now since it seems solved.