From 2b16dcf51dc5bfae3d62450b5368b87a782d08c9 Mon Sep 17 00:00:00 2001 From: Nikolay Vitkov Date: Tue, 12 Sep 2023 13:34:22 +0200 Subject: [PATCH 1/4] [WebDriver BiDi] `addPreloadScript` supports contexts --- .../webdriver/bidi/modules/script.py | 3 + .../script/add_preload_script/contexts.py | 85 +++++++++++++++++++ .../add_preload_script/contexts_tentative.py | 28 ++++++ .../bidi/script/add_preload_script/invalid.py | 49 ++++++++++- webdriver/tests/support/fixtures_bidi.py | 3 +- 5 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 webdriver/tests/bidi/script/add_preload_script/contexts.py create mode 100644 webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py diff --git a/tools/webdriver/webdriver/bidi/modules/script.py b/tools/webdriver/webdriver/bidi/modules/script.py index f128b0d089c28b..737426a5d54641 100644 --- a/tools/webdriver/webdriver/bidi/modules/script.py +++ b/tools/webdriver/webdriver/bidi/modules/script.py @@ -96,6 +96,7 @@ def add_preload_script( self, function_declaration: str, arguments: Optional[List[Mapping[str, Any]]] = None, + contexts: Optional[List[str]] = None, sandbox: Optional[str] = None ) -> Mapping[str, Any]: params: MutableMapping[str, Any] = { @@ -104,6 +105,8 @@ def add_preload_script( if arguments is not None: params["arguments"] = arguments + if contexts is not None: + params["contexts"] = contexts if sandbox is not None: params["sandbox"] = sandbox diff --git a/webdriver/tests/bidi/script/add_preload_script/contexts.py b/webdriver/tests/bidi/script/add_preload_script/contexts.py new file mode 100644 index 00000000000000..7c8cdf48ec5476 --- /dev/null +++ b/webdriver/tests/bidi/script/add_preload_script/contexts.py @@ -0,0 +1,85 @@ +import pytest + +from webdriver.bidi.modules.script import ContextTarget + + +@pytest.mark.asyncio +@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) +async def test_add_preload_script_in_frame_with_top_context_specified( + bidi_session, add_preload_script, new_tab, + inline, iframe, domain): + + iframe_content = f"
{domain}
" + url = inline(f"{iframe(iframe_content, domain=domain)}") + + await add_preload_script( + function_declaration="() => { window.bar='foo'; }", + contexts=[new_tab["context"]]) + + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=url, + wait="complete", + ) + + # Check that preload script applied the changes to the window + result = await bidi_session.script.evaluate( + expression="window.bar", + target=ContextTarget(new_tab["context"]), + await_promise=True, + ) + assert result == {"type": "string", "value": "foo"} + + contexts = await bidi_session.browsing_context.get_tree( + root=new_tab["context"]) + + assert len(contexts[0]["children"]) == 1 + frame_context = contexts[0]["children"][0] + + # Check that preload script applied the changes to the iframe + result = await bidi_session.script.evaluate( + expression="window.bar", + target=ContextTarget(frame_context["context"]), + await_promise=True, + ) + assert result == {"type": "string", "value": "foo"} + + +@pytest.mark.asyncio +@pytest.mark.parametrize("type_hint", ["tab", "window"]) +async def test_page_script_context_isolation(bidi_session, add_preload_script, + top_context, type_hint, + test_page): + await add_preload_script(function_declaration="() => { window.baz = 42; }", + contexts=[top_context['context']]) + + new_context = await bidi_session.browsing_context.create( + type_hint=type_hint) + + # Navigate both contexts to ensure preload script is triggered + await bidi_session.browsing_context.navigate( + context=top_context['context'], + url=test_page, + wait="complete", + ) + await bidi_session.browsing_context.navigate( + context=new_context["context"], + url=test_page, + wait="complete", + ) + + # Check that preload script applied the changes to the window + result = await bidi_session.script.evaluate( + expression="window.baz", + target=ContextTarget(top_context["context"]), + await_promise=True, + ) + assert result == {"type": "number", "value": 42} + + # Check that preload script did *not* apply the changes to the other window + result = await bidi_session.script.evaluate( + expression="window.baz", + target=ContextTarget(new_context["context"]), + await_promise=True, + ) + assert result == {type: "undefined"} diff --git a/webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py b/webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py new file mode 100644 index 00000000000000..26a72c934a630e --- /dev/null +++ b/webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py @@ -0,0 +1,28 @@ +import pytest + +from webdriver.bidi.modules.script import ContextTarget + + +@pytest.mark.asyncio +async def test_add_preload_script_specify_context_multiple_times( + bidi_session, add_preload_script, new_tab, + test_page_same_origin_frame): + + await add_preload_script( + function_declaration= + "() => { window.foo = window.foo ? window.foo + 1 : 1; }", + contexts=[new_tab["context"], new_tab["context"]]) + + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=test_page_same_origin_frame, + wait="complete", + ) + + # Check that preload script applied the changes to the window + result = await bidi_session.script.evaluate( + expression="window.foo", + target=ContextTarget(new_tab["context"]), + await_promise=True, + ) + assert result == {"type": "number", "value": "1"} diff --git a/webdriver/tests/bidi/script/add_preload_script/invalid.py b/webdriver/tests/bidi/script/add_preload_script/invalid.py index 54440ff67804b6..95db8543b841ff 100644 --- a/webdriver/tests/bidi/script/add_preload_script/invalid.py +++ b/webdriver/tests/bidi/script/add_preload_script/invalid.py @@ -71,7 +71,8 @@ async def test_params_arguments_channel_ownership_invalid_value(bidi_session): with pytest.raises(error.InvalidArgumentException): await bidi_session.script.add_preload_script( function_declaration="() => {}", - arguments=[{"type": "channel", "value": {"ownership": "_UNKNOWN_"}}], + arguments=[{"type": "channel", "value": { + "ownership": "_UNKNOWN_"}}], ) @@ -186,6 +187,52 @@ async def test_params_arguments_channel_include_shadow_tree_invalid_value(bidi_s ) +@pytest.mark.parametrize("contexts", [False, 42, '_UNKNOWN_', {}]) +async def test_params_contexts_invalid_type(bidi_session, contexts): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.script.add_preload_script( + function_declaration="() => {}", + contexts=contexts + ), + + +async def test_params_contexts_empty_list(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.script.add_preload_script( + function_declaration="() => {}", + contexts=[] + ), + + +@pytest.mark.parametrize("value", ["", "somestring"]) +async def test_params_contexts_context_invalid_value(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.script.add_preload_script( + function_declaration="() => {}", + contexts=[value] + ), + + +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.script.add_preload_script( + function_declaration="() => {}", + contexts=[child_info['context']] + ), + + @pytest.mark.parametrize("sandbox", [False, 42, {}, []]) async def test_params_sandbox_invalid_type(bidi_session, sandbox): with pytest.raises(error.InvalidArgumentException): diff --git a/webdriver/tests/support/fixtures_bidi.py b/webdriver/tests/support/fixtures_bidi.py index c073997215e7a6..f4c4c19c3bbe7f 100644 --- a/webdriver/tests/support/fixtures_bidi.py +++ b/webdriver/tests/support/fixtures_bidi.py @@ -20,10 +20,11 @@ async def add_preload_script(bidi_session): preload_scripts_ids = [] - async def add_preload_script(function_declaration, arguments=None, sandbox=None): + async def add_preload_script(function_declaration, arguments=None, contexts=None, sandbox=None): script = await bidi_session.script.add_preload_script( function_declaration=function_declaration, arguments=arguments, + contexts=contexts, sandbox=sandbox, ) preload_scripts_ids.append(script) From 4157523941bb5182324bca70df775ec67112db07 Mon Sep 17 00:00:00 2001 From: Nikolay Vitkov Date: Mon, 18 Dec 2023 18:22:39 +0100 Subject: [PATCH 2/4] chore: fix comments --- .../add_preload_script/add_preload_script.py | 8 +++-- .../script/add_preload_script/contexts.py | 36 ++++++++++++++++--- .../add_preload_script/contexts_tentative.py | 28 --------------- .../bidi/script/add_preload_script/invalid.py | 9 +++++ 4 files changed, 47 insertions(+), 34 deletions(-) delete mode 100644 webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py diff --git a/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py b/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py index cf5e77fac44957..5e26e4e774a2a4 100644 --- a/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py +++ b/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py @@ -90,14 +90,18 @@ async def on_event(method, data): @pytest.mark.asyncio +@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) async def test_add_preload_script_in_iframe( - bidi_session, add_preload_script, new_tab, test_page_same_origin_frame + bidi_session, add_preload_script, new_tab, inline, iframe, domain, ): await add_preload_script(function_declaration="() => { window.bar='foo'; }") + iframe_content = f"
{domain}
" + url = inline(f"{iframe(iframe_content, domain=domain)}") + await bidi_session.browsing_context.navigate( context=new_tab["context"], - url=test_page_same_origin_frame, + url=url, wait="complete", ) diff --git a/webdriver/tests/bidi/script/add_preload_script/contexts.py b/webdriver/tests/bidi/script/add_preload_script/contexts.py index 7c8cdf48ec5476..b8e1b110bfcc15 100644 --- a/webdriver/tests/bidi/script/add_preload_script/contexts.py +++ b/webdriver/tests/bidi/script/add_preload_script/contexts.py @@ -5,7 +5,7 @@ @pytest.mark.asyncio @pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) -async def test_add_preload_script_in_frame_with_top_context_specified( +async def test_iframe( bidi_session, add_preload_script, new_tab, inline, iframe, domain): @@ -22,7 +22,7 @@ async def test_add_preload_script_in_frame_with_top_context_specified( wait="complete", ) - # Check that preload script applied the changes to the window + # Check that preload script applied the changes to the context result = await bidi_session.script.evaluate( expression="window.bar", target=ContextTarget(new_tab["context"]), @@ -68,7 +68,7 @@ async def test_page_script_context_isolation(bidi_session, add_preload_script, wait="complete", ) - # Check that preload script applied the changes to the window + # Check that preload script applied the changes to the context result = await bidi_session.script.evaluate( expression="window.baz", target=ContextTarget(top_context["context"]), @@ -76,10 +76,38 @@ async def test_page_script_context_isolation(bidi_session, add_preload_script, ) assert result == {"type": "number", "value": 42} - # Check that preload script did *not* apply the changes to the other window + # Check that preload script did *not* apply the changes to the other context result = await bidi_session.script.evaluate( expression="window.baz", target=ContextTarget(new_context["context"]), await_promise=True, ) assert result == {type: "undefined"} + + +@pytest.mark.asyncio +@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) +async def test_identical_contexts( + bidi_session, add_preload_script, new_tab, + inline, iframe, domain): + + iframe_content = f"
{domain}
" + url = inline(f"{iframe(iframe_content, domain=domain)}") + + await add_preload_script( + function_declaration="() => { window.foo = window.foo ? window.foo + 1 : 1; }", + contexts=[new_tab["context"], new_tab["context"]]) + + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=url, + wait="complete", + ) + + # Check that preload script applied the changes to the context only once + result = await bidi_session.script.evaluate( + expression="window.foo", + target=ContextTarget(new_tab["context"]), + await_promise=True, + ) + assert result == {"type": "number", "value": "1"} diff --git a/webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py b/webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py deleted file mode 100644 index 26a72c934a630e..00000000000000 --- a/webdriver/tests/bidi/script/add_preload_script/contexts_tentative.py +++ /dev/null @@ -1,28 +0,0 @@ -import pytest - -from webdriver.bidi.modules.script import ContextTarget - - -@pytest.mark.asyncio -async def test_add_preload_script_specify_context_multiple_times( - bidi_session, add_preload_script, new_tab, - test_page_same_origin_frame): - - await add_preload_script( - function_declaration= - "() => { window.foo = window.foo ? window.foo + 1 : 1; }", - contexts=[new_tab["context"], new_tab["context"]]) - - await bidi_session.browsing_context.navigate( - context=new_tab["context"], - url=test_page_same_origin_frame, - wait="complete", - ) - - # Check that preload script applied the changes to the window - result = await bidi_session.script.evaluate( - expression="window.foo", - target=ContextTarget(new_tab["context"]), - await_promise=True, - ) - assert result == {"type": "number", "value": "1"} diff --git a/webdriver/tests/bidi/script/add_preload_script/invalid.py b/webdriver/tests/bidi/script/add_preload_script/invalid.py index 95db8543b841ff..58f1ba02e5fc10 100644 --- a/webdriver/tests/bidi/script/add_preload_script/invalid.py +++ b/webdriver/tests/bidi/script/add_preload_script/invalid.py @@ -204,6 +204,15 @@ async def test_params_contexts_empty_list(bidi_session): ), +@pytest.mark.parametrize("value", [None, False, 42, {}, []]) +async def test_params_contexts_context_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.script.add_preload_script( + function_declaration="() => {}", + contexts=[value] + ), + + @pytest.mark.parametrize("value", ["", "somestring"]) async def test_params_contexts_context_invalid_value(bidi_session, value): with pytest.raises(error.InvalidArgumentException): From 4b9480409e349870846288694a055381a5ef4f6c Mon Sep 17 00:00:00 2001 From: Nikolay Vitkov Date: Tue, 2 Jan 2024 16:38:28 +0100 Subject: [PATCH 3/4] small fixes --- .../tests/bidi/script/add_preload_script/contexts.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/webdriver/tests/bidi/script/add_preload_script/contexts.py b/webdriver/tests/bidi/script/add_preload_script/contexts.py index b8e1b110bfcc15..97d00669d17136 100644 --- a/webdriver/tests/bidi/script/add_preload_script/contexts.py +++ b/webdriver/tests/bidi/script/add_preload_script/contexts.py @@ -5,7 +5,7 @@ @pytest.mark.asyncio @pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) -async def test_iframe( +async def test_top_context_with_iframes( bidi_session, add_preload_script, new_tab, inline, iframe, domain): @@ -86,13 +86,11 @@ async def test_page_script_context_isolation(bidi_session, add_preload_script, @pytest.mark.asyncio -@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) async def test_identical_contexts( bidi_session, add_preload_script, new_tab, - inline, iframe, domain): + inline): - iframe_content = f"
{domain}
" - url = inline(f"{iframe(iframe_content, domain=domain)}") + url = inline(f"
test
") await add_preload_script( function_declaration="() => { window.foo = window.foo ? window.foo + 1 : 1; }", From 16b1b63bc096dc5cc04c8b0356aef7ec8ca6190b Mon Sep 17 00:00:00 2001 From: Nikolay Vitkov Date: Fri, 5 Jan 2024 12:53:37 +0100 Subject: [PATCH 4/4] chore: fix --- .../bidi/script/add_preload_script/add_preload_script.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py b/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py index 5e26e4e774a2a4..cf5e77fac44957 100644 --- a/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py +++ b/webdriver/tests/bidi/script/add_preload_script/add_preload_script.py @@ -90,18 +90,14 @@ async def on_event(method, data): @pytest.mark.asyncio -@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"]) async def test_add_preload_script_in_iframe( - bidi_session, add_preload_script, new_tab, inline, iframe, domain, + bidi_session, add_preload_script, new_tab, test_page_same_origin_frame ): await add_preload_script(function_declaration="() => { window.bar='foo'; }") - iframe_content = f"
{domain}
" - url = inline(f"{iframe(iframe_content, domain=domain)}") - await bidi_session.browsing_context.navigate( context=new_tab["context"], - url=url, + url=test_page_same_origin_frame, wait="complete", )