diff --git a/moli-benchmark/wpt-cross-current/failed-cases.txt b/moli-benchmark/wpt-cross-current/failed-cases.txt index 350c55627f..61cbcd52d7 100644 --- a/moli-benchmark/wpt-cross-current/failed-cases.txt +++ b/moli-benchmark/wpt-cross-current/failed-cases.txt @@ -2714,9 +2714,6 @@ html/browsers/browsing-the-web/navigating-across-documents/014.html html/browsers/browsing-the-web/navigating-across-documents/abort-document-load.html html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-204-fragment.html html/browsers/browsing-the-web/navigating-across-documents/plugin-document.historical.html -html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/iframe-src-during-load.html -html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/iframe-src-during-pageshow.html -html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/iframe-src.html html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-traversal.html html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-stop.html html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal.html diff --git a/moli-benchmark/wpt-cross-current/passed-cases.txt b/moli-benchmark/wpt-cross-current/passed-cases.txt index d856c0bcd5..3b105623fb 100644 --- a/moli-benchmark/wpt-cross-current/passed-cases.txt +++ b/moli-benchmark/wpt-cross-current/passed-cases.txt @@ -5716,6 +5716,9 @@ html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/f html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/history-pushstate-during-load.html html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/history-pushstate-during-pageshow.html html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/history-pushstate.html +html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/iframe-src-during-load.html +html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/iframe-src-during-pageshow.html +html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/iframe-src.html html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-assign-during-load.html html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-assign-during-pageshow.html html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-assign.html diff --git a/moli-core/tests/history_child.rs b/moli-core/tests/history_child.rs index 0e9efb61d7..4e791b75d2 100644 --- a/moli-core/tests/history_child.rs +++ b/moli-core/tests/history_child.rs @@ -928,7 +928,7 @@ async fn child_browsing_context_attribute_navigation_preserves_local_history() - page.serialize_html_async() .await .unwrap() - .contains("data-child-history-length=\"3\""), + .contains("data-child-history-length=\"2\""), "{}", page.serialize_html_async().await.unwrap() ); @@ -938,7 +938,7 @@ async fn child_browsing_context_attribute_navigation_preserves_local_history() - .unwrap() .contains(&format!( "data-child-location-after-back=\"{}\"", - server.url("/compat/window-child-browsing-context-target-name-b") + server.url("/compat/window-child-browsing-context-target-name-a") )), "{}", page.serialize_html_async().await.unwrap() @@ -949,7 +949,7 @@ async fn child_browsing_context_attribute_navigation_preserves_local_history() - .unwrap() .contains(&format!( "data-child-document-location-after-back=\"{}\"", - server.url("/compat/window-child-browsing-context-target-name-b") + server.url("/compat/window-child-browsing-context-target-name-a") )), "{}", page.serialize_html_async().await.unwrap() @@ -960,7 +960,7 @@ async fn child_browsing_context_attribute_navigation_preserves_local_history() - .unwrap() .contains(&format!( "data-child-current-entry-after-back=\"{}\"", - server.url("/compat/window-child-browsing-context-target-name-b") + server.url("/compat/window-child-browsing-context-target-name-a") )), "{}", page.serialize_html_async().await.unwrap() @@ -3987,7 +3987,7 @@ async fn child_browsing_context_fragment_navigation_persists_through_attribute_n page.serialize_html_async() .await .unwrap() - .contains("data-child-history-length=\"3\""), + .contains("data-child-history-length=\"2\""), "{}", page.serialize_html_async().await.unwrap() ); diff --git a/moli-core/tests/history_iframe.rs b/moli-core/tests/history_iframe.rs new file mode 100644 index 0000000000..9d916b949d --- /dev/null +++ b/moli-core/tests/history_iframe.rs @@ -0,0 +1,109 @@ +use anyhow::Result; +use moli_core::runtime::{Browser, BrowserConfig}; +use moli_test_support::FixtureServer; +use serde_json::{Value, json}; +use tokio::time::Duration; +use url::Url; + +async fn iframe_attribute_history(phase: &str, api: &str) -> Result { + let child = r#""#; + let child = serde_json::to_string(child)?.replace("", "<\\/script>"); + let markup = r#""# + .replace("__PHASE__", &serde_json::to_string(phase)?) + .replace("__API__", &serde_json::to_string(api)?) + .replace("__CHILD__", &child); + let server = FixtureServer::spawn().await?; + let browser = Browser::new(BrowserConfig::default())?; + let mut url = Url::parse(&server.url("/compat/child-dynamic-markup-document"))?; + url.query_pairs_mut().append_pair("markup", &markup); + let result = tokio::time::timeout(Duration::from_secs(10), async { + let mut page = browser.fetch(url.as_str()).await?; + page.evaluate_runtime_expression_with_await_async( + "finished.then(value => JSON.stringify(value))", + true, + ) + .await + }) + .await??; + let result = serde_json::from_str(result["value"].as_str().unwrap())?; + server.shutdown().await; + Ok(result) +} + +#[tokio::test(flavor = "multi_thread")] +async fn iframe_src_changes_replace_history_until_child_load_finishes() -> Result<()> { + for api in ["property", "setAttribute"] { + for phase in [ + "parser", + "DOMContentLoaded", + "load", + "pageshow", + "owner-load", + ] { + let result = iframe_attribute_history(phase, api).await?; + let readiness = match phase { + "parser" => "loading", + "DOMContentLoaded" => "interactive", + _ => "complete", + }; + assert_eq!( + result, + json!({"delta": 0, "readiness": readiness, "entries": ["destination"], + "index": 0, "activation": "replace"}), + "{phase}/{api}" + ); + } + } + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn iframe_src_changes_push_history_after_load_even_when_document_is_reopened() -> Result<()> { + for api in ["property", "setAttribute"] { + for phase in ["after-load", "reopen"] { + let result = iframe_attribute_history(phase, api).await?; + assert_eq!( + result, + json!({"delta": 1, "readiness": if phase == "reopen" { "loading" } else { "complete" }, + "entries": ["source", "destination"], "index": 1, "activation": "push"}), + "{phase}/{api}" + ); + } + } + Ok(()) +} diff --git a/moli-renderer-v8/src/native_bridge/element/url_attributes/iframe.rs b/moli-renderer-v8/src/native_bridge/element/url_attributes/iframe.rs index cbf0a95a91..516fde238f 100644 --- a/moli-renderer-v8/src/native_bridge/element/url_attributes/iframe.rs +++ b/moli-renderer-v8/src/native_bridge/element/url_attributes/iframe.rs @@ -38,8 +38,15 @@ pub(in crate::native_bridge) fn update_iframe_snapshot_navigation( handle, previous_seed_snapshot, ); - let replace_current = - runtime.child_browsing_context_is_on_initial_about_blank_entry(handle); + // Attribute navigation replaces an incompletely loaded Document, + // including inside its Window load/pageshow callbacks. readyState + // alone cannot distinguish those callbacks from a completed load. + let replace_current = runtime + .child_browsing_context_is_on_initial_about_blank_entry(handle) + || runtime + .child_browsing_context_document_handle(handle) + .and_then(|document| runtime.document_is_completely_loaded(document)) + == Some(false); if runtime.queue_child_browsing_context_navigation_from_existing_seed( handle, &navigation_target,