diff options
Diffstat (limited to 'testing/web-platform/tests/webdriver/tests/bidi/network')
15 files changed, 607 insertions, 127 deletions
diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/add_intercept.py b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/add_intercept.py index 7648eb1934..c073e1cc32 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/add_intercept.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/add_intercept.py @@ -17,49 +17,6 @@ from .. import ( @pytest.mark.asyncio @pytest.mark.parametrize("phase", ["beforeRequestSent", "responseStarted"]) -async def test_other_context( - bidi_session, - url, - top_context, - add_intercept, - fetch, - setup_network_test, - phase, -): - # Subscribe to network events only in top_context - await setup_network_test( - events=[ - BEFORE_REQUEST_SENT_EVENT, - RESPONSE_STARTED_EVENT, - RESPONSE_COMPLETED_EVENT, - ], - contexts=[top_context["context"]], - ) - - # Create another tab, where network events are not monitored. - other_context = await bidi_session.browsing_context.create(type_hint="tab") - await bidi_session.browsing_context.navigate( - context=other_context["context"], url=url(PAGE_EMPTY_HTML), wait="complete" - ) - - # Add an intercept. - text_url = url(PAGE_EMPTY_TEXT) - await add_intercept( - phases=[phase], - url_patterns=[{"type": "string", "pattern": text_url}], - ) - - # Request to top_context should be blocked and throw a ScriptEvaluateResultException - # from the AbortController. - with pytest.raises(ScriptEvaluateResultException): - await fetch(text_url, context=top_context) - - # Request to other_context should not be blocked. - await fetch(text_url, context=other_context) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("phase", ["beforeRequestSent", "responseStarted"]) async def test_other_url( url, add_intercept, diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/contexts.py b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/contexts.py new file mode 100644 index 0000000000..83dfa5560f --- /dev/null +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/contexts.py @@ -0,0 +1,210 @@ +import asyncio + +import pytest +from webdriver.bidi.modules.script import ScriptEvaluateResultException + +from .. import ( + assert_before_request_sent_event, + PAGE_EMPTY_HTML, + PAGE_EMPTY_TEXT, + BEFORE_REQUEST_SENT_EVENT, + RESPONSE_COMPLETED_EVENT, + RESPONSE_STARTED_EVENT, +) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("phase", ["beforeRequestSent", "responseStarted"]) +async def test_other_context( + bidi_session, + url, + top_context, + add_intercept, + fetch, + setup_network_test, + phase, +): + # Subscribe to network events only in top_context + await setup_network_test( + events=[ + BEFORE_REQUEST_SENT_EVENT, + RESPONSE_STARTED_EVENT, + RESPONSE_COMPLETED_EVENT, + ], + contexts=[top_context["context"]], + ) + + # Create another tab, where network events are not monitored. + other_context = await bidi_session.browsing_context.create(type_hint="tab") + await bidi_session.browsing_context.navigate( + context=other_context["context"], url=url(PAGE_EMPTY_HTML), wait="complete" + ) + + # Add an intercept. + text_url = url(PAGE_EMPTY_TEXT) + await add_intercept( + phases=[phase], + url_patterns=[{"type": "string", "pattern": text_url}], + ) + + # Request to top_context should be blocked and throw a ScriptEvaluateResultException + # from the AbortController. + with pytest.raises(ScriptEvaluateResultException): + await fetch(text_url, context=top_context) + + # Request to other_context should not be blocked. + await fetch(text_url, context=other_context) + + +@pytest.mark.asyncio +async def test_other_context_with_event_subscription( + bidi_session, + url, + top_context, + add_intercept, + fetch, + setup_network_test, + wait_for_event, + wait_for_future_safe +): + # Create another tab that will listen to network events without interception. + other_context = await bidi_session.browsing_context.create(type_hint="tab") + await bidi_session.browsing_context.navigate( + context=other_context["context"], url=url(PAGE_EMPTY_HTML), wait="complete" + ) + + # Subscribe to network events in both contexts. + await setup_network_test( + events=[ + BEFORE_REQUEST_SENT_EVENT, + RESPONSE_STARTED_EVENT, + RESPONSE_COMPLETED_EVENT, + ], + contexts=[top_context["context"], other_context["context"]], + ) + + # Add an intercept to top_context only. + text_url = url(PAGE_EMPTY_TEXT) + await add_intercept( + phases=["beforeRequestSent"], + url_patterns=[{"type": "string", "pattern": text_url}], + contexts=[top_context["context"]] + ) + + # Request to the top_context should be blocked. + on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + asyncio.ensure_future(fetch(text_url, context=top_context)) + event = await wait_for_future_safe(on_network_event) + assert_before_request_sent_event( + event, is_blocked=True + ) + + # Request to other_context should not be blocked. + on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + asyncio.ensure_future(fetch(text_url, context=other_context)) + event = await wait_for_future_safe(on_network_event) + assert_before_request_sent_event( + event, is_blocked=False + ) + + +@pytest.mark.asyncio +async def test_two_contexts_same_intercept( + bidi_session, + url, + top_context, + add_intercept, + fetch, + setup_network_test, + wait_for_event, + wait_for_future_safe +): + other_context = await bidi_session.browsing_context.create(type_hint="tab") + await bidi_session.browsing_context.navigate( + context=other_context["context"], url=url(PAGE_EMPTY_HTML), wait="complete" + ) + + # Subscribe to network events in both contexts. + await setup_network_test( + events=[ + BEFORE_REQUEST_SENT_EVENT, + ], + contexts=[top_context["context"], other_context["context"]], + ) + + # Add an intercept to both contexts + text_url = url(PAGE_EMPTY_TEXT) + intercept = await add_intercept( + phases=["beforeRequestSent"], + url_patterns=[{"type": "string", "pattern": text_url}], + contexts=[top_context["context"], other_context["context"]], + ) + + # Request on the top_context should be blocked. + on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + asyncio.ensure_future(fetch(text_url, context=top_context)) + event = await wait_for_future_safe(on_network_event) + assert_before_request_sent_event( + event, is_blocked=True, intercepts=[intercept] + ) + + # Request on the other_context should be blocked. + on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + asyncio.ensure_future(fetch(text_url, context=other_context)) + event = await wait_for_future_safe(on_network_event) + assert_before_request_sent_event( + event, is_blocked=True, intercepts=[intercept] + ) + + +@pytest.mark.asyncio +async def test_two_contexts_global_intercept( + bidi_session, + url, + top_context, + add_intercept, + fetch, + setup_network_test, + wait_for_event, + wait_for_future_safe +): + other_context = await bidi_session.browsing_context.create(type_hint="tab") + await bidi_session.browsing_context.navigate( + context=other_context["context"], url=url(PAGE_EMPTY_HTML), wait="complete" + ) + + # Subscribe to network events in both contexts. + await setup_network_test( + events=[ + BEFORE_REQUEST_SENT_EVENT, + ], + contexts=[top_context["context"], other_context["context"]], + ) + + # Add an intercept for top_context and a global intercept. + text_url = url(PAGE_EMPTY_TEXT) + context_intercept = await add_intercept( + phases=["beforeRequestSent"], + url_patterns=[{"type": "string", "pattern": text_url}], + contexts=[top_context["context"]], + ) + global_intercept = await add_intercept( + phases=["beforeRequestSent"], + url_patterns=[{"type": "string", "pattern": text_url}], + ) + + # Request on the top_context should be blocked and list both intercepts. + on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + asyncio.ensure_future(fetch(text_url, context=top_context)) + event = await wait_for_future_safe(on_network_event) + assert_before_request_sent_event( + event, is_blocked=True, intercepts=[context_intercept, global_intercept] + ) + + # Request on the other_context should be blocked by the global intercept. + on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + asyncio.ensure_future(fetch(text_url, context=other_context)) + event = await wait_for_future_safe(on_network_event) + assert_before_request_sent_event( + event, is_blocked=True, intercepts=[global_intercept] + ) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/invalid.py b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/invalid.py index ac7b273854..0821ba7782 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/invalid.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/invalid.py @@ -147,7 +147,8 @@ async def test_params_url_patterns_pattern_protocol_file_invalid_value(bidi_sess with pytest.raises(error.InvalidArgumentException): await bidi_session.network.add_intercept( phases=["beforeRequestSent"], - url_patterns=[{"type": "pattern", "protocol": value, "hostname": "example.com"}], + url_patterns=[ + {"type": "pattern", "protocol": value, "hostname": "example.com"}], ) @@ -185,3 +186,36 @@ async def test_params_url_patterns_pattern_search_invalid_value(bidi_session, va phases=["beforeRequestSent"], url_patterns=[{"type": "pattern", "search": value}], ) + + +@pytest.mark.parametrize("value", [False, 42, {}, ""]) +async def test_params_contexts_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_intercept(phases=["beforeRequestSent"], contexts=value) + + +async def test_params_contexts_empty_list(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_intercept(phases=["beforeRequestSent"], contexts=[]) + + +async def test_params_contexts_context_invalid_value(bidi_session): + with pytest.raises(error.NoSuchFrameException): + await bidi_session.network.add_intercept(phases=["beforeRequestSent"], contexts=["does not exist"]) + + +async def test_params_contexts_context_non_top_level(bidi_session, new_tab, test_page_same_origin_frame): + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=test_page_same_origin_frame, + wait="complete", + ) + + contexts = await bidi_session.browsing_context.get_tree(root=new_tab["context"]) + + assert len(contexts) == 1 + assert len(contexts[0]["children"]) == 1 + child_info = contexts[0]["children"][0] + + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_intercept(phases=["beforeRequestSent"], contexts=[child_info['context']]) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/phase_auth_required.py b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/phase_auth_required.py index dd322a2340..0df3e9e86a 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/phase_auth_required.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/phase_auth_required.py @@ -1,9 +1,6 @@ import pytest -from .. import ( - assert_before_request_sent_event, - assert_response_event, -) +import asyncio from .. import ( assert_before_request_sent_event, @@ -26,7 +23,14 @@ async def test_basic_authentication( url, setup_network_test, add_intercept, + fetch, ): + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=url(PAGE_EMPTY_TEXT), + wait="complete", + ) + network_events = await setup_network_test( events=[ BEFORE_REQUEST_SENT_EVENT, @@ -49,11 +53,8 @@ async def test_basic_authentication( assert isinstance(intercept, str) on_auth_required = wait_for_event(AUTH_REQUIRED_EVENT) - await bidi_session.browsing_context.navigate( - context=new_tab["context"], - url=auth_url, - wait="none", - ) + # The fetch should fails as there is no authentication + asyncio.ensure_future(fetch(url=auth_url, context=new_tab)) await wait_for_future_safe(on_auth_required) expected_request = {"method": "GET", "url": auth_url} diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/url_patterns.py b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/url_patterns.py index 517a94ffc4..cee5f5d822 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/url_patterns.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/add_intercept/url_patterns.py @@ -59,7 +59,7 @@ def substitute_host(server_config): async def test_pattern_patterns_matching( wait_for_event, subscribe_events, - top_context, + new_tab, add_intercept, fetch, substitute_host, @@ -67,7 +67,7 @@ async def test_pattern_patterns_matching( patterns, url_template, ): - await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[top_context["context"]]) + await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[new_tab["context"]]) for pattern in patterns: for key in pattern: @@ -78,7 +78,7 @@ async def test_pattern_patterns_matching( intercept = await add_intercept(phases=["beforeRequestSent"], url_patterns=patterns) on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) - asyncio.ensure_future(fetch(substitute_host(url_template))) + asyncio.ensure_future(fetch(substitute_host(url_template), context=new_tab)) event = await wait_for_future_safe(on_network_event) assert_before_request_sent_event(event, is_blocked=True, intercepts=[intercept]) @@ -106,7 +106,7 @@ async def test_pattern_patterns_matching( async def test_pattern_patterns_not_matching( wait_for_event, subscribe_events, - top_context, + new_tab, add_intercept, fetch, substitute_host, @@ -114,7 +114,7 @@ async def test_pattern_patterns_not_matching( pattern, url_template, ): - await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[top_context["context"]]) + await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[new_tab["context"]]) for key in pattern: pattern[key] = substitute_host(pattern[key]) @@ -124,7 +124,7 @@ async def test_pattern_patterns_not_matching( await add_intercept(phases=["beforeRequestSent"], url_patterns=[pattern]) on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) - asyncio.ensure_future(fetch(substitute_host(url_template))) + asyncio.ensure_future(fetch(substitute_host(url_template), context=new_tab)) event = await wait_for_future_safe(on_network_event) assert_before_request_sent_event(event, is_blocked=False) @@ -156,7 +156,7 @@ async def test_pattern_patterns_not_matching( async def test_string_patterns_matching( wait_for_event, subscribe_events, - top_context, + new_tab, add_intercept, fetch, substitute_host, @@ -164,7 +164,7 @@ async def test_string_patterns_matching( pattern, url_template, ): - await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[top_context["context"]]) + await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[new_tab["context"]]) intercept = await add_intercept( phases=["beforeRequestSent"], @@ -172,7 +172,7 @@ async def test_string_patterns_matching( ) on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) - asyncio.ensure_future(fetch(substitute_host(url_template))) + asyncio.ensure_future(fetch(substitute_host(url_template), context=new_tab)) event = await wait_for_future_safe(on_network_event) assert_before_request_sent_event(event, is_blocked=True, intercepts=[intercept]) @@ -198,7 +198,7 @@ async def test_string_patterns_matching( async def test_string_patterns_not_matching( wait_for_event, subscribe_events, - top_context, + new_tab, add_intercept, fetch, substitute_host, @@ -206,7 +206,7 @@ async def test_string_patterns_not_matching( pattern, url_template, ): - await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[top_context["context"]]) + await subscribe_events(events=[BEFORE_REQUEST_SENT_EVENT], contexts=[new_tab["context"]]) await add_intercept( phases=["beforeRequestSent"], @@ -214,7 +214,7 @@ async def test_string_patterns_not_matching( ) on_network_event = wait_for_event(BEFORE_REQUEST_SENT_EVENT) - asyncio.ensure_future(fetch(substitute_host(url_template))) + asyncio.ensure_future(fetch(substitute_host(url_template), context=new_tab)) event = await wait_for_future_safe(on_network_event) assert_before_request_sent_event(event, is_blocked=False) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/auth_required.py b/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/auth_required.py index 9a24946cde..4f5c836280 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/auth_required.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/auth_required.py @@ -1,12 +1,20 @@ import pytest +import asyncio + from .. import assert_response_event, AUTH_REQUIRED_EVENT, PAGE_EMPTY_HTML @pytest.mark.asyncio async def test_subscribe_status( - bidi_session, new_tab, subscribe_events, wait_for_event, wait_for_future_safe, url + bidi_session, new_tab, subscribe_events, wait_for_event, wait_for_future_safe, url, fetch ): + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=url(PAGE_EMPTY_HTML), + wait="complete", + ) + await subscribe_events(events=[AUTH_REQUIRED_EVENT]) # Track all received network.authRequired events in the events array. @@ -15,7 +23,8 @@ async def test_subscribe_status( async def on_event(method, data): events.append(data) - remove_listener = bidi_session.add_event_listener(AUTH_REQUIRED_EVENT, on_event) + remove_listener = bidi_session.add_event_listener( + AUTH_REQUIRED_EVENT, on_event) auth_url = url( "/webdriver/tests/support/http_handlers/authentication.py?realm=testrealm" @@ -23,13 +32,7 @@ async def test_subscribe_status( on_auth_required = wait_for_event(AUTH_REQUIRED_EVENT) - # navigate using wait="none" as other wait conditions would hang because of - # the authentication prompt. - await bidi_session.browsing_context.navigate( - context=new_tab["context"], - url=auth_url, - wait="none", - ) + asyncio.ensure_future(fetch(url=auth_url, context=new_tab)) await wait_for_future_safe(on_auth_required) @@ -63,7 +66,8 @@ async def test_no_authentication( async def on_event(method, data): events.append(data) - remove_listener = bidi_session.add_event_listener(AUTH_REQUIRED_EVENT, on_event) + remove_listener = bidi_session.add_event_listener( + AUTH_REQUIRED_EVENT, on_event) # Navigate to a page which should not trigger any authentication. await bidi_session.browsing_context.navigate( diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/unsubscribe.py b/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/unsubscribe.py index cf818fee6f..0bbf8df266 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/unsubscribe.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/auth_required/unsubscribe.py @@ -1,15 +1,22 @@ -import asyncio - import pytest -pytestmark = pytest.mark.asyncio +import asyncio + +from webdriver.bidi.modules.script import ScriptEvaluateResultException from .. import AUTH_REQUIRED_EVENT, PAGE_EMPTY_HTML +pytestmark = pytest.mark.asyncio # This test can be moved back to `auth_required.py` when all implementations # support handing of HTTP auth prompt. -async def test_unsubscribe(bidi_session, new_tab, url): +async def test_unsubscribe(bidi_session, new_tab, url, fetch): + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=url(PAGE_EMPTY_HTML), + wait="complete", + ) + await bidi_session.session.subscribe(events=[AUTH_REQUIRED_EVENT]) await bidi_session.session.unsubscribe(events=[AUTH_REQUIRED_EVENT]) @@ -19,17 +26,13 @@ async def test_unsubscribe(bidi_session, new_tab, url): async def on_event(method, data): events.append(data) - remove_listener = bidi_session.add_event_listener(AUTH_REQUIRED_EVENT, on_event) + remove_listener = bidi_session.add_event_listener( + AUTH_REQUIRED_EVENT, on_event) + + asyncio.ensure_future(fetch(url=url( + "/webdriver/tests/support/http_handlers/authentication.py?realm=testrealm" + ), context=new_tab)) - # Navigate to authentication.py again and check no event is received. - await bidi_session.browsing_context.navigate( - context=new_tab["context"], - url=url( - "/webdriver/tests/support/http_handlers/authentication.py?realm=testrealm" - ), - wait="none", - ) - await asyncio.sleep(0.5) assert len(events) == 0 remove_listener() diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py b/testing/web-platform/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py new file mode 100644 index 0000000000..2de71362ae --- /dev/null +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py @@ -0,0 +1,123 @@ +import pytest +import random + +from tests.support.sync import AsyncPoll + +from .. import ( + assert_before_request_sent_event, + PAGE_EMPTY_TEXT, + BEFORE_REQUEST_SENT_EVENT, +) + +# Note: The cached status cannot be checked in the beforeRequestSent event, but +# the goal is to verify that the events are still emitted for cached requests. + + +@pytest.mark.asyncio +async def test_cached_document( + wait_for_event, + wait_for_future_safe, + url, + fetch, + setup_network_test, +): + network_events = await setup_network_test( + events=[ + BEFORE_REQUEST_SENT_EVENT, + ] + ) + events = network_events[BEFORE_REQUEST_SENT_EVENT] + + # `nocache` is not used in cached.py, it is here to avoid the browser cache. + cached_url = url( + f"/webdriver/tests/support/http_handlers/cached.py?status=200&nocache={random.random()}" + ) + on_before_request_sent = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + await fetch(cached_url) + await wait_for_future_safe(on_before_request_sent) + + assert len(events) == 1 + expected_request = {"method": "GET", "url": cached_url} + + assert_before_request_sent_event( + events[0], + expected_request=expected_request, + ) + + on_before_request_sent = wait_for_event(BEFORE_REQUEST_SENT_EVENT) + await fetch(cached_url) + await wait_for_future_safe(on_before_request_sent) + + assert len(events) == 2 + + assert_before_request_sent_event( + events[1], + expected_request=expected_request, + ) + + +@pytest.mark.asyncio +async def test_page_with_cached_resource( + bidi_session, + url, + inline, + setup_network_test, + top_context, +): + network_events = await setup_network_test( + events=[ + BEFORE_REQUEST_SENT_EVENT, + ] + ) + events = network_events[BEFORE_REQUEST_SENT_EVENT] + + # Build a page with a stylesheet resource which will be read from http cache + # on the next reload. + # `nocache` is not used in cached.py, it is here to avoid the browser cache. + cached_css_url = url( + f"/webdriver/tests/support/http_handlers/cached.py?status=200&contenttype=text/css&nocache={random.random()}" + ) + page_with_cached_css = inline( + f""" + <head><link rel="stylesheet" type="text/css" href="{cached_css_url}"></head> + <body>test page with cached stylesheet</body> + """, + ) + + await bidi_session.browsing_context.navigate( + context=top_context["context"], + url=page_with_cached_css, + wait="complete", + ) + + # Expect two events, one for the document, one for the stylesheet. + wait = AsyncPoll(bidi_session, timeout=2) + await wait.until(lambda _: len(events) >= 2) + assert len(events) == 2 + + assert_before_request_sent_event( + events[0], + expected_request={"method": "GET", "url": page_with_cached_css}, + ) + assert_before_request_sent_event( + events[1], + expected_request={"method": "GET", "url": cached_css_url}, + ) + + # Reload the page. + await bidi_session.browsing_context.reload(context=top_context["context"]) + + # Expect two events after reload, for the document and the stylesheet. + wait = AsyncPoll(bidi_session, timeout=2) + await wait.until(lambda _: len(events) >= 4) + assert len(events) == 4 + + assert_before_request_sent_event( + events[2], + expected_request={"method": "GET", "url": page_with_cached_css}, + ) + + assert_before_request_sent_event( + events[3], + expected_request={"method": "GET", "url": cached_css_url}, + ) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/conftest.py b/testing/web-platform/tests/webdriver/tests/bidi/network/conftest.py index 934b649c91..7813530c4c 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/conftest.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/conftest.py @@ -17,11 +17,12 @@ async def add_intercept(bidi_session): intercepts = [] - async def add_intercept(phases, url_patterns): + async def add_intercept(phases, url_patterns, contexts = None): nonlocal intercepts intercept = await bidi_session.network.add_intercept( phases=phases, url_patterns=url_patterns, + contexts=contexts, ) intercepts.append(intercept) @@ -143,6 +144,7 @@ async def setup_blocked_request( add_intercept, fetch, wait_for_event, + wait_for_future_safe, top_context, ): """Creates an intercept for the provided phase, sends a fetch request that @@ -189,16 +191,17 @@ async def setup_blocked_request( ], ) + network_event = wait_for_event(f"network.{phase}") if navigate: asyncio.ensure_future( bidi_session.browsing_context.navigate( - context=top_context["context"], url=blocked_url, wait="complete" + context=context["context"], url=blocked_url, wait="complete" ) ) else: - asyncio.ensure_future(fetch(blocked_url)) + asyncio.ensure_future(fetch(blocked_url, context=context)) - event = await wait_for_event(f"network.{phase}") + event = await wait_for_future_safe(network_event) request = event["request"]["request"] return request diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/credentials.py b/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/credentials.py index 3e595722cc..499c8a28c1 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/credentials.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/credentials.py @@ -11,7 +11,7 @@ pytestmark = pytest.mark.asyncio @pytest.mark.parametrize("navigate", [False, True], ids=["fetch", "navigate"]) async def test_wrong_credentials( - setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate + setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate, wait_for_future_safe ): username = f"test_missing_credentials_{navigate}" password = f"test_missing_credentials_password_{navigate}" @@ -27,12 +27,12 @@ async def test_wrong_credentials( await bidi_session.network.continue_response( request=request, credentials=wrong_credentials ) - await on_auth_required + await wait_for_future_safe(on_auth_required) @pytest.mark.parametrize("navigate", [False, True], ids=["fetch", "navigate"]) async def test_correct_credentials( - setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate + setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate, wait_for_future_safe ): # Setup unique username / password because browsers cache credentials. username = f"test_wrong_credentials_{navigate}" @@ -64,15 +64,17 @@ async def test_correct_credentials( await bidi_session.network.continue_response( request=request, credentials=correct_credentials ) - await on_response_completed + await wait_for_future_safe(on_response_completed) if navigate: - await on_load - - # Wait until 2 responseCompleted events have been emitted: - # - one for the initial request - # - one for the continue with correct credentials - wait = AsyncPoll(bidi_session, timeout=2) - await wait.until(lambda _: len(response_completed_events) >= 2) - assert len(response_completed_events) == 2 + await wait_for_future_safe(on_load) + + # TODO: At the moment, the specification does not expect to receive a + # responseCompleted event for each authentication attempt, so only assert + # the last event. See https://github.com/w3c/webdriver-bidi/issues/627 + + # Wait until a a responseCompleted event with status 200 OK is received. + wait = AsyncPoll( + bidi_session, message="Didn't receive response completed events") + await wait.until(lambda _: len(response_completed_events) > 0 and response_completed_events[-1]["response"]["status"] == 200) remove_listener() diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/request.py b/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/request.py index 579f1da288..ae9c94d955 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/request.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/continue_response/request.py @@ -1,17 +1,13 @@ import pytest -from webdriver.bidi.modules.network import AuthCredentials - -from tests.support.sync import AsyncPoll - -from .. import AUTH_REQUIRED_EVENT, RESPONSE_COMPLETED_EVENT, RESPONSE_STARTED_EVENT +from .. import AUTH_REQUIRED_EVENT, RESPONSE_COMPLETED_EVENT pytestmark = pytest.mark.asyncio @pytest.mark.parametrize("navigate", [False, True], ids=["fetch", "navigate"]) async def test_continue_auth_required( - setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate + setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate, wait_for_future_safe ): # Setup unique username / password because browsers cache credentials. username = f"test_continue_auth_required_{navigate}" @@ -30,12 +26,12 @@ async def test_continue_auth_required( # network.authRequired should be emitted. on_auth_required = wait_for_event(AUTH_REQUIRED_EVENT) await bidi_session.network.continue_response(request=request) - await on_auth_required + await wait_for_future_safe(on_auth_required) @pytest.mark.parametrize("navigate", [False, True], ids=["fetch", "navigate"]) async def test_continue_response_started( - setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate + setup_blocked_request, subscribe_events, wait_for_event, bidi_session, navigate, wait_for_future_safe ): request = await setup_blocked_request("responseStarted", navigate=navigate) @@ -52,6 +48,6 @@ async def test_continue_response_started( await bidi_session.network.continue_response(request=request) - await on_response_completed + await wait_for_future_safe(on_response_completed) if navigate: - await on_load + await wait_for_future_safe(on_load) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/continue_with_auth/action.py b/testing/web-platform/tests/webdriver/tests/bidi/network/continue_with_auth/action.py index a122ce0e49..e4cf6da08f 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/continue_with_auth/action.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/continue_with_auth/action.py @@ -7,7 +7,6 @@ from tests.support.sync import AsyncPoll from .. import ( assert_response_event, AUTH_REQUIRED_EVENT, - PAGE_EMPTY_TEXT, RESPONSE_COMPLETED_EVENT, ) @@ -15,7 +14,7 @@ pytestmark = pytest.mark.asyncio async def test_cancel( - setup_blocked_request, subscribe_events, wait_for_event, bidi_session, url + setup_blocked_request, subscribe_events, wait_for_event, bidi_session, wait_for_future_safe ): request = await setup_blocked_request("authRequired") await subscribe_events(events=[RESPONSE_COMPLETED_EVENT]) @@ -24,7 +23,7 @@ async def test_cancel( await bidi_session.network.continue_with_auth(request=request, action="cancel") await on_response_completed - response_event = await on_response_completed + response_event = await wait_for_future_safe(on_response_completed) assert_response_event( response_event, expected_response={ @@ -35,7 +34,7 @@ async def test_cancel( async def test_default( - setup_blocked_request, subscribe_events, wait_for_event, bidi_session, url + setup_blocked_request, subscribe_events, bidi_session ): request = await setup_blocked_request("authRequired") @@ -64,7 +63,7 @@ async def test_default( async def test_provideCredentials( - setup_blocked_request, subscribe_events, bidi_session, url + setup_blocked_request, subscribe_events, bidi_session ): # Setup unique username / password because browsers cache credentials. username = "test_provideCredentials" @@ -101,7 +100,7 @@ async def test_provideCredentials( async def test_provideCredentials_wrong_credentials( - setup_blocked_request, subscribe_events, bidi_session, wait_for_event, url + setup_blocked_request, subscribe_events, bidi_session, wait_for_event, wait_for_future_safe ): # Setup unique username / password because browsers cache credentials. username = "test_provideCredentials_wrong_credentials" @@ -129,7 +128,7 @@ async def test_provideCredentials_wrong_credentials( ) # We expect to get another authRequired event after providing wrong credentials - await on_auth_required + await wait_for_future_safe(on_auth_required) # Continue with the correct credentials correct_credentials = AuthCredentials(username=username, password=password) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py b/testing/web-platform/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py index 6457e7d412..25503c971d 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py @@ -148,6 +148,7 @@ async def test_cached_revalidate( ) events = network_events[RESPONSE_COMPLETED_EVENT] + # `nocache` is not used in cached.py, it is here to avoid the browser cache. revalidate_url = url( f"/webdriver/tests/support/http_handlers/must-revalidate.py?nocache={random.random()}" ) @@ -189,3 +190,74 @@ async def test_cached_revalidate( expected_request=expected_request, expected_response=expected_response, ) + + +@pytest.mark.asyncio +async def test_page_with_cached_resource( + bidi_session, + url, + inline, + setup_network_test, + top_context, +): + network_events = await setup_network_test( + events=[ + RESPONSE_COMPLETED_EVENT, + ] + ) + events = network_events[RESPONSE_COMPLETED_EVENT] + + # Build a page with a stylesheet resource which will be read from http cache + # on the next reload. + # `nocache` is not used in cached.py, it is here to avoid the browser cache. + cached_css_url = url( + f"/webdriver/tests/support/http_handlers/cached.py?status=200&contenttype=text/css&nocache={random.random()}" + ) + page_with_cached_css = inline( + f""" + <head><link rel="stylesheet" type="text/css" href="{cached_css_url}"></head> + <body>test page with cached stylesheet</body> + """, + ) + + await bidi_session.browsing_context.navigate( + context=top_context["context"], + url=page_with_cached_css, + wait="complete", + ) + + # Expect two events, one for the page, one for the stylesheet. + wait = AsyncPoll(bidi_session, timeout=2) + await wait.until(lambda _: len(events) >= 2) + assert len(events) == 2 + + assert_response_event( + events[0], + expected_request={"method": "GET", "url": page_with_cached_css}, + expected_response={"url": page_with_cached_css, "fromCache": False}, + ) + assert_response_event( + events[1], + expected_request={"method": "GET", "url": cached_css_url}, + expected_response={"url": cached_css_url, "fromCache": False}, + ) + + # Reload the page. + await bidi_session.browsing_context.reload(context=top_context["context"]) + + # Expect two additional events after reload, for the page and the stylesheet. + wait = AsyncPoll(bidi_session, timeout=2) + await wait.until(lambda _: len(events) >= 4) + assert len(events) == 4 + + assert_response_event( + events[2], + expected_request={"method": "GET", "url": page_with_cached_css}, + expected_response={"url": page_with_cached_css, "fromCache": False}, + ) + + assert_response_event( + events[3], + expected_request={"method": "GET", "url": cached_css_url}, + expected_response={"url": cached_css_url, "fromCache": True}, + ) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started.py b/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started.py index dec743e175..fb99073fb3 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started.py @@ -245,6 +245,11 @@ async def test_response_mime_type_file( async def test_www_authenticate( bidi_session, url, fetch, new_tab, wait_for_event, wait_for_future_safe, setup_network_test ): + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=url(PAGE_EMPTY_HTML), + wait="complete", + ) auth_url = url( "/webdriver/tests/support/http_handlers/authentication.py?realm=testrealm" ) @@ -253,11 +258,8 @@ async def test_www_authenticate( events = network_events[RESPONSE_STARTED_EVENT] on_response_started = wait_for_event(RESPONSE_STARTED_EVENT) - await bidi_session.browsing_context.navigate( - context=new_tab["context"], - url=auth_url, - wait="none", - ) + + asyncio.ensure_future(fetch(url=auth_url, context=new_tab)) await wait_for_future_safe(on_response_started) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py b/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py index 2776950b0e..2c747f135a 100644 --- a/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py +++ b/testing/web-platform/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py @@ -21,6 +21,7 @@ async def test_cached( ) events = network_events[RESPONSE_STARTED_EVENT] + # `nocache` is not used in cached.py, it is here to avoid the browser cache. cached_url = url( f"/webdriver/tests/support/http_handlers/cached.py?status=200&nocache={random.random()}" ) @@ -78,6 +79,7 @@ async def test_cached_redirect( events = network_events[RESPONSE_STARTED_EVENT] text_url = url(PAGE_EMPTY_TEXT) + # `nocache` is not used in cached.py, it is here to avoid the browser cache. cached_url = url( f"/webdriver/tests/support/http_handlers/cached.py?status=301&location={text_url}&nocache={random.random()}" ) @@ -156,6 +158,7 @@ async def test_cached_revalidate( ) events = network_events[RESPONSE_STARTED_EVENT] + # `nocache` is not used in cached.py, it is here to avoid the browser cache. revalidate_url = url( f"/webdriver/tests/support/http_handlers/must-revalidate.py?nocache={random.random()}" ) @@ -197,3 +200,74 @@ async def test_cached_revalidate( expected_request=expected_request, expected_response=expected_response, ) + + +@pytest.mark.asyncio +async def test_page_with_cached_resource( + bidi_session, + url, + inline, + setup_network_test, + top_context, +): + network_events = await setup_network_test( + events=[ + RESPONSE_STARTED_EVENT, + ] + ) + events = network_events[RESPONSE_STARTED_EVENT] + + # Build a page with a stylesheet resource which will be read from http cache + # on the next reload. + # `nocache` is not used in cached.py, it is here to avoid the browser cache. + cached_css_url = url( + f"/webdriver/tests/support/http_handlers/cached.py?status=200&contenttype=text/css&nocache={random.random()}" + ) + page_with_cached_css = inline( + f""" + <head><link rel="stylesheet" type="text/css" href="{cached_css_url}"></head> + <body>test page with cached stylesheet</body> + """, + ) + + await bidi_session.browsing_context.navigate( + context=top_context["context"], + url=page_with_cached_css, + wait="complete", + ) + + # Expect two events, one for the page, one for the stylesheet. + wait = AsyncPoll(bidi_session, timeout=2) + await wait.until(lambda _: len(events) >= 2) + assert len(events) == 2 + + assert_response_event( + events[0], + expected_request={"method": "GET", "url": page_with_cached_css}, + expected_response={"url": page_with_cached_css, "fromCache": False}, + ) + assert_response_event( + events[1], + expected_request={"method": "GET", "url": cached_css_url}, + expected_response={"url": cached_css_url, "fromCache": False}, + ) + + # Reload the page. + await bidi_session.browsing_context.reload(context=top_context["context"]) + + # Expect two additional events after reload, for the page and the stylesheet. + wait = AsyncPoll(bidi_session, timeout=2) + await wait.until(lambda _: len(events) >= 4) + assert len(events) == 4 + + assert_response_event( + events[2], + expected_request={"method": "GET", "url": page_with_cached_css}, + expected_response={"url": page_with_cached_css, "fromCache": False}, + ) + + assert_response_event( + events[3], + expected_request={"method": "GET", "url": cached_css_url}, + expected_response={"url": cached_css_url, "fromCache": True}, + ) |