commit 03a1387028b591218dbe3e313b6cff3df3ca13ad parent 15f23f0a402ed8f4efb8e30ee1b9f4133ade86d3 Author: Maksim Sadym <69349599+sadym-chromium@users.noreply.github.com> Date: Tue, 14 Oct 2025 22:24:56 +0000 Bug 1993464 [wpt PR 55300] - [wdspec] `emulation.setNetworkConditions:offline`, a=testonly Automatic update from web-platform-tests [wdspec] `emulation.setNetworkConditions:offline` (#55300) -- wpt-commits: 28aef72ff6f2ab97375853874eab3eae2d4e41e0 wpt-pr: 55300 Diffstat:
9 files changed, 706 insertions(+), 1 deletion(-)
diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/emulation.py b/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/emulation.py @@ -104,3 +104,16 @@ class Emulation(BidiModule): "contexts": contexts, "userContexts": user_contexts, } + + @command + def set_network_conditions( + self, + network_conditions: Nullable[Dict[str, Any]], + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, + ) -> Mapping[str, Any]: + return { + "networkConditions": network_conditions, + "contexts": contexts, + "userContexts": user_contexts, + } diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/__init__.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/__init__.py @@ -0,0 +1 @@ +OFFLINE_NETWORK_CONDITIONS = {"type": "offline"} diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/conftest.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/conftest.py @@ -0,0 +1,78 @@ +import uuid + +import pytest_asyncio + +from webdriver.bidi.error import UnknownErrorException +from webdriver.bidi.modules.script import ContextTarget, \ + ScriptEvaluateResultException + + +@pytest_asyncio.fixture +async def get_navigator_online(bidi_session): + async def get_navigator_online(context): + result = await bidi_session.script.evaluate( + expression="navigator.onLine", + target=ContextTarget(context["context"]), + await_promise=True, + ) + + return result["value"] + + return get_navigator_online + + +@pytest_asyncio.fixture +async def get_can_fetch(bidi_session, url): + async def get_can_fetch(context): + try: + await bidi_session.script.call_function( + function_declaration=f"(url)=>fetch(url)", + arguments=[{ + "type": "string", + "value": url(f"/common/blank.html?{uuid.uuid4()}") + }], + target=ContextTarget(context["context"]), + await_promise=True, + ) + return True + except ScriptEvaluateResultException: + return False + + return get_can_fetch + + +@pytest_asyncio.fixture +async def get_can_navigate(bidi_session, url): + async def get_can_navigate(context): + try: + await bidi_session.browsing_context.navigate( + context=context["context"], + url=url(f"/common/blank.html?{uuid.uuid4()}"), + wait="complete") + return True + except UnknownErrorException: + return False + + return get_can_navigate + + +@pytest_asyncio.fixture(params=['default', 'new'], + ids=["Default user context", "Custom user context"]) +async def target_user_context(request, create_user_context): + return request.param + + +@pytest_asyncio.fixture +async def affected_user_context(target_user_context, create_user_context): + """ Returns either a new or default user context. """ + if target_user_context == 'default': + return 'default' + return await create_user_context() + + +@pytest_asyncio.fixture +async def not_affected_user_context(target_user_context, create_user_context): + """ Returns opposite to `affected_user_context user context. """ + if target_user_context == 'new': + return 'default' + return await create_user_context() diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/contexts.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/contexts.py @@ -0,0 +1,171 @@ +import pytest + +from . import OFFLINE_NETWORK_CONDITIONS + +pytestmark = pytest.mark.asyncio + + +async def test_isolation(bidi_session, top_context, + get_navigator_online): + another_context = await bidi_session.browsing_context.create( + type_hint="tab") + + assert await get_navigator_online(top_context) + assert await get_navigator_online(another_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[top_context["context"]]) + + assert not await get_navigator_online(top_context) + assert await get_navigator_online(another_context) + yet_another_context = await bidi_session.browsing_context.create( + type_hint="tab") + assert await get_navigator_online(yet_another_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]]) + + assert await get_navigator_online(top_context) + assert await get_navigator_online(another_context) + assert await get_navigator_online(yet_another_context) + + +@pytest.mark.parametrize("domain", ["", "alt"], + ids=["same_origin", "cross_origin"]) +async def test_frame(bidi_session, url, get_navigator_online, + top_context, create_iframe, domain): + iframe_id = await create_iframe(top_context, url('/', domain=domain)); + + assert await get_navigator_online(iframe_id) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[top_context["context"]]) + + assert not await get_navigator_online(iframe_id) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]]) + + assert await get_navigator_online(iframe_id) + + +async def test_overrides_user_contexts(bidi_session, get_navigator_online, + affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[affected_context["context"]]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[affected_context["context"]]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[affected_user_context]) + + assert await get_navigator_online(affected_context) + + +async def test_restores_to_user_contexts_when_removed(bidi_session, + get_navigator_online, + affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[affected_context["context"]]) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + user_contexts=[affected_user_context]) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[affected_context["context"]]) + + assert not await get_navigator_online(affected_context) + + +async def test_overrides_global(bidi_session, get_navigator_online, + affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[affected_context["context"]]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[affected_context["context"]]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None) + + assert await get_navigator_online(affected_context) + + +async def test_restores_to_global_when_removed(bidi_session, + get_navigator_online, + affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[affected_context["context"]]) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[affected_context["context"]]) + + assert not await get_navigator_online(affected_context) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/global.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/global.py @@ -0,0 +1,47 @@ +import pytest + +from . import OFFLINE_NETWORK_CONDITIONS + +pytestmark = pytest.mark.asyncio + + +async def test_top_level(bidi_session, create_user_context, + get_navigator_online, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS) + + assert not await get_navigator_online(affected_context) + + another_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + assert not await get_navigator_online(another_affected_context) + + await bidi_session.emulation.set_network_conditions(network_conditions=None) + + assert await get_navigator_online(affected_context) + assert await get_navigator_online(another_affected_context) + + +@pytest.mark.parametrize("domain", ["", "alt"], + ids=["same_origin", "cross_origin"]) +async def test_iframe(bidi_session, url, get_navigator_online, + top_context, create_iframe, domain, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + iframe_id = await create_iframe(affected_context, url('/', domain=domain)) + + assert await get_navigator_online(iframe_id) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS) + + assert not await get_navigator_online(iframe_id) + + await bidi_session.emulation.set_network_conditions(network_conditions=None) + + assert await get_navigator_online(iframe_id) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/invalid.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/invalid.py @@ -0,0 +1,129 @@ +import pytest + +import webdriver.bidi.error as error +from tests.bidi import get_invalid_cases +from webdriver.bidi.undefined import UNDEFINED + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.parametrize("value", get_invalid_cases("list")) +async def test_params_contexts_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=value + ) + + +async def test_params_contexts_empty_list(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[]) + + +@pytest.mark.parametrize("value", get_invalid_cases("string")) +async def test_params_contexts_entry_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[value]) + + +async def test_params_contexts_entry_invalid_value(bidi_session): + with pytest.raises(error.NoSuchFrameException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=["_invalid_"], + ) + + +async def test_params_contexts_iframe(bidi_session, new_tab, get_test_page): + url = get_test_page(as_frame=True) + await bidi_session.browsing_context.navigate( + context=new_tab["context"], url=url, wait="complete" + ) + + contexts = await bidi_session.browsing_context.get_tree( + root=new_tab["context"]) + assert len(contexts) == 1 + frames = contexts[0]["children"] + assert len(frames) == 1 + + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[frames[0]["context"]], + ) + + +@pytest.mark.parametrize("value", get_invalid_cases("list")) +async def test_params_user_contexts_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=value, + ) + + +async def test_params_user_contexts_empty_list(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[], + ) + + +@pytest.mark.parametrize("value", get_invalid_cases("string")) +async def test_params_user_contexts_entry_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[value], + ) + + +@pytest.mark.parametrize("value", ["", "somestring"]) +async def test_params_user_contexts_entry_invalid_value(bidi_session, value): + with pytest.raises(error.NoSuchUserContextException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[value], + ) + + +async def test_params_contexts_and_user_contexts(bidi_session, top_context): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]], + user_contexts=["default"], + ) + + +async def test_params_network_conditions_missing(bidi_session, top_context): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=UNDEFINED, + contexts=[top_context["context"]], + ) + + +@pytest.mark.parametrize("value", get_invalid_cases("dict", nullable=True)) +async def test_params_network_conditions_invalid_type(bidi_session, top_context, + value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions=value, + contexts=[top_context["context"]], + ) + + +async def test_params_network_conditions_invalid_value(bidi_session, + top_context): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.emulation.set_network_conditions( + network_conditions={"type": "SOME_INVALID_TYPE"}, + contexts=[top_context["context"]], + ) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/network_conditions_offline.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/network_conditions_offline.py @@ -0,0 +1,123 @@ +import pytest + +from tests.bidi import recursive_compare +from webdriver.bidi.modules.script import ContextTarget +from . import OFFLINE_NETWORK_CONDITIONS + +pytestmark = pytest.mark.asyncio + + +async def test_navigator_online(bidi_session, top_context, + get_navigator_online): + assert await get_navigator_online(top_context) + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[top_context["context"]]) + assert not await get_navigator_online(top_context) + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]]) + assert await get_navigator_online(top_context) + + +async def test_fetch(bidi_session, top_context, url, get_can_fetch): + # Navigate away from about:blank to allow fetch requests. + await bidi_session.browsing_context.navigate( + context=top_context["context"], + url=url(f"/common/blank.html"), + wait="complete") + + assert await get_can_fetch(top_context) + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[top_context["context"]]) + assert not await get_can_fetch(top_context) + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]]) + assert await get_can_fetch(top_context) + + +async def test_navigate(bidi_session, top_context, url, + get_can_navigate): + assert await get_can_navigate(top_context) + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[top_context["context"]]) + assert not await get_can_navigate(top_context) + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]]) + assert await get_can_navigate(top_context) + + +async def test_window_offline_online_events(bidi_session, top_context, url, + subscribe_events, wait_for_event, wait_for_future_safe): + await subscribe_events(["script.message"]) + await bidi_session.script.call_function( + function_declaration="""(channel)=>{ + window.addEventListener("offline", (e) => {{ + channel("offline, isTrusted: "+ e.isTrusted); + }}); + window.addEventListener("online", (e) => {{ + channel("online, isTrusted: "+ e.isTrusted); + }}); + }""", + arguments=[{ + "type": "channel", + "value": { + "channel": "channel_name" + } + }], + target=ContextTarget(top_context["context"]), + await_promise=True, + ) + + on_script_message = wait_for_event("script.message") + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + contexts=[top_context["context"]]) + + # Wait for the window `offline` event. + event_data = await wait_for_future_safe(on_script_message) + recursive_compare( + { + 'channel': 'channel_name', + 'data': { + 'type': 'string', + 'value': 'offline, isTrusted: true' + }, + }, event_data, + ) + + on_script_message = wait_for_event("script.message") + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + contexts=[top_context["context"]]) + + # Wait for the window `online` event. + event_data = await wait_for_future_safe(on_script_message) + recursive_compare( + { + 'channel': 'channel_name', + 'data': { + 'type': 'string', + 'value': 'online, isTrusted: true' + }, + }, event_data, + ) + + +@pytest.mark.skip("TODO: implement the test") +async def test_websocket_disconnected(): + pass + + +@pytest.mark.skip("TODO: implement the test") +async def test_service_worker_fetch(): + pass + + +@pytest.mark.skip("TODO: implement the test") +async def test_service_worker_websocket_disconnected(): + pass diff --git a/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/user_contexts.py b/testing/web-platform/tests/webdriver/tests/bidi/emulation/set_network_conditions/user_contexts.py @@ -0,0 +1,120 @@ +import pytest + +from . import OFFLINE_NETWORK_CONDITIONS + +pytestmark = pytest.mark.asyncio + + +async def test_isolation(bidi_session, create_user_context, + get_navigator_online, affected_user_context, not_affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + not_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=not_affected_user_context) + + assert await get_navigator_online(affected_context) + assert await get_navigator_online(not_affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(affected_context) + assert await get_navigator_online(not_affected_context) + + another_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + another_not_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=not_affected_user_context) + assert not await get_navigator_online(another_affected_context) + assert await get_navigator_online(another_not_affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[affected_user_context]) + + assert await get_navigator_online(affected_context) + assert await get_navigator_online(not_affected_context) + assert await get_navigator_online(another_affected_context) + assert await get_navigator_online(another_not_affected_context) + + +@pytest.mark.parametrize("domain", ["", "alt"], + ids=["same_origin", "cross_origin"]) +async def test_frame(bidi_session, url, get_navigator_online, + top_context, create_iframe, domain, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + iframe_id = await create_iframe(affected_context, url('/', domain=domain)) + + assert await get_navigator_online(iframe_id) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(iframe_id) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[affected_user_context]) + + assert await get_navigator_online(iframe_id) + + +async def test_overrides_global(bidi_session, get_navigator_online, + affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None) + + assert await get_navigator_online(affected_context) + + +async def test_restores_to_global_when_removed(bidi_session, + get_navigator_online, + affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + + assert await get_navigator_online(affected_context) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS, + user_contexts=[affected_user_context]) + + await bidi_session.emulation.set_network_conditions( + network_conditions=OFFLINE_NETWORK_CONDITIONS) + + await bidi_session.emulation.set_network_conditions( + network_conditions=None, + user_contexts=[affected_user_context]) + + assert not await get_navigator_online(affected_context) diff --git a/testing/web-platform/tests/webdriver/tests/support/fixtures_bidi.py b/testing/web-platform/tests/webdriver/tests/support/fixtures_bidi.py @@ -241,7 +241,30 @@ def current_time(bidi_session, top_context): @pytest.fixture -def add_and_remove_iframe(bidi_session): +def create_iframe(bidi_session): + """ + Create an iframe and wait for it to load. Return the iframe's context id. + """ + + async def create_iframe(context, url): + resp = await bidi_session.script.call_function( + function_declaration="""(url) => { + const iframe = document.createElement("iframe"); + iframe.src = url; + document.documentElement.lastElementChild.append(iframe); + return new Promise(resolve => iframe.onload = () => resolve(iframe.contentWindow)); + }""", + arguments=[{"type": "string", "value": url}], + target=ContextTarget(context["context"]), + await_promise=True) + assert resp["type"] == "window" + return resp["value"] + + return create_iframe + + +@pytest.fixture +def add_and_remove_iframe(bidi_session, create_iframe): """Create a frame, wait for load, and remove it. Return the frame's context id, which allows to test for invalid