dom: settle async inline style updates
This commit is contained in:
1 parent
9ec43134ae
commit
9ffc071ce0
2 files changed
+61
-4
No files matched your search
Vendored
+2
-1
@@ -693,7 +693,8 @@ const _styleProxy = (decl) => new Proxy(decl, {
|
||||
if (typeof p === "symbol") { t[p] = v; return true; }
|
||||
if (p === "_loaded") { t._loaded = v; return true; }
|
||||
if (p === "cssText") { t.cssText = v; return true; }
|
||||
if (/^\d+$/.test(p) || p in Object.getPrototypeOf(t)) return true;
|
||||
if (p in t) { Reflect.set(t, p, v); return true; }
|
||||
if (/^\d+$/.test(p)) return true;
|
||||
t.setProperty(p, v);
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -881,10 +881,18 @@ impl ObscuraJsRuntime {
|
||||
}
|
||||
|
||||
pub async fn run_event_loop(&mut self) -> Result<(), String> {
|
||||
self.runtime
|
||||
// A browser performs a microtask checkpoint at the end of each task.
|
||||
// deno_core's event loop may return immediately when no async op is
|
||||
// pending, leaving an already-resolved Promise continuation stranded
|
||||
// (document.fonts.load(...).then(...), framework post-render hooks,
|
||||
// and hydration follow-ups all rely on this boundary).
|
||||
self.runtime.v8_isolate().perform_microtask_checkpoint();
|
||||
let result = self.runtime
|
||||
.run_event_loop(deno_core::PollEventLoopOptions::default())
|
||||
.await
|
||||
.map_err(|e| format!("Event loop error: {}", e))
|
||||
.map_err(|e| format!("Event loop error: {}", e));
|
||||
self.runtime.v8_isolate().perform_microtask_checkpoint();
|
||||
result
|
||||
}
|
||||
|
||||
/// Whether the serialized dynamic-script queue is still fetching or
|
||||
@@ -1845,6 +1853,24 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn idle_event_loop_flushes_resolved_promise_continuations() {
|
||||
let mut rt = setup_runtime("<html><body><div id='state'>pending</div></body></html>");
|
||||
rt.execute_script(
|
||||
"font-ready",
|
||||
"document.fonts.load('normal 1px Example').then(() => {\
|
||||
document.getElementById('state').textContent = 'ready';\
|
||||
});",
|
||||
)
|
||||
.unwrap();
|
||||
rt.run_event_loop_bounded(100).await.unwrap();
|
||||
assert_eq!(
|
||||
rt.evaluate("document.getElementById('state').textContent")
|
||||
.unwrap(),
|
||||
serde_json::json!("ready")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_document_url() {
|
||||
let mut rt = setup_runtime("<html><body></body></html>");
|
||||
@@ -3021,7 +3047,8 @@ mod tests {
|
||||
datasetKeys: Object.keys(el.dataset),
|
||||
cssText: el.style.cssText,
|
||||
length: el.style.length,
|
||||
getByDash: el.style.getPropertyValue('font-size')
|
||||
getByDash: el.style.getPropertyValue('font-size'),
|
||||
reflectedAttribute: el.getAttribute('style')
|
||||
});
|
||||
})()"#,
|
||||
)
|
||||
@@ -3036,6 +3063,35 @@ mod tests {
|
||||
assert_eq!(p["cssText"], "color: red; font-size: 14px;");
|
||||
assert_eq!(p["length"], 2);
|
||||
assert_eq!(p["getByDash"], "14px");
|
||||
assert_eq!(p["reflectedAttribute"], "color: red; font-size: 14px;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn style_declaration_reflects_and_removes_parsed_attributes() {
|
||||
let mut rt = setup_runtime(
|
||||
"<html><body><div id='icon' style='font-size: 0px; color: red'></div></body></html>",
|
||||
);
|
||||
let result = rt
|
||||
.evaluate(
|
||||
r#"(() => {
|
||||
const el = document.getElementById('icon');
|
||||
const before = [el.style.fontSize, el.style.color, el.style.length];
|
||||
const removed = el.style.removeProperty('font-size');
|
||||
return JSON.stringify({
|
||||
before,
|
||||
removed,
|
||||
after: el.style.cssText,
|
||||
attribute: el.getAttribute('style')
|
||||
});
|
||||
})()"#,
|
||||
)
|
||||
.unwrap();
|
||||
let value: serde_json::Value =
|
||||
serde_json::from_str(result.as_str().unwrap()).unwrap();
|
||||
assert_eq!(value["before"], serde_json::json!(["0px", "red", 2]));
|
||||
assert_eq!(value["removed"], "0px");
|
||||
assert_eq!(value["after"], "color: red;");
|
||||
assert_eq!(value["attribute"], "color: red;");
|
||||
}
|
||||
|
||||
/// Regression for #105: `element.querySelector` and `querySelectorAll`
|
||||
|
||||
Reference in new issue
Block a user