Bug 1948752 - Part 1: Throw TypeError when failing to create notification r=asuth

Currently we expose nsresult there.

Differential Revision: https://phabricator.services.mozilla.com/D248924
This commit is contained in:
Kagami Sascha Rosylight
2025-05-13 11:20:34 +00:00
committed by krosylight@mozilla.com
parent 8f81cf5c44
commit a4ab12c86b
5 changed files with 59 additions and 7 deletions

View File

@@ -183,9 +183,14 @@ nsresult NotificationParent::HandleAlertTopic(AlertTopic aTopic) {
// alertshow happens first before alertfinished, and it should have // alertshow happens first before alertfinished, and it should have
// nullified mResolver. If not it means it failed to show and is bailing // nullified mResolver. If not it means it failed to show and is bailing
// out. // out.
// XXX: Apparently XUL manual do not disturb mode does this without firing // NOTE(krosylight): The spec does not define what to do when a
// alertshow at all. // permission-granted notification fails to open, we throw TypeError here
mResolver.take().value()(CopyableErrorResult(NS_ERROR_FAILURE)); // as that's the error for when permission is denied.
CopyableErrorResult rv;
rv.ThrowTypeError(
"Failed to show notification, potentially because the browser did "
"not have the corresponding OS-level permission."_ns);
mResolver.take().value()(rv);
} }
// Unpersisted already and being unregistered already by nsIAlertsService // Unpersisted already and being unregistered already by nsIAlertsService

View File

@@ -29,6 +29,11 @@ function mockServicesChromeScript() {
// fake async alert show event // fake async alert show event
if (listener) { if (listener) {
setTimeout(() => { setTimeout(() => {
if (this.mockFailure) {
listener.observe(null, "alertfinished", alert.cookie);
return;
}
listener.observe(null, "alertshow", alert.cookie); listener.observe(null, "alertshow", alert.cookie);
if (this.autoClick) { if (this.autoClick) {
let subject; let subject;
@@ -142,6 +147,10 @@ function mockServicesChromeScript() {
mockAlertsService.autoClick = action || true; mockAlertsService.autoClick = action || true;
}); });
addMessageListener("mock-alert-service:mock-failure", action => {
mockAlertsService.mockFailure = action || true;
});
addMessageListener("mock-alert-service:get-notification-ids", () => addMessageListener("mock-alert-service:get-notification-ids", () =>
Object.keys(activeNotifications) Object.keys(activeNotifications)
); );
@@ -206,6 +215,12 @@ const MockAlertsService = {
action action
); );
}, },
async mockFailure(action) {
await this._chromeScript.sendQuery(
"mock-alert-service:mock-failure",
action
);
},
async getNotificationIds() { async getNotificationIds() {
return await this._chromeScript.sendQuery( return await this._chromeScript.sendQuery(
"mock-alert-service:get-notification-ids" "mock-alert-service:get-notification-ids"

View File

@@ -101,6 +101,7 @@ async function setupServiceWorker(src, scope) {
SimpleTest.registerCleanupFunction(async () => { SimpleTest.registerCleanupFunction(async () => {
await registration.unregister(); await registration.unregister();
}); });
return registration;
} }
async function testFrame(src, args) { async function testFrame(src, args) {

View File

@@ -11,7 +11,14 @@ prefs = [
["test_notification_basics.html"] ["test_notification_basics.html"]
skip-if = [ skip-if = [
"xorigin", # Bug 1792790 "xorigin", # Bug 1792790
"os == 'android'", # Bug 1816427, Notification.onshow/close are broken on Android "os == 'android'", # Bug 1948752, Notification.onshow/close are broken on Android
]
["test_notification_browser_failure.html"]
support-files = ["notification_empty_sw.js"]
skip-if = [
"xorigin", # Bug 1792790
"os == 'android'", # Bug 1948752, Notification.onshow/close are broken on Android
] ]
["test_notification_crossorigin_iframe.html"] ["test_notification_crossorigin_iframe.html"]
@@ -93,13 +100,13 @@ support-files = ["create_notification.html"]
["test_notification_worker.html"] ["test_notification_worker.html"]
skip-if = [ skip-if = [
"os == 'android'", # Bug 1816427, Notification.onshow/close are broken on Android "os == 'android'", # Bug 1948752, Notification.onshow/close are broken on Android
] ]
support-files = ["notification_worker.js"] support-files = ["notification_worker.js"]
["test_notification_worker_child.html"] ["test_notification_worker_child.html"]
skip-if = [ skip-if = [
"os == 'android'", # Bug 1816427, Notification.onshow/close are broken on Android "os == 'android'", # Bug 1948752, Notification.onshow/close are broken on Android
] ]
support-files = [ support-files = [
"notification_worker_child-child.js", "notification_worker_child-child.js",
@@ -108,7 +115,7 @@ support-files = [
["test_notification_worker_click.html"] ["test_notification_worker_click.html"]
skip-if = [ skip-if = [
"os == 'android'", # Bug 1816427, Notification.onshow/close are broken on Android "os == 'android'", # Bug 1948752, Notification.onshow/close are broken on Android
] ]
["test_notification_worker_permission.html"] ["test_notification_worker_permission.html"]

View File

@@ -0,0 +1,24 @@
<!DOCTYPE html>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/dom/serviceworkers/test/utils.js"></script>
<script src="MockAlertsService.js"></script>
<script src="NotificationTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<script class="testbody">
add_task(async function test_notification_browser_failure() {
/** @type {ServiceWorkerRegistration} */
const registration = await setupServiceWorker("notification_empty_sw.js", ".")
await MockAlertsService.mockFailure();
try {
await registration.showNotification("This must not succeed");
ok(false, "showNotification after mockFailure unexpectedly succeeded");
} catch (err) {
is(err.constructor, TypeError, "It should throw TypeError");
ok(
err.message.includes("Failed to show notification"),
`Failing with the proper error message, got: ${err.message}`
);
}
});
</script>