From f3fa0c8cde546ca2bd8e53b09e60337bd80aae1e Mon Sep 17 00:00:00 2001 From: ldm0 Date: Wed, 2 Sep 2026 12:26:38 +0800 Subject: [PATCH] fix(html): make redundant popover calls no-ops --- .../src/native_bridge/element/popover.rs | 27 +++----- .../misc/extracted/misc_platform.rs | 69 +++++++++---------- .../form_controls_and_legacy_elements.rs | 2 +- 3 files changed, 45 insertions(+), 53 deletions(-) diff --git a/moli-renderer-v8/src/native_bridge/element/popover.rs b/moli-renderer-v8/src/native_bridge/element/popover.rs index 0b5030c2e..4b0427fe2 100644 --- a/moli-renderer-v8/src/native_bridge/element/popover.rs +++ b/moli-renderer-v8/src/native_bridge/element/popover.rs @@ -439,15 +439,6 @@ fn close_open_auto_popovers( } } -fn throw_redundant_popover_state_error(scope: &mut v8::PinScope<'_, '_>) { - throw_dom_exception( - scope, - "InvalidStateError", - 11, - "Popover is already in the requested state.", - ); -} - fn parse_popover_invocation<'s>( scope: &mut v8::PinScope<'s, '_>, args: &v8::FunctionCallbackArguments<'s>, @@ -551,14 +542,15 @@ pub(in crate::native_bridge) fn node_show_popover_callback<'s>( return; }; let runtime = unsafe { &*runtime_ptr }; - if !ensure_popover_supported(scope, runtime, handle) - || !ensure_popover_connected(scope, runtime, handle) - { + if !ensure_popover_supported(scope, runtime, handle) { rv.set_undefined(); return; } if popover_is_open(runtime, handle) { - throw_redundant_popover_state_error(scope); + rv.set_undefined(); + return; + } + if !ensure_popover_connected(scope, runtime, handle) { rv.set_undefined(); return; } @@ -577,14 +569,15 @@ pub(in crate::native_bridge) fn node_hide_popover_callback<'s>( return; }; let runtime = unsafe { &*runtime_ptr }; - if !ensure_popover_supported(scope, runtime, handle) - || !ensure_popover_connected(scope, runtime, handle) - { + if !ensure_popover_supported(scope, runtime, handle) { rv.set_undefined(); return; } if !popover_is_open(runtime, handle) { - throw_redundant_popover_state_error(scope); + rv.set_undefined(); + return; + } + if !ensure_popover_connected(scope, runtime, handle) { rv.set_undefined(); return; } diff --git a/moli-renderer-v8/src/script_vm/tests/browser_api/misc/extracted/misc_platform.rs b/moli-renderer-v8/src/script_vm/tests/browser_api/misc/extracted/misc_platform.rs index e600e82c8..b4223f00e 100644 --- a/moli-renderer-v8/src/script_vm/tests/browser_api/misc/extracted/misc_platform.rs +++ b/moli-renderer-v8/src/script_vm/tests/browser_api/misc/extracted/misc_platform.rs @@ -367,42 +367,7 @@ fn showing_popover_throws_when_force_close_removes_opening_popover() { assert_eq!(result, "InvalidStateError:true|false|false"); } -#[test] -fn show_and_hide_popover_throw_on_redundant_state_changes() { - let mut vm = new_storage_test_vm("https://popover-redundant-state.test/"); - let result = vm - .eval( - r#" - (() => { - const html = document.appendChild(document.createElement("html")); - const body = html.appendChild(document.createElement("body")); - const popover = document.createElement("div"); - popover.popover = "auto"; - body.append(popover); - const probe = callback => { - try { - callback(); - return "ok"; - } catch (error) { - return `${error.name}:${error instanceof DOMException}`; - } - }; - const hiddenHide = probe(() => popover.hidePopover()); - popover.showPopover(); - const shownShow = probe(() => popover.showPopover()); - popover.hidePopover(); - return [hiddenHide, shownShow, popover.matches(":popover-open")].join("|"); - })() - "#, - ) - .expect("redundant popover state probe should evaluate"); - - assert_eq!( - result, - "InvalidStateError:true|InvalidStateError:true|false" - ); -} #[test] fn opening_auto_popovers_preserves_flat_tree_ancestors() { let mut vm = new_storage_test_vm("https://popover-flat-tree-ancestors.test/"); @@ -1315,3 +1280,37 @@ fn notification_permission_tracks_permission_overrides_and_request_permission() ); assert_eq!(request_permission_result(&mut insecure_vm), "denied"); } + +#[test] +fn show_and_hide_popover_are_no_ops_for_redundant_state_changes() { + let mut vm = new_storage_test_vm("https://popover-redundant-state.test/"); + + let result = vm + .eval( + r#" + (() => { + const html = document.appendChild(document.createElement("html")); + const body = html.appendChild(document.createElement("body")); + const popover = document.createElement("div"); + popover.popover = "auto"; + body.append(popover); + const probe = callback => { + try { + callback(); + return "ok"; + } catch (error) { + return `${error.name}:${error instanceof DOMException}`; + } + }; + const hiddenHide = probe(() => popover.hidePopover()); + popover.showPopover(); + const shownShow = probe(() => popover.showPopover()); + popover.hidePopover(); + return [hiddenHide, shownShow, popover.matches(":popover-open")].join("|"); + })() + "#, + ) + .expect("redundant popover state probe should evaluate"); + + assert_eq!(result, "ok|ok|false"); +} diff --git a/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/form_controls_and_legacy_elements.rs b/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/form_controls_and_legacy_elements.rs index 8b149db2e..55952404e 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/form_controls_and_legacy_elements.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/form_controls_and_legacy_elements.rs @@ -453,7 +453,7 @@ fn detached_popover_methods_use_html_element_prototype_brand_checks() { assert_eq!( result, - r#"{"shapes":"true:function:0:true:true|true:function:0:true:true|true:function:0:true:true","own":"false,false,false","elementOwn":"false,false,false","svgTypes":"undefined,undefined,undefined","direct":"ERR:NotSupportedError:9|ERR:InvalidStateError:11|ERR:InvalidStateError:11|ERR:InvalidStateError:11","prototype":"ERR:NotSupportedError:9|ERR:InvalidStateError:11|ERR:InvalidStateError:11|ERR:InvalidStateError:11"}"# + r#"{"shapes":"true:function:0:true:true|true:function:0:true:true|true:function:0:true:true","own":"false,false,false","elementOwn":"false,false,false","svgTypes":"undefined,undefined,undefined","direct":"ERR:NotSupportedError:9|ERR:InvalidStateError:11|OK:undefined|ERR:InvalidStateError:11","prototype":"ERR:NotSupportedError:9|ERR:InvalidStateError:11|OK:undefined|ERR:InvalidStateError:11"}"# ); }