diff --git a/crates/obscura-js/js/bootstrap.js b/crates/obscura-js/js/bootstrap.js index 46637cc..f6a8d4a 100644 --- a/crates/obscura-js/js/bootstrap.js +++ b/crates/obscura-js/js/bootstrap.js @@ -6049,6 +6049,12 @@ globalThis.DocumentType = DocumentType; globalThis.Node = Node; globalThis.Element = Element; globalThis.Document = Document; +// CSSStyleDeclaration is the type of element.style and getComputedStyle(); it is +// pre-declared non-enumerable in _preHideInternals, but unlike the other WebIDL +// interfaces it had no value assignment, leaving `window.CSSStyleDeclaration` +// undefined (so `el.style instanceof CSSStyleDeclaration` threw). Assigning here +// only fills the value; the property stays enumerable:false, matching Chrome. +globalThis.CSSStyleDeclaration = CSSStyleDeclaration; globalThis.XPathResult = globalThis.XPathResult || class XPathResult {}; Object.assign(globalThis.XPathResult, { ANY_TYPE: 0, diff --git a/crates/obscura-js/src/runtime.rs b/crates/obscura-js/src/runtime.rs index 5d1a14a..69dec4a 100644 --- a/crates/obscura-js/src/runtime.rs +++ b/crates/obscura-js/src/runtime.rs @@ -3552,6 +3552,20 @@ mod tests { assert_eq!(kb, serde_json::json!(true)); } + #[test] + fn cssstyledeclaration_is_a_usable_global_interface() { + // CSSStyleDeclaration was pre-declared non-enumerable but never assigned + // a value (the only WebIDL interface missing its globalThis.X = X line), + // so it was `undefined` while `'CSSStyleDeclaration' in window` was true, + // and `el.style instanceof CSSStyleDeclaration` threw. It must be a real + // constructor, non-enumerable like a browser, and the type of .style. + let mut rt = setup_runtime(""); + let v = rt + .evaluate("(function(){var d=Object.getOwnPropertyDescriptor(window,'CSSStyleDeclaration');return (typeof window.CSSStyleDeclaration)+'|'+(document.body.style instanceof CSSStyleDeclaration)+'|'+(d?d.enumerable:'missing');})()") + .unwrap(); + assert_eq!(v, serde_json::json!("function|true|false")); + } + #[test] fn test_create_event_unknown_type_returns_event() { let mut rt = setup_runtime("");