mirror of
https://github.com/lexmount/moli.git
synced 2026-10-07 08:01:00 +00:00
Keep blocked writes with the input position saved by each parser script. Share the context between main and child parsers so external-script suspension preserves nested caller tails and consecutive write order. Add four integration regressions across main/child and navigation/script-created parsers. Validated with fmt, strict workspace Clippy, 19474 passing nextest tests, 18 Chromium comparison checks, and 50 WPT pages without new failures.
103 lines
3.5 KiB
Rust
103 lines
3.5 KiB
Rust
use super::*;
|
|
|
|
const NESTED_WRITE: &str =
|
|
include_str!("../fixtures/runtime/document_write_nested_external_input.html");
|
|
|
|
fn markup_url(server: &FixtureServer, markup: &str) -> String {
|
|
let mut url = url::Url::parse(&server.url("/compat/child-dynamic-markup-document")).unwrap();
|
|
url.query_pairs_mut().append_pair("markup", markup);
|
|
url.into()
|
|
}
|
|
|
|
async fn nested_external_writes_keep_script_insertion_points(
|
|
child: bool,
|
|
script_created: bool,
|
|
) -> Result<()> {
|
|
let server = FixtureServer::spawn().await?;
|
|
let browser = Browser::new(AppConfig::default())?;
|
|
let markup = if script_created {
|
|
if child {
|
|
"<!doctype html><body><iframe id=target></iframe>".to_owned()
|
|
} else {
|
|
"<!doctype html><body>".to_owned()
|
|
}
|
|
} else if child {
|
|
format!(
|
|
"<!doctype html><body><iframe id=target src=\"{}\"></iframe>",
|
|
markup_url(&server, NESTED_WRITE)
|
|
)
|
|
} else {
|
|
NESTED_WRITE.to_owned()
|
|
};
|
|
let mut page = tokio::time::timeout(
|
|
Duration::from_secs(10),
|
|
browser.fetch(&markup_url(&server, &markup)),
|
|
)
|
|
.await??;
|
|
let receiver = if child {
|
|
"document.getElementById('target').contentDocument"
|
|
} else {
|
|
"document"
|
|
};
|
|
if script_created {
|
|
let script = format!(
|
|
r#"new Promise(resolve => {{
|
|
const doc = {receiver};
|
|
doc.open();
|
|
doc.addEventListener('DOMContentLoaded', () => resolve(true), {{once: true}});
|
|
doc.write({});
|
|
doc.close();
|
|
}})"#,
|
|
serde_json::to_string(NESTED_WRITE)?
|
|
);
|
|
tokio::time::timeout(
|
|
Duration::from_secs(10),
|
|
page.evaluate_runtime_expression_with_await_async(&script, true),
|
|
)
|
|
.await??;
|
|
}
|
|
let result = page
|
|
.evaluate_runtime_expression_with_await_async(
|
|
&format!(
|
|
r#"(() => {{
|
|
const doc = {receiver};
|
|
return JSON.stringify({{
|
|
text: Array.from(doc.getElementById('written').childNodes)
|
|
.filter(node => node.nodeType === 3).map(node => node.data).join('').trim(),
|
|
tail: doc.getElementById('tail')?.textContent
|
|
}});
|
|
}})()"#
|
|
),
|
|
true,
|
|
)
|
|
.await?;
|
|
let result: serde_json::Value =
|
|
serde_json::from_str(result["value"].as_str().expect("nested write observation"))?;
|
|
assert_eq!(
|
|
result,
|
|
serde_json::json!({"text": "worked", "tail": "tail"})
|
|
);
|
|
server.shutdown().await;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
async fn main_parser_nested_external_writes_keep_each_script_insertion_point() -> Result<()> {
|
|
nested_external_writes_keep_script_insertion_points(false, false).await
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
async fn main_open_parser_nested_external_writes_keep_each_script_insertion_point() -> Result<()> {
|
|
nested_external_writes_keep_script_insertion_points(false, true).await
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
async fn child_parser_nested_external_writes_keep_each_script_insertion_point() -> Result<()> {
|
|
nested_external_writes_keep_script_insertion_points(true, false).await
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
async fn child_open_parser_nested_external_writes_keep_each_script_insertion_point() -> Result<()> {
|
|
nested_external_writes_keep_script_insertion_points(true, true).await
|
|
}
|