diff --git a/moli-renderer-v8/src/native_bridge/context_host/child_frames/registry.rs b/moli-renderer-v8/src/native_bridge/context_host/child_frames/registry.rs index 8ba6ee1465..c1ce4f35fa 100644 --- a/moli-renderer-v8/src/native_bridge/context_host/child_frames/registry.rs +++ b/moli-renderer-v8/src/native_bridge/context_host/child_frames/registry.rs @@ -192,7 +192,14 @@ impl JsContextHost { let existing_document_policy = existing .as_ref() .map(|entry| entry.document_policy_container_snapshot()); - let name = self.dom_host().get_attribute(handle, "name"); + // The owner element's `name` attribute seeds the navigable target name only + // when the child navigable is created. Preserve later `window.name` writes + // across ordinary DOM-to-runtime record refreshes. + let name = existing + .as_ref() + .map(|entry| entry.name.clone()) + .unwrap_or_else(|| self.dom_host().get_attribute(handle, "name")) + .filter(|value| !value.is_empty()); let id = self.dom_host().get_attribute(handle, "id"); let credentialless = self .dom_host() @@ -332,7 +339,7 @@ impl JsContextHost { current_document_loader_id: existing.as_ref().and_then(|entry| { entry.current_document_loader_id().map(ToOwned::to_owned) }), - name: name.filter(|value| !value.is_empty()), + name, id: id.filter(|value| !value.is_empty()), attribute_bootstrap, pending_attribute_bootstrap_commit: diff --git a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs index 6724b1d6a2..2910982ff6 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs @@ -8828,6 +8828,76 @@ frame.name = 'target'; assert_eq!(result, "[object Window]|true|object"); } + +#[tokio::test] +async fn child_window_name_assignment_updates_parent_named_access() { + let mut vm = new_storage_test_vm("https://dynamic-frame-name.test/"); + + let initial = vm + .eval( + r#" +(() => { + const frame = document.createElement('iframe'); + frame.id = 'frame'; + frame.name = 'bar'; + (document.body || document.documentElement || document).appendChild(frame); + return [ + 'bar' in window, + window.bar === frame.contentWindow, + frame.contentWindow.name + ].join('|'); +})() +"#, + ) + .expect("initial iframe browsing-context name should evaluate"); + assert_eq!(initial, "true|true|bar"); + + vm.eval( + r#" +document.getElementById('frame').srcdoc = + "