chromium/third_party/blink/web_tests/external/wpt/webdriver/tests/interop/beforeunload_prompt.py

import asyncio
import pytest
import pytest_asyncio
from webdriver.error import NoSuchAlertException

from tests.support.sync import AsyncPoll

from ..bidi import (
    any_string,
    recursive_compare,
)


pytestmark = pytest.mark.asyncio

USER_PROMPT_CLOSED_EVENT = "browsingContext.userPromptClosed"
USER_PROMPT_OPENED_EVENT = "browsingContext.userPromptOpened"


@pytest_asyncio.fixture
async def check_beforeunload_not_implicitly_accepted(
    bidi_session,
    current_session,
    setup_beforeunload_page,
    subscribe_events,
    wait_for_event,
    wait_for_future_safe,
    new_tab,
    execute_as_async,
    url,
):
    async def check_beforeunload_not_implicitly_accepted(accept):
        current_session.window_handle = new_tab["context"]

        page_beforeunload = await setup_beforeunload_page(new_tab)
        page_target = url("/webdriver/tests/support/html/default.html")

        on_prompt_closed = wait_for_event(USER_PROMPT_CLOSED_EVENT)
        on_prompt_opened = wait_for_event(USER_PROMPT_OPENED_EVENT)

        await subscribe_events([USER_PROMPT_CLOSED_EVENT, USER_PROMPT_OPENED_EVENT])

        # Using WebDriver classic's navigation command to navigate away from
        # the page will hang and wait for the beforeunload dialog to close.
        # As such start the command immediately as task but await for it later
        # when BiDi closed the prompt.
        def sync_navigate():
            current_session.url = page_target

        task_navigate = asyncio.create_task(execute_as_async(sync_navigate))
        opened_event = await wait_for_future_safe(on_prompt_opened)

        recursive_compare(
            {
                "context": new_tab["context"],
                "type": "beforeunload",
                "message": any_string,
            },
            opened_event,
        )

        # Close the beforeunload prompt and wait for the navigation to finish.
        await bidi_session.browsing_context.handle_user_prompt(
            context=new_tab["context"], accept=accept
        )
        closed_event = await wait_for_future_safe(on_prompt_closed)
        await task_navigate

        # Check that the beforeunload prompt is closed and the event was sent.
        with pytest.raises(NoSuchAlertException):
            current_session.alert.text

        recursive_compare(
            {
                "accepted": accept,
                "context": new_tab["context"],
                "type": "beforeunload",
            },
            closed_event,
        )

        if accept:
            assert current_session.url == page_target
        else:
            assert current_session.url == page_beforeunload

    return check_beforeunload_not_implicitly_accepted


@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
@pytest.mark.parametrize("accept", [False, True])
async def test_accept(check_beforeunload_not_implicitly_accepted, accept):
    await check_beforeunload_not_implicitly_accepted(accept)


@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
@pytest.mark.parametrize("accept", [False, True])
async def test_accept_and_notify(check_beforeunload_not_implicitly_accepted, accept):
    await check_beforeunload_not_implicitly_accepted(accept)


@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
@pytest.mark.parametrize("accept", [False, True])
async def test_dismiss(check_beforeunload_not_implicitly_accepted, accept):
    await check_beforeunload_not_implicitly_accepted(accept)


@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
@pytest.mark.parametrize("accept", [False, True])
async def test_dismiss_and_notify(check_beforeunload_not_implicitly_accepted, accept):
    await check_beforeunload_not_implicitly_accepted(accept)


@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
@pytest.mark.parametrize("accept", [False, True])
async def test_ignore(check_beforeunload_not_implicitly_accepted, accept):
    await check_beforeunload_not_implicitly_accepted(accept)