diff options
Diffstat (limited to 'toolkit/components/alerts/test')
-rw-r--r-- | toolkit/components/alerts/test/browser.toml | 4 | ||||
-rw-r--r-- | toolkit/components/alerts/test/browser_bug1682866.js | 56 | ||||
-rw-r--r-- | toolkit/components/alerts/test/file_bug1682866.html | 9 | ||||
-rw-r--r-- | toolkit/components/alerts/test/image.gif | bin | 0 -> 60901 bytes | |||
-rw-r--r-- | toolkit/components/alerts/test/image.png | bin | 0 -> 2531 bytes | |||
-rw-r--r-- | toolkit/components/alerts/test/image_server.sjs | 92 | ||||
-rw-r--r-- | toolkit/components/alerts/test/mochitest.toml | 28 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_alerts.html | 88 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_alerts_noobserve.html | 93 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_alerts_requireinteraction.html | 164 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_image.html | 117 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_invalid_utf16.html | 160 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_multiple_alerts.html | 99 | ||||
-rw-r--r-- | toolkit/components/alerts/test/test_principal.html | 123 |
14 files changed, 1033 insertions, 0 deletions
diff --git a/toolkit/components/alerts/test/browser.toml b/toolkit/components/alerts/test/browser.toml new file mode 100644 index 0000000000..61724f2c12 --- /dev/null +++ b/toolkit/components/alerts/test/browser.toml @@ -0,0 +1,4 @@ +[DEFAULT] + +["browser_bug1682866.js"] +support-files = ["file_bug1682866.html"] diff --git a/toolkit/components/alerts/test/browser_bug1682866.js b/toolkit/components/alerts/test/browser_bug1682866.js new file mode 100644 index 0000000000..24b8b6f7b8 --- /dev/null +++ b/toolkit/components/alerts/test/browser_bug1682866.js @@ -0,0 +1,56 @@ +const baseURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +const alertURL = `${baseURL}file_bug1682866.html`; + +add_task(async function testAlertForceClosed() { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + alertURL, + true /* waitForLoad */ + ); + + // Open a second which is in the same process as tab + let secondTabIsLoaded = BrowserTestUtils.waitForNewTab( + gBrowser, + alertURL, + true, + false + ); + + let isSuspendedAfterAlert = await SpecialPowers.spawn( + tab.linkedBrowser.browsingContext, + [alertURL], + url => { + content.open(url); + var utils = SpecialPowers.getDOMWindowUtils(content); + return utils.isInputTaskManagerSuspended; + } + ); + + await secondTabIsLoaded; + + let secondTab = gBrowser.tabs[2]; + + is( + isSuspendedAfterAlert, + Services.prefs.getBoolPref("dom.input_events.canSuspendInBCG.enabled"), + "InputTaskManager should be suspended because alert is opened" + ); + + let alertClosed = BrowserTestUtils.waitForEvent( + tab.linkedBrowser, + "DOMModalDialogClosed" + ); + + BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, "about:newtab"); + + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + await alertClosed; + + gBrowser.removeTab(tab); + gBrowser.removeTab(secondTab); +}); diff --git a/toolkit/components/alerts/test/file_bug1682866.html b/toolkit/components/alerts/test/file_bug1682866.html new file mode 100644 index 0000000000..328edcbac5 --- /dev/null +++ b/toolkit/components/alerts/test/file_bug1682866.html @@ -0,0 +1,9 @@ +<html> + <body> + <script> + window.onload = function() { + alert("This is an alert"); + } + </script> + </body> +</html> diff --git a/toolkit/components/alerts/test/image.gif b/toolkit/components/alerts/test/image.gif Binary files differnew file mode 100644 index 0000000000..053b4d9261 --- /dev/null +++ b/toolkit/components/alerts/test/image.gif diff --git a/toolkit/components/alerts/test/image.png b/toolkit/components/alerts/test/image.png Binary files differnew file mode 100644 index 0000000000..430c3c5e65 --- /dev/null +++ b/toolkit/components/alerts/test/image.png diff --git a/toolkit/components/alerts/test/image_server.sjs b/toolkit/components/alerts/test/image_server.sjs new file mode 100644 index 0000000000..4caa21ce27 --- /dev/null +++ b/toolkit/components/alerts/test/image_server.sjs @@ -0,0 +1,92 @@ +const CC = Components.Constructor; + +let { setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +const LocalFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath"); + +const FileInputStream = CC( + "@mozilla.org/network/file-input-stream;1", + "nsIFileInputStream", + "init" +); + +const BinaryInputStream = CC( + "@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream" +); + +function handleRequest(request, response) { + let params = parseQueryString(request.queryString); + + response.setStatusLine(request.httpVersion, 200, "OK"); + + // Compare and increment a cookie for this request. This is used to test + // private browsing mode; the cookie should not be set if the image is + // loaded anonymously. + if (params.has("c")) { + let expectedValue = parseInt(params.get("c"), 10); + let actualValue = !request.hasHeader("Cookie") + ? 0 + : parseInt( + request.getHeader("Cookie").replace(/^counter=(\d+)/, "$1"), + 10 + ); + if (actualValue != expectedValue) { + response.setStatusLine(request.httpVersion, 400, "Wrong counter value"); + return; + } + response.setHeader("Set-Cookie", `counter=${expectedValue + 1}`, false); + } + + // Wait to send the image if a timeout is given. + let timeout = parseInt(params.get("t"), 10); + if (timeout > 0) { + response.processAsync(); + setTimeout(() => { + respond(params, request, response); + response.finish(); + }, timeout * 1000); + return; + } + + respond(params, request, response); +} + +function parseQueryString(queryString) { + return queryString.split("&").reduce((params, param) => { + let [key, value] = param.split("=", 2); + params.set(key, value); + return params; + }, new Map()); +} + +function respond(params, request, response) { + if (params.has("s")) { + let statusCode = parseInt(params.get("s"), 10); + response.setStatusLine(request.httpVersion, statusCode, "Custom status"); + return; + } + var filename = params.get("f"); + writeFile(filename, response); +} + +function writeFile(name, response) { + var file = new LocalFile(getState("__LOCATION__")).parent; + file.append(name); + + let mimeType = Cc["@mozilla.org/uriloader/external-helper-app-service;1"] + .getService(Ci.nsIMIMEService) + .getTypeFromFile(file); + + let fileStream = new FileInputStream(file, 1, 0, false); + let binaryStream = new BinaryInputStream(fileStream); + + response.setHeader("Content-Type", mimeType, false); + response.bodyOutputStream.writeFrom(binaryStream, binaryStream.available()); + + binaryStream.close(); + fileStream.close(); +} diff --git a/toolkit/components/alerts/test/mochitest.toml b/toolkit/components/alerts/test/mochitest.toml new file mode 100644 index 0000000000..bb6da55f33 --- /dev/null +++ b/toolkit/components/alerts/test/mochitest.toml @@ -0,0 +1,28 @@ +[DEFAULT] +skip-if = ["os == 'android'"] # We don't use XUL alerts on Android +support-files = [ + "image.gif", + "image.png", + "image_server.sjs", +] + +# Synchronous tests like test_alerts.html must come before +# asynchronous tests like test_alerts_noobserve.html! + +["test_alerts.html"] + +["test_alerts_noobserve.html"] + +["test_alerts_requireinteraction.html"] +skip-if = ["verify && os == 'linux'"] + +["test_image.html"] +skip-if = ["verify"] + +["test_invalid_utf16.html"] +run-if = ["os == 'win'"] # Bug 1836526 + +["test_multiple_alerts.html"] + +["test_principal.html"] +skip-if = ["verify"] # Bug 1810860 diff --git a/toolkit/components/alerts/test/test_alerts.html b/toolkit/components/alerts/test/test_alerts.html new file mode 100644 index 0000000000..9c9371fc70 --- /dev/null +++ b/toolkit/components/alerts/test/test_alerts.html @@ -0,0 +1,88 @@ +<!DOCTYPE HTML> +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<html> +<head> + <title>Test for Alerts Service</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> +<p id="display"></p> + +<br>Alerts service, with observer "synchronous" case. +<br> +<br>Did a notification appear anywhere? +<br>If so, the test will finish once the notification disappears. + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +var notifier; +var alertName = "fiorello"; + +var observer = { + alertShow: false, + observe(aSubject, aTopic, aData) { + is(aData, "foobarcookie", "Checking whether the alert cookie was passed correctly"); + if (aTopic == "alertclickcallback") { + todo(false, "Did someone click the notification while running mochitests? (Please don't.)"); + } else if (aTopic == "alertshow") { + ok(!this.alertShow, "Alert should not be shown more than once"); + this.alertShow = true; + + // Notifications are native on OS X 10.8 and later, GNOME Shell with + // libnotify (bug 1236036) and Windows >= 8. These notifications persist + // in the Notification Center, and only fire the `alertfinished` event + // when closed. For platforms where native notifications may be used, we + // need to close explicitly to avoid a hang. This also works for XUL + // notifications when running this test on OS X < 10.8, or a window + // manager like Ubuntu Unity with incomplete libnotify support. + notifier.closeAlert(alertName); + } else { + is(aTopic, "alertfinished", "Checking the topic for a finished notification"); + SimpleTest.finish(); + } + }, +}; + +function runTest() { + const Cc = SpecialPowers.Cc; + const Ci = SpecialPowers.Ci; + + if (!("@mozilla.org/alerts-service;1" in Cc)) { + todo(false, "Alerts service does not exist in this application"); + return; + } + + ok(true, "Alerts service exists in this application"); + + try { + notifier = Cc["@mozilla.org/alerts-service;1"]. + getService(Ci.nsIAlertsService); + ok(true, "Alerts service is available"); + } catch (ex) { + todo(false, + "Alerts service is not available.", ex); + return; + } + + try { + SimpleTest.waitForExplicitFinish(); + notifier.showAlertNotification(null, "Notification test", + "Surprise! I'm here to test notifications!", + false, "foobarcookie", observer, alertName); + ok(true, "showAlertNotification() succeeded. Waiting for notification..."); + } catch (ex) { + todo(false, "showAlertNotification() failed.", ex); + SimpleTest.finish(); + } +} + +runTest(); + +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/alerts/test/test_alerts_noobserve.html b/toolkit/components/alerts/test/test_alerts_noobserve.html new file mode 100644 index 0000000000..b6a7658e17 --- /dev/null +++ b/toolkit/components/alerts/test/test_alerts_noobserve.html @@ -0,0 +1,93 @@ +<!DOCTYPE HTML> +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<html> +<head> + <title>Test for Alerts Service</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> +<p id="display"></p> + +<br>Alerts service, without observer "asynchronous" case. +<br> +<br>A notification should soon appear somewhere. +<br>If there has been no crash when the notification (later) disappears, assume all is good. + +<pre id="test"> +<script class="testbody" type="text/javascript"> +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; + +const chromeScript = SpecialPowers.loadChromeScript(_ => { + /* eslint-env mozilla/chrome-script */ + const {setTimeout} = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" + ); + + function anyXULAlertsVisible() { + var windows = Services.wm.getEnumerator("alert:alert"); + return windows.hasMoreElements(); + } + + addMessageListener("anyXULAlertsVisible", anyXULAlertsVisible); + + addMessageListener("waitForAlerts", function waitForAlerts() { + if (anyXULAlertsVisible()) { + setTimeout(waitForAlerts, 1000); + } else { + sendAsyncMessage("waitedForAlerts"); + } + }); +}); + +function waitForAlertsThenFinish() { + chromeScript.addMessageListener("waitedForAlerts", function waitedForAlerts() { + chromeScript.removeMessageListener("waitedForAlerts", waitedForAlerts); + ok(true, "Alert disappeared."); + SimpleTest.finish(); + }); + chromeScript.sendAsyncMessage("waitForAlerts"); +} + +async function runTest() { + var alertsVisible = await chromeScript.sendQuery("anyXULAlertsVisible"); + ok(!alertsVisible, "Alerts should not be present at the start of the test."); + + if (!("@mozilla.org/alerts-service;1" in Cc)) { + todo(false, "Alerts service does not exist in this application"); + } else { + ok(true, "Alerts service exists in this application"); + + var notifier; + try { + notifier = Cc["@mozilla.org/alerts-service;1"]. + getService(Ci.nsIAlertsService); + ok(true, "Alerts service is available"); + } catch (ex) { + todo(false, "Alerts service is not available.", ex); + } + + if (notifier) { + try { + notifier.showAlertNotification(null, "Notification test", + "This notification has no observer"); + ok(true, "showAlertNotification() succeeded"); + } catch (ex) { + todo(false, "showAlertNotification() failed.", ex); + } + } + } +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); + +runTest(); +setTimeout(waitForAlertsThenFinish, 1000); +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/alerts/test/test_alerts_requireinteraction.html b/toolkit/components/alerts/test/test_alerts_requireinteraction.html new file mode 100644 index 0000000000..ca8fa1c9e3 --- /dev/null +++ b/toolkit/components/alerts/test/test_alerts_requireinteraction.html @@ -0,0 +1,164 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for alerts with requireInteraction</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<pre id="test"> +<script class="testbody" type="text/javascript"> +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; + +const chromeScript = SpecialPowers.loadChromeScript(_ => { + /* eslint-env mozilla/chrome-script */ + const {clearTimeout, setTimeout} = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" + ); + + addMessageListener("waitForXULAlert", function() { + var timer = setTimeout(function() { + Services.ww.unregisterNotification(windowObserver); + sendAsyncMessage("waitForXULAlert", false); + }, 2000); + + var windowObserver = function(win, aTopic, aData) { + if (aTopic != "domwindowopened") { + return; + } + + win.addEventListener("load", function() { + let windowType = win.document.documentElement.getAttribute("windowtype"); + if (windowType == "alert:alert") { + clearTimeout(timer); + Services.ww.unregisterNotification(windowObserver); + + sendAsyncMessage("waitForXULAlert", true); + } + }, {once: true}); + }; + + Services.ww.registerNotification(windowObserver); + }); +}); + +var cookie = 0; +function promiseCreateXULAlert(alertService, listener, name) { + return new Promise(resolve => { + chromeScript.addMessageListener("waitForXULAlert", function waitedForAlert(result) { + chromeScript.removeMessageListener("waitForXULAlert", waitedForAlert); + resolve(result); + }); + + chromeScript.sendAsyncMessage("waitForXULAlert"); + alertService.showAlertNotification(null, "title", "body", + true, cookie++, listener, name, null, null, null, + null, false, true); + }); +} + +add_task(async function test_require_interaction() { + if (!("@mozilla.org/alerts-service;1" in Cc)) { + todo(false, "Alerts service does not exist in this application."); + return; + } + + ok(true, "Alerts service exists in this application."); + + var alertService; + try { + alertService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); + ok(true, "Alerts service is available."); + } catch (ex) { + todo(false, "Alerts service is not available."); + return; + } + + await SpecialPowers.pushPrefEnv({"set": [ + [ "dom.webnotifications.requireinteraction.enabled", true ], + [ "dom.webnotifications.requireinteraction.count", 2 ], + ]}); + + var expectedSequence = [ + "first show", + "second show", + "second finished", + "second replacement show", + "third finished", + "first finished", + "third replacement show", + "second replacement finished", + "third replacement finished", + ]; + + var actualSequence = []; + + function createAlertListener(name, showCallback, finishCallback) { + return (subject, topic, data) => { + if (topic == "alertshow") { + actualSequence.push(name + " show"); + if (showCallback) { + showCallback(); + } + } else if (topic == "alertfinished") { + actualSequence.push(name + " finished"); + if (finishCallback) { + finishCallback(); + } + } + }; + } + + var xulAlertCreated = await promiseCreateXULAlert(alertService, + createAlertListener("first"), "first"); + if (!xulAlertCreated) { + ok(true, "Platform does not use XUL alerts."); + alertService.closeAlert("first"); + return; + } + + xulAlertCreated = await promiseCreateXULAlert(alertService, + createAlertListener("second"), "second"); + ok(xulAlertCreated, "Create XUL alert"); + + // Replace second alert + xulAlertCreated = await promiseCreateXULAlert(alertService, + createAlertListener("second replacement"), "second"); + ok(xulAlertCreated, "Create XUL alert"); + + var testFinishResolve; + var testFinishPromise = new Promise((resolve) => { testFinishResolve = resolve; }); + + xulAlertCreated = await promiseCreateXULAlert(alertService, + createAlertListener("third"), "third"); + ok(!xulAlertCreated, "XUL alert should not be visible"); + + // Replace the not-yet-visible third alert. + xulAlertCreated = await promiseCreateXULAlert(alertService, + createAlertListener("third replacement", + function showCallback() { + alertService.closeAlert("second"); + alertService.closeAlert("third"); + }, + function finishCallback() { + // Check actual sequence of alert events compared to expected sequence. + for (var i = 0; i < actualSequence.length; i++) { + is(actualSequence[i], expectedSequence[i], + "Alert callback at index " + i + " should be in expected order."); + } + + testFinishResolve(); + }), "third"); + + ok(!xulAlertCreated, "XUL alert should not be visible"); + + alertService.closeAlert("first"); + + await testFinishPromise; +}); + +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/alerts/test/test_image.html b/toolkit/components/alerts/test/test_image.html new file mode 100644 index 0000000000..3928529c13 --- /dev/null +++ b/toolkit/components/alerts/test/test_image.html @@ -0,0 +1,117 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 1233086</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> +<p id="display"></p> + +<pre id="test"> +<script class="testbody" type="text/javascript"> + +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; +const Services = SpecialPowers.Services; + +const imageServerURL = "http://mochi.test:8888/tests/toolkit/components/alerts/test/image_server.sjs"; + +function makeAlert(...params) { + var alert = Cc["@mozilla.org/alert-notification;1"] + .createInstance(Ci.nsIAlertNotification); + alert.init(...params); + return alert; +} + +function promiseImage(alert, timeout = 0, userData = null) { + return new Promise(resolve => { + var isDone = false; + function done(value) { + ok(!isDone, "Should call the image listener once"); + isDone = true; + resolve(value); + } + alert.loadImage(timeout, SpecialPowers.wrapCallbackObject({ + onImageReady(aUserData, aRequest) { + done([true, aRequest, aUserData]); + }, + onImageMissing(aUserData) { + done([false, aUserData]); + }, + }), SpecialPowers.wrap(userData)); + }); +} + +add_task(async function testContext() { + var inUserData = Cc["@mozilla.org/supports-PRInt64;1"] + .createInstance(Ci.nsISupportsPRInt64); + inUserData.data = 123; + + var alert = makeAlert(null, imageServerURL + "?f=image.png"); + var [ready, , userData] = await promiseImage(alert, 0, inUserData); + ok(ready, "Should load requested image"); + is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123, + "Should pass user data for loaded image"); + + alert = makeAlert(null, imageServerURL + "?s=404"); + [ready, userData] = await promiseImage(alert, 0, inUserData); + ok(!ready, "Should not load missing image"); + is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123, + "Should pass user data for missing image"); +}); + +add_task(async function testTimeout() { + var alert = makeAlert(null, imageServerURL + "?f=image.png&t=3"); + var [ready] = await promiseImage(alert, 1000); + ok(!ready, "Should cancel request if timeout fires"); + + [ready] = await promiseImage(alert, 45000); + ok(ready, "Should load image if request finishes before timeout"); +}); + +add_task(async function testAnimatedGIF() { + var alert = makeAlert(null, imageServerURL + "?f=image.gif"); + var [ready, request] = await promiseImage(alert); + ok(ready, "Should load first animated GIF frame"); + is(request.mimeType, "image/gif", "Should report correct GIF MIME type"); + is(request.image.width, 256, "GIF width should be 256px"); + is(request.image.height, 256, "GIF height should be 256px"); +}); + +add_task(async function testCancel() { + var alert = makeAlert(null, imageServerURL + "?f=image.gif&t=180"); + await new Promise((resolve, reject) => { + var request = alert.loadImage(0, SpecialPowers.wrapCallbackObject({ + onImageReady() { + reject(new Error("Should not load cancelled request")); + }, + onImageMissing() { + resolve(); + }, + }), null); + request.cancel(SpecialPowers.Cr.NS_BINDING_ABORTED); + }); +}); + +add_task(async function testMixedContent() { + // Loading principal is HTTPS; image URL is HTTP. + var origin = "https://mochi.test:8888"; + var principal = Services.scriptSecurityManager + .createContentPrincipalFromOrigin(origin); + + var alert = makeAlert(null, imageServerURL + "?f=image.png", + null, null, false, null, null, null, + null, principal); + var [ready, request] = await promiseImage(alert); + ok(ready, "Should load cross-protocol image"); + is(request.mimeType, "image/png", "Should report correct MIME type"); + is(request.image.width, 32, "Width should be 32px"); + is(request.image.height, 32, "Height should be 32px"); +}); + +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/alerts/test/test_invalid_utf16.html b/toolkit/components/alerts/test/test_invalid_utf16.html new file mode 100644 index 0000000000..a4f862238c --- /dev/null +++ b/toolkit/components/alerts/test/test_invalid_utf16.html @@ -0,0 +1,160 @@ +<!DOCTYPE HTML> +<html> + +<head> + <meta charset="utf-8"> + <title>Test for stability when providing invalid UTF-16 strings</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css" /> + <script> + const Cc = SpecialPowers.Cc; + const Ci = SpecialPowers.Ci; + let notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);; + let notification = Cc["@mozilla.org/alert-notification;1"] + + function buildObserver(alertName) { + let resolve; + let reject; + let promise = new Promise((res, rej) => {resolve = res; reject = rej}); + + let success = false; + function observe(aSubject, aTopic, aData) { + if (aTopic == "alertshow") { + success = true; + notifier.closeAlert(alertName); + } else if (aTopic == "alertfinished") { + ok(true, "alertfinished"); + if (success) { + resolve(); + } else { + reject(); + } + } + } + + return { promise, observe }; + }; + + function buildAlert(options) { + let alert = notification.createInstance( + Ci.nsIAlertNotification + ); + alert.init( + options.name, + options.imageURL, + options.title, + options.text, + options.textClickable, + options.cookie, + options.dir, + options.lang, + options.data, + options.principal, + options.inPrivateBrowsing, + options.requireInteraction, + options.silent, + options.vibrate || [] + ); + if (options.actions) { + alert.actions = options.actions; + } + return alert; + } + + async function runTest(options) { + let alert = buildAlert(options) + const { promise, observe } = buildObserver(options.name); + notifier.showAlert(alert, observe); + await promise; + } + + let invalidUtf16 = String.fromCharCode(0xdfff); + + add_task(async function test_invalid_utf16_name() { + let name = invalidUtf16; + let alert = buildAlert({name}); + + // Extract the alert name to ensure it was not forced to be valid UTF-16. + ok(name == alert.name, "Notification name was not forced to be valid UTF-16"); + + const { promise, observe } = buildObserver(name); + notifier.showAlert(alert, observe); + await promise; + + ok(true, "Notification shown with invalid UTF-16 name"); + }); + + add_task(async function test_invalid_utf16_title() { + let name = "invalid title"; + let title = invalidUtf16; + await runTest({name, title}); + + ok(true, "Notification shown with invalid UTF-16 title"); + }); + + add_task(async function test_invalid_utf16_body() { + let name = "invalid body"; + let text = invalidUtf16; + await runTest({name, text}); + + ok(true, "Notification shown with invalid UTF-16 body"); + }); + + add_task(async function test_invalid_utf16_image_url() { + let name = "invalid image URL"; + let imageURL = invalidUtf16; + await runTest({name, imageURL}); + + ok(true, "Notification shown with invalid UTF-16 image url"); + }); + + add_task(async function test_invalid_utf16_data() { + let name = "invalid data"; + let data = invalidUtf16; + await runTest({name, data}); + + ok(true, "Notification shown with invalid UTF-16 data"); + }); + + // At time of writing, actions are a Windows only, privileged feature. + add_task(async function test_invalid_utf16_action_body() { + let name = "invalid action body"; + let actions = [ + { action: invalidUtf16 }, + ]; + await runTest({name, actions}); + + ok(true, "Notification shown with invalid UTF-16 action body"); + }); + + // At time of writing, actions are a Windows only, privileged feature. + add_task(async function test_invalid_utf16_action_title() { + let name = "invalid action title"; + let actions = [ + {title:invalidUtf16}, + ]; + await runTest({name, actions}); + + ok(true, "Notification shown with invalid UTF-16 action title"); + }); + + // At time of writing, actions are a Windows only, privileged feature. + add_task(async function test_invalid_utf16_action_image_url() { + let name = "invalid action image URL"; + let actions = [ + { iconURL: invalidUtf16 }, + ]; + await runTest({name, actions}); + + ok(true, "Notification shown with invalid UTF-16 action image URL"); + }); + </script> +</head> + +<body> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> + +</html> diff --git a/toolkit/components/alerts/test/test_multiple_alerts.html b/toolkit/components/alerts/test/test_multiple_alerts.html new file mode 100644 index 0000000000..95843b2e89 --- /dev/null +++ b/toolkit/components/alerts/test/test_multiple_alerts.html @@ -0,0 +1,99 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for multiple alerts</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<pre id="test"> +<script class="testbody" type="text/javascript"> +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; + +const chromeScript = SpecialPowers.loadChromeScript(_ => { + /* eslint-env mozilla/chrome-script */ + const {clearTimeout, setTimeout} = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" + ); + + const alertService = Cc["@mozilla.org/alerts-service;1"] + .getService(Ci.nsIAlertsService); + + addMessageListener("waitForPosition", function() { + var timer = setTimeout(function() { + Services.ww.unregisterNotification(windowObserver); + sendAsyncMessage("waitedForPosition", null); + }, 2000); + + var windowObserver = function(win, aTopic, aData) { + if (aTopic != "domwindowopened") { + return; + } + + // Alerts are implemented using XUL. + clearTimeout(timer); + + Services.ww.unregisterNotification(windowObserver); + + win.addEventListener("pageshow", function() { + var x = win.screenX; + var y = win.screenY; + + win.addEventListener("pagehide", function() { + sendAsyncMessage("waitedForPosition", { x, y }); + }, {once: true}); + + alertService.closeAlert(); + }, {once: true}); + }; + + Services.ww.registerNotification(windowObserver); + }); +}); + +function promiseAlertPosition(alertService) { + return new Promise(resolve => { + chromeScript.addMessageListener("waitedForPosition", function waitedForPosition(result) { + chromeScript.removeMessageListener("waitedForPosition", waitedForPosition); + resolve(result); + }); + chromeScript.sendAsyncMessage("waitForPosition"); + + alertService.showAlertNotification(null, "title", "body"); + ok(true, "Alert shown."); + }); +} + +add_task(async function test_multiple_alerts() { + if (!("@mozilla.org/alerts-service;1" in Cc)) { + todo(false, "Alerts service does not exist in this application."); + return; + } + + ok(true, "Alerts service exists in this application."); + + var alertService; + try { + alertService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); + ok(true, "Alerts service is available."); + } catch (ex) { + todo(false, "Alerts service is not available."); + return; + } + + var firstAlertPosition = await promiseAlertPosition(alertService); + if (!firstAlertPosition) { + ok(true, "Platform does not use XUL alerts."); + return; + } + + var secondAlertPosition = await promiseAlertPosition(alertService); + is(secondAlertPosition.x, firstAlertPosition.x, "Second alert should be opened in the same position."); + is(secondAlertPosition.y, firstAlertPosition.y, "Second alert should be opened in the same position."); +}); + +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/alerts/test/test_principal.html b/toolkit/components/alerts/test/test_principal.html new file mode 100644 index 0000000000..5464d92977 --- /dev/null +++ b/toolkit/components/alerts/test/test_principal.html @@ -0,0 +1,123 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 1202933</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> +<p id="display"></p> + +<pre id="test"> +<script class="testbody" type="text/javascript"> +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; +const Services = SpecialPowers.Services; + +const notifier = Cc["@mozilla.org/alerts-service;1"] + .getService(Ci.nsIAlertsService); + +const chromeScript = SpecialPowers.loadChromeScript(_ => { + /* eslint-env mozilla/chrome-script */ + addMessageListener("anyXULAlertsVisible", function() { + var windows = Services.wm.getEnumerator("alert:alert"); + return windows.hasMoreElements(); + }); + + addMessageListener("getAlertSource", function() { + var alertWindows = Services.wm.getEnumerator("alert:alert"); + if (!alertWindows) { + return null; + } + var alertWindow = alertWindows.getNext(); + return alertWindow.document.getElementById("alertSourceLabel").getAttribute("value"); + }); +}); + +function notify(alertName, principal) { + return new Promise((resolve, reject) => { + var source; + async function observe(subject, topic, data) { + if (topic == "alertclickcallback") { + reject(new Error("Alerts should not be clicked during test")); + } else if (topic == "alertshow") { + source = await chromeScript.sendQuery("getAlertSource"); + notifier.closeAlert(alertName); + } else { + is(topic, "alertfinished", "Should hide alert"); + resolve(source); + } + } + notifier.showAlertNotification(null, "Notification test", + "Surprise! I'm here to test notifications!", + false, alertName, observe, alertName, + null, null, null, principal); + if (SpecialPowers.Services.appinfo.OS == "Darwin") { + notifier.closeAlert(alertName); + } + }); +} + +async function testNoPrincipal() { + var source = await notify("noPrincipal", null); + ok(!source, "Should omit source without principal"); +} + +async function testSystemPrincipal() { + var principal = Services.scriptSecurityManager.getSystemPrincipal(); + var source = await notify("systemPrincipal", principal); + ok(!source, "Should omit source for system principal"); +} + +async function testNullPrincipal() { + var principal = Services.scriptSecurityManager.createNullPrincipal({}); + var source = await notify("nullPrincipal", principal); + ok(!source, "Should omit source for null principal"); +} + +async function testNodePrincipal() { + var principal = SpecialPowers.wrap(document).nodePrincipal; + var source = await notify("nodePrincipal", principal); + + var stringBundle = Services.strings.createBundle( + "chrome://alerts/locale/alert.properties" + ); + var localizedSource = stringBundle.formatStringFromName( + "source.label", [principal.hostPort]); + is(source, localizedSource, "Should include source for node principal"); +} + +function runTest() { + if (!("@mozilla.org/alerts-service;1" in Cc)) { + todo(false, "Alerts service does not exist in this application"); + return; + } + + ok(true, "Alerts service exists in this application"); + + add_setup(async () => { + // This test verifies behavior specific to XUL alerts. + await SpecialPowers.pushPrefEnv({ + set: [["alerts.useSystemBackend", false]], + }); + }); + + // sendSyncMessage returns an array of arrays. See the comments in + // test_alerts_noobserve.html and test_SpecialPowersLoadChromeScript.html. + add_task(async () => { + var alertsVisible = await chromeScript.sendQuery("anyXULAlertsVisible"); + ok(!alertsVisible, "Alerts should not be present at the start of the test."); + }); + + add_task(testNoPrincipal); + add_task(testSystemPrincipal); + add_task(testNullPrincipal); + add_task(testNodePrincipal); +} + +runTest(); +</script> +</pre> +</body> +</html> |