diff --git a/moli-renderer-v8/src/context_bootstrap/events/subclasses/constructor.rs b/moli-renderer-v8/src/context_bootstrap/events/subclasses/constructor.rs index 286de81d86..8f71dffb93 100644 --- a/moli-renderer-v8/src/context_bootstrap/events/subclasses/constructor.rs +++ b/moli-renderer-v8/src/context_bootstrap/events/subclasses/constructor.rs @@ -156,7 +156,11 @@ fn event_subclass_constructor_callback<'s>( } } EventSubclassKind::InterestEvent => data::initialize_interest_event(scope, event, init), - EventSubclassKind::PopStateEvent => data::initialize_pop_state_event(scope, event, init), + EventSubclassKind::PopStateEvent => { + if !data::initialize_pop_state_event(scope, event, init) { + return; + } + } EventSubclassKind::PageTransitionEvent => { data::initialize_page_transition_event(scope, event, init); } diff --git a/moli-renderer-v8/src/context_bootstrap/events/subclasses/data.rs b/moli-renderer-v8/src/context_bootstrap/events/subclasses/data.rs index e9cb6ece7d..0ae0e48728 100644 --- a/moli-renderer-v8/src/context_bootstrap/events/subclasses/data.rs +++ b/moli-renderer-v8/src/context_bootstrap/events/subclasses/data.rs @@ -197,6 +197,15 @@ struct PopStateEventInitDeclaration<'scope> { has_ua_visual_transition: bool, } +#[derive(Default, webidl::WebIdlDictionary)] +#[webidl(prefix = "PopStateEventInit")] +struct PopStateEventInitMembers<'s> { + #[webidl(name = "hasUAVisualTransition", default = false)] + has_ua_visual_transition: bool, + #[webidl(converter = "raw")] + state: Option>, +} + #[derive(WebApiObject)] #[webapi(plain, data_properties, enumerable)] struct PageTransitionEventOwnInitDeclaration { @@ -508,11 +517,24 @@ pub(in crate::context_bootstrap::events::subclasses) fn initialize_pop_state_eve scope: &mut v8::PinScope<'s, '_>, event: v8::Local<'s, v8::Object>, init: Option>, -) { - let state = init_value_property(scope, init, "state").unwrap_or_else(|| v8::null(scope).into()); - PopStateEventInitDeclaration::new(state, false) +) -> bool { + let parsed = match init { + Some(init) => { + match webidl::parse_dictionary_object::(scope, init) { + Ok(parsed) => parsed, + Err(error) => { + webidl::throw_error(scope, &error); + return false; + } + } + } + None => PopStateEventInitMembers::default(), + }; + let state = parsed.state.unwrap_or_else(|| v8::null(scope).into()); + PopStateEventInitDeclaration::new(state, parsed.has_ua_visual_transition) .initialize(scope, event) .expect("PopStateEvent init declaration should initialize"); + true } pub(in crate::context_bootstrap::events::subclasses) fn initialize_page_transition_event<'s>( diff --git a/moli-renderer-v8/src/script_vm/tests/browser_api/events_selection_storage/event_classes_ranges_and_selection.rs b/moli-renderer-v8/src/script_vm/tests/browser_api/events_selection_storage/event_classes_ranges_and_selection.rs index d5a0081433..6a2ae8cf15 100644 --- a/moli-renderer-v8/src/script_vm/tests/browser_api/events_selection_storage/event_classes_ranges_and_selection.rs +++ b/moli-renderer-v8/src/script_vm/tests/browser_api/events_selection_storage/event_classes_ranges_and_selection.rs @@ -1722,3 +1722,72 @@ fn window_error_handler_only_boolean_true_cancels() { "[[false,true],[true,false],[true,false],[true,false]]" ); } + +#[test] +fn pop_state_event_constructor_converts_visual_transition_and_state_members() { + let mut vm = new_storage_test_vm("https://pop-state-event-constructor.test/"); + + let result = vm + .eval( + r#" + (() => { + const reads = []; + const state = { marker: true }; + const initialized = new PopStateEvent("popstate", { + get state() { + reads.push("state"); + return state; + }, + get hasUAVisualTransition() { + reads.push("hasUAVisualTransition"); + return 1; + } + }); + let dispatchedState = null; + let dispatchedTransition = false; + addEventListener("popstate", event => { + dispatchedState = event.state; + dispatchedTransition = event.hasUAVisualTransition; + }, { once: true }); + dispatchEvent(initialized); + + let getterError = "none"; + try { + new PopStateEvent("popstate", { + get hasUAVisualTransition() { + throw new RangeError("sentinel"); + } + }); + } catch (error) { + getterError = `${error.name}:${error.message}`; + } + + return JSON.stringify({ + defaults: [ + new PopStateEvent("popstate").state, + new PopStateEvent("popstate").hasUAVisualTransition + ], + initialized: [ + initialized.state === state, + initialized.hasUAVisualTransition, + reads.join(",") + ], + explicitFalse: new PopStateEvent("popstate", { + hasUAVisualTransition: 0 + }).hasUAVisualTransition, + dispatched: [ + dispatchedState === state, + dispatchedTransition + ], + getterError + }); + })() + "#, + ) + .expect("PopStateEvent constructor dictionary probe should evaluate"); + + assert_eq!( + result, + r#"{"defaults":[null,false],"initialized":[true,true,"hasUAVisualTransition,state"],"explicitFalse":false,"dispatched":[true,true],"getterError":"RangeError:sentinel"}"# + ); +}