chromium/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/browsing_context/navigation_failed/navigation_failed.py

import asyncio
import pytest
from tests.support.sync import AsyncPoll

from webdriver.error import TimeoutException

from .. import assert_navigation_info


pytestmark = pytest.mark.asyncio

NAVIGATION_FAILED_EVENT = "browsingContext.navigationFailed"
NAVIGATION_STARTED_EVENT = "browsingContext.navigationStarted"
USER_PROMPT_OPENED_EVENT = "browsingContext.userPromptOpened"


async def test_unsubscribe(bidi_session, inline, new_tab):
    await bidi_session.session.subscribe(events=[NAVIGATION_FAILED_EVENT])
    await bidi_session.session.unsubscribe(events=[NAVIGATION_FAILED_EVENT])

    # Track all received browsingContext.navigationFailed events in the events array.
    events = []

    async def on_event(method, data):
        events.append(data)

    remove_listener = bidi_session.add_event_listener(NAVIGATION_FAILED_EVENT, on_event)

    iframe_url = inline("<div>foo</div>", domain="alt")
    page_url = inline(
        f"""<iframe src={iframe_url}></iframe>""",
        parameters={"pipe": "header(Content-Security-Policy, default-src 'self')"},
    )

    await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=page_url, wait="none"
    )

    wait = AsyncPoll(bidi_session, timeout=0.5)
    with pytest.raises(TimeoutException):
        await wait.until(lambda _: len(events) > 0)

    remove_listener()


async def test_with_csp_meta_tag(
    bidi_session,
    subscribe_events,
    inline,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
):
    iframe_url = inline("<div>foo</div>", domain="alt")
    page_url = inline(
        f"""
<!DOCTYPE html>
<html>
    <head>
        <meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'" />
    </head>
    <body><iframe src="{iframe_url}"></iframe></body>
</html>
"""
    )
    await subscribe_events(events=[NAVIGATION_FAILED_EVENT, NAVIGATION_STARTED_EVENT])

    # Track all received browsingContext.navigationStarted events in the events array.
    events = []

    async def on_event(method, data):
        events.append(data)

    remove_listener = bidi_session.add_event_listener(
        NAVIGATION_STARTED_EVENT, on_event
    )

    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=page_url, wait="complete"
    )
    event = await wait_for_future_safe(on_navigation_failed)

    contexts = await bidi_session.browsing_context.get_tree(root=new_tab["context"])
    iframe_context = contexts[0]["children"][0]["context"]

    started_event_for_iframe = next(
        event for event in events if event["context"] == iframe_context
    )

    # Make sure that the iframe navigation was blocked.
    assert_navigation_info(
        event,
        {
            "context": iframe_context,
            "navigation": started_event_for_iframe["navigation"],
            "url": iframe_url,
        },
    )

    remove_listener()


@pytest.mark.parametrize(
    "header",
    [
        "Content-Security-Policy, default-src 'self'",
        "Cross-Origin-Embedder-Policy, require-corp",
    ],
)
async def test_with_content_blocking_header_in_top_context(
    bidi_session,
    subscribe_events,
    inline,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
    header,
):
    iframe_url = inline("<div>foo</div>", domain="alt")
    page_url = inline(
        f"""<iframe src={iframe_url}></iframe>""",
        parameters={"pipe": f"header({header})"},
    )
    await subscribe_events(events=[NAVIGATION_FAILED_EVENT, NAVIGATION_STARTED_EVENT])

    # Track all received browsingContext.navigationStarted events in the events array.
    events = []

    async def on_event(method, data):
        events.append(data)

    remove_listener = bidi_session.add_event_listener(
        NAVIGATION_STARTED_EVENT, on_event
    )

    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=page_url, wait="none"
    )
    event = await wait_for_future_safe(on_navigation_failed)

    contexts = await bidi_session.browsing_context.get_tree(root=new_tab["context"])
    iframe_context = contexts[0]["children"][0]["context"]

    started_event_for_iframe = next(
        event for event in events if event["context"] == iframe_context
    )

    # Make sure that the iframe navigation was blocked.
    assert_navigation_info(
        event,
        {
            "context": iframe_context,
            "navigation": started_event_for_iframe["navigation"],
            "url": iframe_url,
        },
    )

    remove_listener()


@pytest.mark.parametrize(
    "header_value",
    [
        "SAMEORIGIN",
        "DENY",
    ],
)
async def test_with_x_frame_options_header(
    bidi_session,
    subscribe_events,
    inline,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
    header_value
):
    iframe_url = inline(
        "<div>foo</div>",
        parameters={"pipe": f"header(X-Frame-Options, {header_value})"},
    )
    page_url = inline(f"""<iframe src={iframe_url}></iframe>""", domain="alt")
    await subscribe_events(events=[NAVIGATION_FAILED_EVENT, NAVIGATION_STARTED_EVENT])

    # Track all received browsingContext.navigationStarted events in the events array.
    events = []

    async def on_event(method, data):
        events.append(data)

    remove_listener = bidi_session.add_event_listener(
        NAVIGATION_STARTED_EVENT, on_event
    )

    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=page_url, wait="none"
    )
    event = await wait_for_future_safe(on_navigation_failed)

    contexts = await bidi_session.browsing_context.get_tree(root=new_tab["context"])
    iframe_context = contexts[0]["children"][0]["context"]

    started_event_for_iframe = next(
        event for event in events if event["context"] == iframe_context
    )

    # Make sure that the iframe navigation was blocked.
    assert_navigation_info(
        event,
        {
            "context": iframe_context,
            "navigation": started_event_for_iframe["navigation"],
            "url": iframe_url,
        },
    )

    remove_listener()


