diff --git a/src/bidiMapper/modules/context/BrowsingContextImpl.ts b/src/bidiMapper/modules/context/BrowsingContextImpl.ts index b4f8e938ef..a9957a46da 100644 --- a/src/bidiMapper/modules/context/BrowsingContextImpl.ts +++ b/src/bidiMapper/modules/context/BrowsingContextImpl.ts @@ -712,8 +712,12 @@ export class BrowsingContextImpl { case BrowsingContext.UserPromptType.Beforeunload: return ( this.#unhandledPromptBehavior?.beforeUnload ?? - this.#unhandledPromptBehavior?.default ?? - defaultPromptHandler + // In WebDriver Classic spec, `beforeUnload` prompt should be accepted by + // default. Step 4 of "Get the prompt handler" algorithm + // (https://w3c.github.io/webdriver/#dfn-get-the-prompt-handler): + // > If type is "beforeUnload", return a prompt handler configuration with + // handler "accept" and notify false. + Session.UserPromptHandlerType.Accept ); case BrowsingContext.UserPromptType.Confirm: return ( diff --git a/tests/browsing_context/test_close.py b/tests/browsing_context/test_close.py index d89ca200df..f1369f7ea4 100644 --- a/tests/browsing_context/test_close.py +++ b/tests/browsing_context/test_close.py @@ -55,7 +55,7 @@ async def test_browsingContext_close(websocket, context_id): @pytest.mark.asyncio @pytest.mark.parametrize('capabilities', [{ 'unhandledPromptBehavior': { - 'default': 'ignore' + 'beforeUnload': 'ignore' } }], indirect=True) @@ -170,11 +170,10 @@ async def test_browsingContext_close_prompt(websocket, context_id, html, @pytest.mark.asyncio @pytest.mark.parametrize('capabilities', [{ 'unhandledPromptBehavior': { - 'default': 'ignore' + 'beforeUnload': 'ignore' } }], indirect=True) -# @pytest.mark.parametrize("accept", [True]) @pytest.mark.parametrize("accept", [True, False]) async def test_browsingContext_navigate_prompt(websocket, context_id, html, accept): diff --git a/tests/browsing_context/test_user_prompt.py b/tests/browsing_context/test_user_prompt.py index 303bb6b1da..3bcc96a16c 100644 --- a/tests/browsing_context/test_user_prompt.py +++ b/tests/browsing_context/test_user_prompt.py @@ -13,7 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. import pytest -from test_helpers import send_JSON_command, subscribe, wait_for_event +from anys import ANY_DICT +from test_helpers import (AnyExtending, execute_command, goto_url, + read_JSON_message, send_JSON_command, subscribe, + wait_for_event) @pytest.mark.asyncio @@ -87,7 +90,7 @@ } }], indirect=True) -async def test_browsingContext_userPromptOpened_userPromptClosed( +async def test_browsingContext_userPromptOpened_capabilityRespected( websocket, context_id, prompt_type, capabilities): await subscribe(websocket, [ "browsingContext.userPromptOpened", "browsingContext.userPromptClosed" @@ -162,42 +165,135 @@ async def test_browsingContext_userPromptOpened_userPromptClosed( @pytest.mark.asyncio -@pytest.mark.parametrize('capabilities', [{ +@pytest.mark.parametrize('capabilities', [{}, { + 'unhandledPromptBehavior': 'dismiss' +}, { + 'unhandledPromptBehavior': 'dismiss and notify' +}, { + 'unhandledPromptBehavior': { + 'default': 'dismiss' + } +}, { 'unhandledPromptBehavior': { + 'beforeUnload': 'dismiss', 'default': 'ignore' } +}, { + 'unhandledPromptBehavior': 'accept' +}, { + 'unhandledPromptBehavior': 'accept and notify' +}, { + 'unhandledPromptBehavior': { + 'default': 'accept' + } +}, { + 'unhandledPromptBehavior': { + 'beforeUnload': 'accept', + 'default': 'ignore' + } +}, { + 'unhandledPromptBehavior': 'ignore' +}, { + 'unhandledPromptBehavior': { + 'default': 'ignore' + } +}, { + 'unhandledPromptBehavior': { + 'beforeUnload': 'ignore', + 'default': 'accept' + } }], indirect=True) -async def test_browsingContext_userPromptOpened_event_default_value( - websocket, context_id): - +async def test_browsingContext_beforeUnloadPromptOpened_capabilityRespected( + websocket, context_id, html, capabilities): await subscribe(websocket, ["browsingContext.userPromptOpened"]) - message = 'Prompt Opened' - default = 'Prompt Default' + url = html(""" + + """) - await send_JSON_command( + await goto_url(websocket, context_id, url) + + # We need to interact with the page to trigger "beforeunload" + await execute_command( websocket, { "method": "script.evaluate", "params": { - "expression": f"""prompt('{message}', '{default}')""", - "awaitPromise": True, + "expression": "document.body.click()", "target": { - "context": context_id, - } + "context": context_id + }, + "awaitPromise": False, + "userActivation": True } }) - response = await wait_for_event(websocket, - "browsingContext.userPromptOpened") - assert response == { + navigate_command_id = await send_JSON_command( + websocket, { + "method": "browsingContext.navigate", + "params": { + "url": 'about:blank', + "context": context_id, + "wait": "complete" + } + }) + + # Default behavior is to accept the before unload prompt. + expected_handler = 'accept' + if 'unhandledPromptBehavior' in capabilities: + if 'beforeUnload' in capabilities['unhandledPromptBehavior']: + expected_handler = capabilities['unhandledPromptBehavior'][ + 'beforeUnload'] + + resp = await read_JSON_message(websocket) + assert resp == { + 'method': 'browsingContext.userPromptOpened', + 'params': { + 'context': context_id, + 'handler': expected_handler, + 'message': '', + 'type': 'beforeunload', + }, 'type': 'event', - "method": "browsingContext.userPromptOpened", - "params": { - "context": context_id, - "type": 'prompt', - 'handler': 'ignore', - "message": message, - "defaultValue": default, - } } + + if expected_handler == 'accept': + # Assert navigation succeeded. + resp = await read_JSON_message(websocket) + assert resp == { + 'id': navigate_command_id, + 'result': ANY_DICT, + 'type': 'success', + } + elif expected_handler == 'dismiss': + # Assert navigation failed. + resp = await read_JSON_message(websocket) + assert resp == AnyExtending({ + 'id': navigate_command_id, + 'type': 'error' + }) + elif expected_handler == 'ignore': + # Handle prompt. + await execute_command( + websocket, { + "method": "browsingContext.handleUserPrompt", + "params": { + "context": context_id, + "accept": True + } + }) + + # Assert navigation succeeded. + resp = await read_JSON_message(websocket) + assert resp == { + 'id': navigate_command_id, + 'result': ANY_DICT, + 'type': 'success', + } + else: + assert False, f"Unexpected handler: {expected_handler}" diff --git a/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/close/prompt_unload.py.ini b/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/close/prompt_unload.py.ini index 682bdc9fa7..616451249a 100644 --- a/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/close/prompt_unload.py.ini +++ b/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/close/prompt_unload.py.ini @@ -4,3 +4,9 @@ [test_prompt_unload_triggering_dialog[tab\]] expected: FAIL + + [test_prompt_unload_triggering_dialog[capabilities0-window\]] + expected: FAIL + + [test_prompt_unload_triggering_dialog[capabilities0-tab\]] + expected: FAIL diff --git a/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/handle_user_prompt/handle_user_prompt.py.ini b/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/handle_user_prompt/handle_user_prompt.py.ini new file mode 100644 index 0000000000..140a58c30c --- /dev/null +++ b/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/handle_user_prompt/handle_user_prompt.py.ini @@ -0,0 +1,6 @@ +[handle_user_prompt.py] + [test_beforeunload[capabilities0-True\]] + expected: FAIL + + [test_beforeunload[capabilities0-False\]] + expected: FAIL diff --git a/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/user_prompt_closed/beforeunload.py.ini b/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/user_prompt_closed/beforeunload.py.ini new file mode 100644 index 0000000000..038eceaa65 --- /dev/null +++ b/wpt-metadata/mapper/headless/webdriver/tests/bidi/browsing_context/user_prompt_closed/beforeunload.py.ini @@ -0,0 +1,6 @@ +[beforeunload.py] + [test_beforeunload[capabilities0-False\]] + expected: FAIL + + [test_beforeunload[capabilities0-True\]] + expected: FAIL