fix(permissions): give PermissionStatus inherited EventTarget behavior

This commit is contained in:
lanyue-llk
2026-10-16 12:03:06 +08:00
committed by Donough Liu
parent f117afa726
commit 1a40265083
3 changed files with 50 additions and 3 deletions
@@ -608,9 +608,11 @@ fn build_permission_status_object<'s>(
name: &str,
state: &str,
) -> v8::Local<'s, v8::Object> {
PermissionStatusObjectDeclaration::new(name.to_owned(), state.to_owned())
let status = PermissionStatusObjectDeclaration::new(name.to_owned(), state.to_owned())
.bind(scope)
.expect("PermissionStatus declaration should bind")
.expect("PermissionStatus declaration should bind");
mark_simple_event_target_slot(scope, status, "__moliPermissionStatusListeners");
status
}
pub(in crate::context_bootstrap) fn permission_status_name_getter_callback<'s>(
@@ -870,3 +870,48 @@ async fn request_relative_urls_follow_live_http_iframe_base_urls() {
assert_retained_request_uses_child_document(&mut vm, child_url.as_str());
server.await.expect("iframe response server should finish");
}
#[test]
fn permission_status_supports_inherited_event_target_listeners() {
let mut vm = new_storage_test_vm("https://permission-status-events.test/");
vm.eval(
r#"
globalThis.permissionEvents = "pending";
Promise.all([
navigator.permissions.query({name: "geolocation"}),
navigator.permissions.query({name: "clipboard-write"})
]).then(([first, second]) => {
const checks = [
first instanceof PermissionStatus,
first instanceof EventTarget,
Object.getPrototypeOf(PermissionStatus.prototype) === EventTarget.prototype,
first.addEventListener === EventTarget.prototype.addEventListener
];
let calls = 0;
let otherCalls = 0;
const listener = event => {
checks.push(event.target === first, event.currentTarget === first);
calls++;
};
first.addEventListener("change", listener);
second.addEventListener("change", () => otherCalls++);
first.dispatchEvent(new Event("change"));
first.removeEventListener("change", listener);
first.dispatchEvent(new Event("change"));
let once = 0;
first.addEventListener("change", () => once++, {once: true});
first.dispatchEvent(new Event("change"));
first.dispatchEvent(new Event("change"));
checks.push(calls === 1, otherCalls === 0, once === 1);
try { new PermissionStatus(); checks.push(false); }
catch (error) { checks.push(error instanceof TypeError); }
globalThis.permissionEvents = checks.join(",");
}).catch(error => { globalThis.permissionEvents = String(error); });
"#,
)
.expect("permission listener scenario should evaluate");
let result = vm
.eval("String(globalThis.permissionEvents)")
.expect("permission queries should settle");
assert_eq!(result, "true,true,true,true,true,true,true,true,true,true");
}
+1 -1
View File
@@ -391,7 +391,7 @@ interfaces! {
PerformanceTiming;
PeriodicSyncEvent: ExtendableEvent;
PeriodicSyncManager;
PermissionStatus;
PermissionStatus: EventTarget;
Permissions;
Plugin;
PluginArray;