async def test_with_new_navigation(
    bidi_session,
    subscribe_events,
    inline,
    url,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
):
    slow_page_url = url(
        "/webdriver/tests/bidi/browsing_context/support/empty.html?pipe=trickle(d10)"
    )
    await subscribe_events(events=[NAVIGATION_FAILED_EVENT])

    result = await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=slow_page_url, wait="none"
    )
    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    second_url = inline("<div>foo</div>")

    # Trigger the second navigation which should fail the first one.
    await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=second_url, wait="none"
    )

    event = await wait_for_future_safe(on_navigation_failed)

    # Make sure that the first navigation failed.
    assert_navigation_info(
        event,
        {
            "context": new_tab["context"],
            "navigation": result["navigation"],
            "url": slow_page_url,
        },
    )


async def test_with_new_navigation_inside_page(
    bidi_session,
    subscribe_events,
    inline,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
):
    second_url = inline("<div>foo</div>")
    slow_page_url = inline(
        f"""
<!DOCTYPE html>
<html>
    <body>
        <img src="/webdriver/tests/bidi/browsing_context/support/empty.svg?pipe=trickle(d10)" />
        <script>
            location.href = "{second_url}"
        </script>
        <img src="/webdriver/tests/bidi/browsing_context/support/empty.svg?pipe=trickle(d10)" />
    </body>
</html>
"""
    )
    await subscribe_events(events=[NAVIGATION_FAILED_EVENT])
    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)

    result = await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=slow_page_url, wait="none"
    )

    event = await wait_for_future_safe(on_navigation_failed)

    # Make sure that the first navigation failed.
    assert_navigation_info(
        event,
        {
            "context": new_tab["context"],
            "navigation": result["navigation"],
            "url": slow_page_url,
        },
    )


@pytest.mark.parametrize("type_hint", ["tab", "window"])
async def test_close_context(
    bidi_session,
    subscribe_events,
    url,
    wait_for_event,
    wait_for_future_safe,
    type_hint,
):
    new_context = await bidi_session.browsing_context.create(type_hint=type_hint)
    slow_page_url = url(
        "/webdriver/tests/bidi/browsing_context/support/empty.html?pipe=trickle(d10)"
    )
    await subscribe_events(events=[NAVIGATION_FAILED_EVENT])

    result = await bidi_session.browsing_context.navigate(
        context=new_context["context"], url=slow_page_url, wait="none"
    )

    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    await bidi_session.browsing_context.close(context=new_context["context"])
    event = await wait_for_future_safe(on_navigation_failed)

    # Make sure that the navigation failed.
    assert_navigation_info(
        event,
        {
            "context": new_context["context"],
            "navigation": result["navigation"],
            "url": slow_page_url,
        },
    )


async def test_close_iframe(
    bidi_session,
    subscribe_events,
    inline,
    url,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
):
    iframe_url = inline("<div>foo</div>")
    page_url = inline(f"<iframe src={iframe_url}></iframe")

    await subscribe_events(events=[NAVIGATION_FAILED_EVENT])

    result = await bidi_session.browsing_context.navigate(
        context=new_tab["context"], url=page_url, wait="complete"
    )

    contexts = await bidi_session.browsing_context.get_tree(root=new_tab["context"])
    iframe_context = contexts[0]["children"][0]["context"]

    slow_page_url = url(
        "/webdriver/tests/bidi/browsing_context/support/empty.html?pipe=trickle(d10)"
    )
    # Navigate in the iframe.
    result = await bidi_session.browsing_context.navigate(
        context=iframe_context, url=slow_page_url, wait="none"
    )

    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    # Reload the top context to destroy the iframe.
    await bidi_session.browsing_context.reload(context=new_tab["context"], wait="none")
    event = await wait_for_future_safe(on_navigation_failed)

    # Make sure that the iframe navigation failed.
    assert_navigation_info(
        event,
        {
            "context": iframe_context,
            "navigation": result["navigation"],
            "url": slow_page_url,
        },
    )


@pytest.mark.capabilities({"unhandledPromptBehavior": {"beforeUnload": "ignore"}})
async def test_with_beforeunload_prompt(
    bidi_session,
    new_tab,
    wait_for_event,
    wait_for_future_safe,
    url,
    subscribe_events,
    setup_beforeunload_page,
):
    await subscribe_events(
        events=[
            NAVIGATION_FAILED_EVENT,
            NAVIGATION_STARTED_EVENT,
            USER_PROMPT_OPENED_EVENT,
        ]
    )
    await setup_beforeunload_page(new_tab)
    target_url = url("/webdriver/tests/support/html/default.html", domain="alt")

    on_navigation_started = wait_for_event(NAVIGATION_STARTED_EVENT)
    on_prompt_opened = wait_for_event(USER_PROMPT_OPENED_EVENT)

    asyncio.ensure_future(
        bidi_session.browsing_context.navigate(
            context=new_tab["context"], url=target_url, wait="none"
        )
    )

    # Wait for the navigation to start.
    navigation_started_event = await wait_for_future_safe(on_navigation_started)

    # Wait for the prompt to open.
    await wait_for_future_safe(on_prompt_opened)

    on_navigation_failed = wait_for_event(NAVIGATION_FAILED_EVENT)
    # Stay on the page to fail the started navigation.
    await bidi_session.browsing_context.handle_user_prompt(
        context=new_tab["context"], accept=False
    )

    event = await wait_for_future_safe(on_navigation_failed)

    # Make sure that the first navigation failed.
    assert_navigation_info(
        event,
        {
            "context": new_tab["context"],
            "navigation": navigation_started_event["navigation"],
            "url": target_url,
        },
    )