diff --git a/src/bidiMapper/modules/context/NavigationTracker.spec.ts b/src/bidiMapper/modules/context/NavigationTracker.spec.ts index 54420e6a4d..081a17ddf4 100644 --- a/src/bidiMapper/modules/context/NavigationTracker.spec.ts +++ b/src/bidiMapper/modules/context/NavigationTracker.spec.ts @@ -310,7 +310,12 @@ describe('NavigationTracker', () => { navigationTracker.frameNavigated(YET_ANOTHER_URL, LOADER_ID); - assertNoNavigationEvents(); + assertNavigationEvent( + ChromiumBidi.BrowsingContext.EventNames.NavigationCommitted, + sinon.match.any, + YET_ANOTHER_URL, + ); + assert.equal(navigationTracker.url, YET_ANOTHER_URL); navigationTracker.loadPageEvent(LOADER_ID); diff --git a/src/bidiMapper/modules/context/NavigationTracker.ts b/src/bidiMapper/modules/context/NavigationTracker.ts index 957ac916d7..028dbe93ec 100644 --- a/src/bidiMapper/modules/context/NavigationTracker.ts +++ b/src/bidiMapper/modules/context/NavigationTracker.ts @@ -121,6 +121,16 @@ export class NavigationState { frameNavigated() { this.#navigated = true; + if (!this.#isInitial) { + this.#eventManager.registerEvent( + { + type: 'event', + method: ChromiumBidi.BrowsingContext.EventNames.NavigationCommitted, + params: this.navigationInfo(), + }, + this.#browsingContextId, + ); + } } fragmentNavigated() { @@ -257,7 +267,7 @@ export class NavigationTracker { if ( this.#pendingNavigation !== undefined && - this.#pendingNavigation?.loaderId === undefined + this.#pendingNavigation.loaderId === undefined ) { // This can be a pending navigation to `about:blank` created by a command. Use the // pending navigation in this case. @@ -289,7 +299,6 @@ export class NavigationTracker { } const navigation = this.#getNavigationForFrameNavigated(url, loaderId); - navigation.frameNavigated(); if (navigation !== this.#currentNavigation) { this.#currentNavigation.fail( @@ -301,6 +310,7 @@ export class NavigationTracker { navigation.loaderId = loaderId; this.#loaderIdToNavigationsMap.set(loaderId, navigation); navigation.start(); + navigation.frameNavigated(); this.#currentNavigation = navigation; if (this.#pendingNavigation === navigation) { diff --git a/tests/browsing_context/__snapshots__/test_navigate_events.ambr b/tests/browsing_context/__snapshots__/test_navigate_events.ambr index 4ca2f4db7d..d78eb4bebf 100644 --- a/tests/browsing_context/__snapshots__/test_navigate_events.ambr +++ b/tests/browsing_context/__snapshots__/test_navigate_events.ambr @@ -24,6 +24,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -88,6 +97,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -152,6 +170,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -242,6 +269,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_6', + 'url': 'stable_7', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -295,6 +331,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -359,6 +404,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -423,6 +477,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -493,6 +556,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.navigationStarted', 'params': dict({ @@ -511,6 +583,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_3', + 'url': 'stable_4', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -542,6 +623,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.domContentLoaded', 'params': dict({ @@ -573,6 +663,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.fragmentNavigated', 'params': dict({ @@ -613,6 +712,15 @@ }), 'type': 'event', }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_1', + 'url': 'stable_2', + }), + 'type': 'event', + }), dict({ 'method': 'browsingContext.fragmentNavigated', 'params': dict({ @@ -642,3 +750,107 @@ }), ]) # --- +# name: test_window_open_aboutBlank_checkEvents[] + list([ + dict({ + 'method': 'browsingContext.contextCreated', + 'params': dict({ + 'children': None, + 'clientWindow': '', + 'context': 'stable_0', + 'originalOpener': 'stable_2', + 'parent': None, + 'url': 'stable_1', + 'userContext': 'default', + }), + 'type': 'event', + }), + ]) +# --- +# name: test_window_open_aboutBlank_checkEvents[about:blank?test] + list([ + dict({ + 'method': 'browsingContext.contextCreated', + 'params': dict({ + 'children': None, + 'clientWindow': '', + 'context': 'stable_0', + 'originalOpener': 'stable_2', + 'parent': None, + 'url': 'stable_1', + 'userContext': 'default', + }), + 'type': 'event', + }), + ]) +# --- +# name: test_window_open_aboutBlank_checkEvents[about:blank] + list([ + dict({ + 'method': 'browsingContext.contextCreated', + 'params': dict({ + 'children': None, + 'clientWindow': '', + 'context': 'stable_0', + 'originalOpener': 'stable_2', + 'parent': None, + 'url': 'stable_1', + 'userContext': 'default', + }), + 'type': 'event', + }), + ]) +# --- +# name: test_window_open_url_checkEvents + list([ + dict({ + 'method': 'browsingContext.contextCreated', + 'params': dict({ + 'children': None, + 'clientWindow': '', + 'context': 'stable_0', + 'originalOpener': 'stable_2', + 'parent': None, + 'url': 'stable_1', + 'userContext': 'default', + }), + 'type': 'event', + }), + dict({ + 'method': 'browsingContext.navigationStarted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_3', + 'url': 'stable_4', + }), + 'type': 'event', + }), + dict({ + 'method': 'browsingContext.navigationCommitted', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_3', + 'url': 'stable_4', + }), + 'type': 'event', + }), + dict({ + 'method': 'browsingContext.domContentLoaded', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_3', + 'url': 'stable_4', + }), + 'type': 'event', + }), + dict({ + 'method': 'browsingContext.load', + 'params': dict({ + 'context': 'stable_0', + 'navigation': 'stable_3', + 'url': 'stable_4', + }), + 'type': 'event', + }), + ]) +# --- diff --git a/tests/browsing_context/test_create.py b/tests/browsing_context/test_create.py index 4e87e69ecf..adcbda4b0a 100644 --- a/tests/browsing_context/test_create.py +++ b/tests/browsing_context/test_create.py @@ -112,7 +112,7 @@ async def test_browsingContext_windowOpen_nonBlank_eventsEmitted( }) events = await read_messages( - 4, + 5, # Filter out the command result, as it's order is not defined. filter_lambda=lambda m: 'id' not in m, keys_to_stabilize=['context', 'navigation'], @@ -140,6 +140,15 @@ async def test_browsingContext_windowOpen_nonBlank_eventsEmitted( 'url': url_example, }, 'type': 'event', + }, { + 'method': 'browsingContext.navigationCommitted', + 'params': { + 'context': 'stable_0', + 'navigation': 'stable_1', + 'timestamp': ANY_TIMESTAMP, + 'url': url_example, + }, + 'type': 'event', }, { 'method': 'browsingContext.domContentLoaded', 'params': { diff --git a/tests/browsing_context/test_navigate_events.py b/tests/browsing_context/test_navigate_events.py index 6d8dc3833a..d86c5963d3 100644 --- a/tests/browsing_context/test_navigate_events.py +++ b/tests/browsing_context/test_navigate_events.py @@ -20,7 +20,9 @@ SNAPSHOT_EXCLUDE = props("timestamp", "timings", "headers", "stacktrace", "response", "initiator", "realm") -KEYS_TO_STABILIZE = ['context', 'navigation', 'id', 'url', 'request'] +KEYS_TO_STABILIZE = [ + 'context', 'navigation', 'id', 'url', 'request', 'originalOpener' +] async def set_beforeunload_handler(websocket, context_id): @@ -69,7 +71,58 @@ async def test_navigate_checkEvents(websocket, context_id, url_base, } }) - messages = await read_messages(6, + messages = await read_messages(7, + keys_to_stabilize=KEYS_TO_STABILIZE, + check_no_other_messages=True, + sort=False) + assert messages == snapshot(exclude=SNAPSHOT_EXCLUDE) + + +@pytest.mark.asyncio +async def test_window_open_url_checkEvents(websocket, context_id, url_example, + read_messages, snapshot): + await subscribe(websocket, ["browsingContext"]) + + await send_JSON_command( + websocket, { + "method": "script.evaluate", + "params": { + "expression": f"window.open('{url_example}');", + "target": { + "context": context_id, + }, + "awaitPromise": False + } + }) + + messages = await read_messages(5, + filter_lambda=lambda x: 'id' not in x, + keys_to_stabilize=KEYS_TO_STABILIZE, + check_no_other_messages=True, + sort=False) + assert messages == snapshot(exclude=SNAPSHOT_EXCLUDE) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("url", ["", "about:blank", "about:blank?test"]) +async def test_window_open_aboutBlank_checkEvents(websocket, context_id, url, + read_messages, snapshot): + await subscribe(websocket, ["browsingContext"]) + + await send_JSON_command( + websocket, { + "method": "script.evaluate", + "params": { + "expression": f"window.open('{url}');", + "target": { + "context": context_id, + }, + "awaitPromise": False + } + }) + + messages = await read_messages(1, + filter_lambda=lambda x: 'id' not in x, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False) @@ -97,7 +150,7 @@ async def test_navigate_aboutBlank_checkEvents(websocket, context_id, url_base, } }) - messages = await read_messages(5, + messages = await read_messages(6, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False) @@ -125,7 +178,7 @@ async def test_navigate_dataUrl_checkEvents(websocket, context_id, url_base, } }) - messages = await read_messages(6, + messages = await read_messages(7, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False) @@ -167,7 +220,7 @@ async def test_navigate_hang_navigate_again_checkEvents( } }) - messages = await read_messages(9, + messages = await read_messages(10, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False) @@ -192,7 +245,7 @@ async def test_scriptNavigate_checkEvents(websocket, context_id, url_example, }) messages = await read_messages( - 5, + 7, # Filter out command result, as it can be # racy with other events. filter_lambda=lambda x: 'id' not in x, @@ -257,7 +310,7 @@ async def test_scriptNavigate_dataUrl_checkEvents(websocket, context_id, }) messages = await read_messages( - 3, + 4, # Filter out command result, as it can be # racy with other events. filter_lambda=lambda x: 'id' not in x, @@ -286,7 +339,7 @@ async def test_scriptNavigate_fragment_checkEvents(websocket, context_id, }) messages = await read_messages( - 4, + 5, # Filter out command result, as it can be # racy with other events. filter_lambda=lambda x: 'id' not in x, @@ -314,7 +367,7 @@ async def test_scriptNavigate_fragment_nested_checkEvents( }) messages = await read_messages( - 4, + 5, # Filter out command result, as it can be # racy with other events. filter_lambda=lambda x: 'id' not in x, @@ -343,7 +396,7 @@ async def test_reload_checkEvents(websocket, context_id, url_example, html, } }) - messages = await read_messages(6, + messages = await read_messages(7, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False) @@ -371,7 +424,7 @@ async def test_reload_aboutBlank_checkEvents(websocket, context_id, html, } }) - messages = await read_messages(5, + messages = await read_messages(6, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False) @@ -398,7 +451,7 @@ async def test_reload_dataUrl_checkEvents(websocket, context_id, html, } }) - messages = await read_messages(6, + messages = await read_messages(7, keys_to_stabilize=KEYS_TO_STABILIZE, check_no_other_messages=True, sort=False)