summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/notifications
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/notifications
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/notifications')
-rw-r--r--testing/web-platform/tests/notifications/META.yml3
-rw-r--r--testing/web-platform/tests/notifications/body-basic-manual.https.html28
-rw-r--r--testing/web-platform/tests/notifications/body-empty-manual.https.html31
-rw-r--r--testing/web-platform/tests/notifications/common.js48
-rw-r--r--testing/web-platform/tests/notifications/constructor-basic.https.html46
-rw-r--r--testing/web-platform/tests/notifications/constructor-invalid.https.html14
-rw-r--r--testing/web-platform/tests/notifications/constructor-non-secure.html13
-rw-r--r--testing/web-platform/tests/notifications/event-onclick-manual.https.html25
-rw-r--r--testing/web-platform/tests/notifications/event-onclose.https.html26
-rw-r--r--testing/web-platform/tests/notifications/event-onerror-default-manual.https.html27
-rw-r--r--testing/web-platform/tests/notifications/event-onerror-denied-manual.https.html26
-rw-r--r--testing/web-platform/tests/notifications/event-onshow.https.html24
-rw-r--r--testing/web-platform/tests/notifications/getnotifications-across-processes.https.window.js21
-rw-r--r--testing/web-platform/tests/notifications/getnotifications-sw.js56
-rw-r--r--testing/web-platform/tests/notifications/historical.any.js3
-rw-r--r--testing/web-platform/tests/notifications/icon-basic-manual.https.html28
-rw-r--r--testing/web-platform/tests/notifications/icon-empty-manual.https.html27
-rw-r--r--testing/web-platform/tests/notifications/idlharness.https.any.js31
-rw-r--r--testing/web-platform/tests/notifications/instance.https.html60
-rw-r--r--testing/web-platform/tests/notifications/lang.https.html63
-rw-r--r--testing/web-platform/tests/notifications/noop-sw.js0
-rw-r--r--testing/web-platform/tests/notifications/permission.html14
-rw-r--r--testing/web-platform/tests/notifications/permissions-non-secure.html16
-rw-r--r--testing/web-platform/tests/notifications/requestPermission-denied-manual.https.html22
-rw-r--r--testing/web-platform/tests/notifications/requestPermission-granted-manual.https.html18
-rw-r--r--testing/web-platform/tests/notifications/requireInteraction-manual.https.html51
-rw-r--r--testing/web-platform/tests/notifications/resources/custom-data.js66
-rw-r--r--testing/web-platform/tests/notifications/resources/helpers.js20
-rw-r--r--testing/web-platform/tests/notifications/resources/icon.pngbin0 -> 1540 bytes
-rw-r--r--testing/web-platform/tests/notifications/resources/shownotification-sw.js27
-rw-r--r--testing/web-platform/tests/notifications/shownotification-resolve-manual.https.html52
-rw-r--r--testing/web-platform/tests/notifications/shownotification-without-permission.https.window.js28
-rw-r--r--testing/web-platform/tests/notifications/shownotification.https.window.js87
-rw-r--r--testing/web-platform/tests/notifications/tag-different-manual.https.html37
-rw-r--r--testing/web-platform/tests/notifications/tag-same-manual.https.html37
35 files changed, 1075 insertions, 0 deletions
diff --git a/testing/web-platform/tests/notifications/META.yml b/testing/web-platform/tests/notifications/META.yml
new file mode 100644
index 0000000000..0daa86e6f4
--- /dev/null
+++ b/testing/web-platform/tests/notifications/META.yml
@@ -0,0 +1,3 @@
+spec: https://notifications.spec.whatwg.org/
+suggested_reviewers:
+ - sideshowbarker
diff --git a/testing/web-platform/tests/notifications/body-basic-manual.https.html b/testing/web-platform/tests/notifications/body-basic-manual.https.html
new file mode 100644
index 0000000000..a479917aee
--- /dev/null
+++ b/testing/web-platform/tests/notifications/body-basic-manual.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.body (basic)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<div id=passfail></div>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification = null,
+ notifications = [],
+ text = "This is the body content: Room 101"
+ createPassFail("If a notification appears containing the text"
+ + " \"" + text + "\"",
+ t, closeNotifications, notifications)
+ notification = new Notification("", {
+ body: text
+ })
+ notifications.push(notification)
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/body-empty-manual.https.html b/testing/web-platform/tests/notifications/body-empty-manual.https.html
new file mode 100644
index 0000000000..a94f08e1c5
--- /dev/null
+++ b/testing/web-platform/tests/notifications/body-empty-manual.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.body (empty string)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<div id=passfail></div>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification = null,
+ notifications = [],
+ text = "This is the title: New e-mail received"
+ createPassFail("If a notification appears containing the text "
+ + "\"" + text + "\""
+ + " but containing no body text other than any boilerplate"
+ + " content the browser may automatically add to all"
+ + " notifications (for example, some browsers show the origin"
+ + " in the notification)", t, closeNotifications, notifications)
+ notification = new Notification(text, {
+ body: ""
+ })
+ notifications.push(notification)
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/common.js b/testing/web-platform/tests/notifications/common.js
new file mode 100644
index 0000000000..ecfa0e3c2d
--- /dev/null
+++ b/testing/web-platform/tests/notifications/common.js
@@ -0,0 +1,48 @@
+function createPassFail(condition, test, cleanup, cleanupParam) {
+ var div = document.querySelector("#passfail")
+ var para = document.createElement("p")
+ var pass = document.createElement("button")
+ var fail = document.createElement("button")
+ var style = "font-family: monospace"
+ para.innerHTML = condition
+ + ', press the PASS button;'
+ + ' otherwise press the FAIL button.',
+ pass.innerHTML = "PASS"
+ fail.innerHTML = "FAIL"
+ pass.setAttribute("style", style)
+ fail.setAttribute("style", style)
+ pass.addEventListener("click", function () {
+ clearPassFail()
+ cleanup(cleanupParam)
+ test.done()
+ }, false)
+ fail.addEventListener("click", function () {
+ clearPassFail()
+ cleanup(cleanupParam)
+ test.force_timeout()
+ test.set_status(test.FAIL)
+ test.done()
+ }, false)
+ document.body.appendChild(div)
+ div.appendChild(para)
+ div.appendChild(pass)
+ div.appendChild(fail)
+}
+function clearPassFail() {
+ document.querySelector("#passfail").innerHTML = ""
+}
+function closeNotifications(notifications) {
+ for (var i=0; i < notifications.length; i++) {
+ notifications[i].close()
+ }
+}
+function hasNotificationPermission() {
+ Notification.requestPermission()
+ if (Notification.permission != "granted") {
+ alert("TEST NOT RUN. Change your browser settings so that"
+ + " notifications for this origin are allowed, and then re-run"
+ + " this test.")
+ return false
+ }
+ return true
+}
diff --git a/testing/web-platform/tests/notifications/constructor-basic.https.html b/testing/web-platform/tests/notifications/constructor-basic.https.html
new file mode 100644
index 0000000000..df959b922f
--- /dev/null
+++ b/testing/web-platform/tests/notifications/constructor-basic.https.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification constructor (basic)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ var notification = new Notification("New Email Received")
+ assert_true(notification instanceof Notification)
+ notification.onshow = function() {
+ notification.close()
+ }
+}, "Called the notification constructor with one argument.")
+
+test(() => {
+ assert_equals(
+ new Notification("a").silent,
+ null,
+ "Expected null by default"
+ );
+}, "Constructing a notification without a NotificationOptions defaults to null.");
+
+test(() => {
+ for (const silent of [null, undefined]) {
+ assert_equals(
+ new Notification("a", { silent }).silent,
+ null,
+ `Expected silent to be null when initialized with ${silent}.`
+ );
+ }
+ for (const silent of [true, 1, 100, {}, [], "a string"]) {
+ assert_true(
+ new Notification("a", { silent }).silent,
+ `Expected silent to be true when initialized with ${silent}.`
+ );
+ }
+ for (const silent of [false, 0, "", NaN]) {
+ assert_false(
+ new Notification("a", { silent }).silent,
+ `Expected silent to be false when initialized with ${silent}.`
+ );
+ }
+}, "constructing a notification with a NotificationOptions dictionary correctly sets and reflects the silent attribute.");
+</script>
diff --git a/testing/web-platform/tests/notifications/constructor-invalid.https.html b/testing/web-platform/tests/notifications/constructor-invalid.https.html
new file mode 100644
index 0000000000..2fae804c2c
--- /dev/null
+++ b/testing/web-platform/tests/notifications/constructor-invalid.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification constructor (invalid)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new Notification()
+ })
+}, "Called the notification constructor with no arguments.")
+</script>
diff --git a/testing/web-platform/tests/notifications/constructor-non-secure.html b/testing/web-platform/tests/notifications/constructor-non-secure.html
new file mode 100644
index 0000000000..df1f74a71f
--- /dev/null
+++ b/testing/web-platform/tests/notifications/constructor-non-secure.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification constructor (basic) on a non-secure connection</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function (t) {
+ const notification = new Notification("Sup.");
+ notification.onerror = t.step_func_done(e => {
+ assert_equals(e.type, "error");
+ });
+}, "new Notification calls onerror in non-secure contexts")
+</script>
diff --git a/testing/web-platform/tests/notifications/event-onclick-manual.https.html b/testing/web-platform/tests/notifications/event-onclick-manual.https.html
new file mode 100644
index 0000000000..0d48d06ae8
--- /dev/null
+++ b/testing/web-platform/tests/notifications/event-onclick-manual.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.onclick (basic)</title>
+<link rel="author" title="Apple Inc." href="http://www.apple.com/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification =
+ new Notification("Please click on the notification.", {
+ body: "Click me to test clicking on notifications."
+ })
+ notification.onclick = function(e) {
+ assert_equals(Object.prototype.toString.call(e), "[object Event]")
+ assert_equals(e.type, "click")
+ t.done()
+ }
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/event-onclose.https.html b/testing/web-platform/tests/notifications/event-onclose.https.html
new file mode 100644
index 0000000000..b410e6c9a1
--- /dev/null
+++ b/testing/web-platform/tests/notifications/event-onclose.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.onclose (basic)</title>
+<link rel="author" title="Apple Inc." href="http://www.apple.com/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_setup(() => {
+ return test_driver.set_permission({ name: "notifications" }, "granted")
+})
+
+promise_test(async t => {
+ const notification = new Notification("New Email Received")
+ await new Promise(resolve => {
+ notification.onshow = resolve;
+ })
+ notification.close()
+ const event = await new Promise(resolve => {
+ notification.onclose = resolve;
+ })
+ assert_equals(Object.prototype.toString.call(event), "[object Event]")
+ assert_equals(event.type, "close", "Checked the event type.")
+}, "Invoked the onclose event handler.")
+</script>
diff --git a/testing/web-platform/tests/notifications/event-onerror-default-manual.https.html b/testing/web-platform/tests/notifications/event-onerror-default-manual.https.html
new file mode 100644
index 0000000000..4a50de7366
--- /dev/null
+++ b/testing/web-platform/tests/notifications/event-onerror-default-manual.https.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.onerror (permission=default)</title>
+<link rel="author" title="Apple Inc." href="http://www.apple.com/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ explicit_timeout: true })
+if (Notification.permission != "default") {
+ alert("TEST NOT RUN. Change your browser settings so that the notification"
+ + " settings for this origin are completely cleared/removed, (so your"
+ + " browser default settings are used for this origin), and then reload"
+ + " this page.")
+} else {
+ async_test(function (t) {
+ t.step(function () {
+ var notification = new Notification("New Email Received")
+ notification.onerror = function(e) {
+ assert_equals(Object.prototype.toString.call(e), "[object Event]")
+ assert_equals(e.type, "error")
+ Notification.requestPermission()
+ t.done()
+ }
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/event-onerror-denied-manual.https.html b/testing/web-platform/tests/notifications/event-onerror-denied-manual.https.html
new file mode 100644
index 0000000000..b90fb38cc1
--- /dev/null
+++ b/testing/web-platform/tests/notifications/event-onerror-denied-manual.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.onerror (permission=denied)</title>
+<link rel="author" title="Apple Inc." href="http://www.apple.com/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ explicit_timeout: true })
+Notification.requestPermission()
+if (Notification.permission != "denied") {
+ alert("TEST NOT RUN. Change your browser settings so that notifications"
+ + " for this origin are blocked, and then reload this page.")
+} else {
+ async_test(function (t) {
+ t.step(function () {
+ var notification = new Notification("New Email Received")
+ notification.onerror = function(e) {
+ assert_equals(Object.prototype.toString.call(e), "[object Event]")
+ assert_equals(e.type, "error")
+ Notification.requestPermission()
+ t.done()
+ }
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/event-onshow.https.html b/testing/web-platform/tests/notifications/event-onshow.https.html
new file mode 100644
index 0000000000..2f7959e7d3
--- /dev/null
+++ b/testing/web-platform/tests/notifications/event-onshow.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.onshow (basic)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_setup(() => {
+ return test_driver.set_permission({ name: "notifications" }, "granted")
+})
+
+promise_test(async t => {
+ const notification = new Notification("New Email Received")
+ const event = await new Promise(resolve => {
+ notification.onshow = resolve;
+ })
+ notification.close()
+ assert_equals(Object.prototype.toString.call(event), "[object Event]")
+ assert_equals(event.type, "show", "Checked the event type.")
+}, "Invoked the onshow event handler.")
+</script>
diff --git a/testing/web-platform/tests/notifications/getnotifications-across-processes.https.window.js b/testing/web-platform/tests/notifications/getnotifications-across-processes.https.window.js
new file mode 100644
index 0000000000..ad0ecf27ef
--- /dev/null
+++ b/testing/web-platform/tests/notifications/getnotifications-across-processes.https.window.js
@@ -0,0 +1,21 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/service-workers/service-worker/resources/test-helpers.sub.js
+
+// (Cannot use `global=serviceworker` because testdriver only supports window)
+
+navigator.serviceWorker.addEventListener("message", async ev => {
+ if (ev.data === "notification-create") {
+ // (Scope used by service_worker_test)
+ const scope = "scope" + window.location.pathname;
+ const reg = await navigator.serviceWorker.getRegistration(scope);
+ await reg.showNotification("Created from window");
+ reg.active.postMessage("notification-created");
+ }
+});
+
+promise_setup(() => {
+ return test_driver.set_permission({ name: "notifications" }, "granted");
+});
+
+service_worker_test("getnotifications-sw.js", "Service worker test setup");
diff --git a/testing/web-platform/tests/notifications/getnotifications-sw.js b/testing/web-platform/tests/notifications/getnotifications-sw.js
new file mode 100644
index 0000000000..331913b993
--- /dev/null
+++ b/testing/web-platform/tests/notifications/getnotifications-sw.js
@@ -0,0 +1,56 @@
+importScripts("/resources/testharness.js");
+
+async function cleanup() {
+ for (const n of await registration.getNotifications()) {
+ n.close();
+ }
+}
+
+async function test_notification(t, title) {
+ t.add_cleanup(cleanup);
+
+ const notifications = await registration.getNotifications();
+
+ assert_equals(
+ notifications.length,
+ 1,
+ "There should be one stored notification"
+ );
+ const notification = notifications[0];
+ assert_true(notification instanceof Notification, "Should be a Notification");
+ assert_equals(notification.title, title, "Title should match");
+}
+
+async function postAll(data) {
+ const clients = await self.clients.matchAll({ includeUncontrolled: true });
+ assert_true(clients.length > 0, "clients.length");
+ for (const client of clients) {
+ client.postMessage(data);
+ }
+}
+
+async function untilActivate() {
+ if (registration.active) {
+ return;
+ }
+ return new Promise(resolve => {
+ addEventListener("activate", resolve, { once: true });
+ });
+}
+
+promise_test(async t => {
+ await new Promise((resolve, reject) => {
+ self.addEventListener("message", ev => {
+ if (ev.data === "notification-created") {
+ resolve();
+ }
+ });
+ untilActivate().then(() => postAll("notification-create")).catch(reject);
+ });
+ await test_notification(t, "Created from window");
+}, "Get notification created from window");
+
+promise_test(async t => {
+ await registration.showNotification("Created here");
+ await test_notification(t, "Created here");
+}, "Create and get notification within service worker");
diff --git a/testing/web-platform/tests/notifications/historical.any.js b/testing/web-platform/tests/notifications/historical.any.js
new file mode 100644
index 0000000000..fe5f3e9059
--- /dev/null
+++ b/testing/web-platform/tests/notifications/historical.any.js
@@ -0,0 +1,3 @@
+test(() => {
+ assert_equals(Notification.get, undefined);
+}, "Notification.get is obsolete");
diff --git a/testing/web-platform/tests/notifications/icon-basic-manual.https.html b/testing/web-platform/tests/notifications/icon-basic-manual.https.html
new file mode 100644
index 0000000000..32e8e0bbbd
--- /dev/null
+++ b/testing/web-platform/tests/notifications/icon-basic-manual.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.icon (basic)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<div id=passfail></div>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification = null,
+ notifications = []
+ createPassFail("If a notification appears containing"
+ + " an image of a cat",
+ t, closeNotifications, notifications)
+ notification = new Notification("New Email Received", {
+ body: "Room 101",
+ icon: "http://test.csswg.org/source/support/cat.png"
+ })
+ notifications.push(notification)
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/icon-empty-manual.https.html b/testing/web-platform/tests/notifications/icon-empty-manual.https.html
new file mode 100644
index 0000000000..a4b288fa59
--- /dev/null
+++ b/testing/web-platform/tests/notifications/icon-empty-manual.https.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.icon (empty string)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<div id=passfail></div>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification = null,
+ notifications = []
+ createPassFail("If a notification appears containing no image",
+ t, closeNotifications, notifications)
+ notification = new Notification("New Email Received", {
+ body: "Room 101",
+ icon: ""
+ })
+ notifications.push(notification)
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/idlharness.https.any.js b/testing/web-platform/tests/notifications/idlharness.https.any.js
new file mode 100644
index 0000000000..e3afe2c219
--- /dev/null
+++ b/testing/web-platform/tests/notifications/idlharness.https.any.js
@@ -0,0 +1,31 @@
+// META: global=window,worker
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://notifications.spec.whatwg.org/
+
+idl_test(
+ ['notifications'],
+ ['service-workers', 'hr-time', 'html', 'dom'],
+ idl_array => {
+ if (self.ServiceWorkerGlobalScope) {
+ idl_array.add_objects({
+ ServiceWorkerGlobalScope: ['self'],
+ });
+ // NotificationEvent could be tested here, but the constructor requires
+ // a Notification instance which cannot be created in a service worker,
+ // see below.
+ } else {
+ // While the Notification interface is exposed in service workers, the
+ // constructor (https://notifications.spec.whatwg.org/#dom-notification-notification)
+ // is defined to throw a TypeError. Therefore, we only add the object in
+ // the other scopes.
+ idl_array.add_objects({
+ Notification: ['notification'],
+ });
+ self.notification = new Notification('title');
+ }
+ }
+);
diff --git a/testing/web-platform/tests/notifications/instance.https.html b/testing/web-platform/tests/notifications/instance.https.html
new file mode 100644
index 0000000000..5ccc6cd1e3
--- /dev/null
+++ b/testing/web-platform/tests/notifications/instance.https.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification instance basic tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/custom-data.js"></script>
+<script>
+var n = new Notification("Radio check",
+ {
+ dir: "ltr",
+ lang: "aa",
+ body: "This is a radio check.",
+ tag: "radio_check999",
+ icon: "http://example.com/icon.png",
+ data: fakeCustomData,
+ }
+)
+n.onshow = function() {
+ n.close()
+}
+test(function() {
+ assert_true(n instanceof Notification)
+},"Notification instance exists.")
+test(function() {
+ assert_true("close" in n)
+},"Attribute exists: close")
+test(function() {
+ assert_true("onclick" in n)
+},"Attribute exists: onclick")
+test(function() {
+ assert_true("onshow" in n)
+},"Attribute exists: onshow")
+test(function() {
+ assert_true("onerror" in n)
+},"Attribute exists: onerror")
+test(function() {
+ assert_true("onclose" in n)
+},"Attribute exists: onclose")
+test(function() {
+ assert_equals("Radio check", n.title)
+},"Attribute exists with expected value: title")
+test(function() {
+ assert_equals("ltr", n.dir)
+},"Attribute exists with expected value: dir")
+test(function() {
+ assert_equals("aa", n.lang)
+},"Attribute exists with expected value: lang")
+test(function() {
+ assert_equals("This is a radio check.", n.body)
+},"Attribute exists with expected value: body")
+test(function() {
+ assert_equals("radio_check999", n.tag)
+},"Attribute exists with expected value: tag")
+test(function() {
+ assert_equals("http://example.com/icon.png", n.icon)
+},"Attribute exists with expected value: icon")
+test(function() {
+ assert_custom_data(n.data);
+},"Attribute exists with expected value: data")
+</script>
diff --git a/testing/web-platform/tests/notifications/lang.https.html b/testing/web-platform/tests/notifications/lang.https.html
new file mode 100644
index 0000000000..be1795c8c9
--- /dev/null
+++ b/testing/web-platform/tests/notifications/lang.https.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.lang</title>
+<link rel="author" title="Apple Inc." href="http://www.apple.com/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ explicit_done: true });
+
+/* Validity and well-formedness was determined by using the BCP 47
+ Validator at http://schneegans.de/lv/ */
+
+/* The empty string is valid, as well as any valid BCP 47 language tag. */
+var valid_langs = ["", "en", "en-US-x-hixie", "de-DE", "de-de", "de-De",
+ "de-dE", "de-DE-1996", "de-Latn-DE", "de-Latf-DE",
+ "de-Latn-DE-1996", "de-CH", "it-CH", "fr-CH",
+ "rm-CH", "es-CH"];
+
+/* Well-formed but invalid BCP 47 language tags should not round-trip;
+ they should come back as the empty string. */
+var well_formed_langs = ["Latn-de", "Latf-de", "tic-tac-tac-toe",
+ "cocoa-1-bar", "cocoa-a-bar"];
+
+/* Invalid BCP 47 language tags should not round-trip; they should come
+ back as the empty string. */
+var invalid_langs = ["en-", "en-\-", "foo-\-bar", "id-\-\-Java", "fr-x",
+ "fr-xenomorph", "fr-x-xenomorph", "a", "a-fr-lang",
+ "b-fr-lang", "es1-KK-aa-bb-cc-dd",
+ "es2-KL-aa-bb-cc-dd", "es3-KM-aa-bb-cc-dd", "fooÉ",
+ "foöÉ-bÁr", "foöÉbÁr"];
+
+function test_lang(language, should_passthrough) {
+ var expected = should_passthrough ? language : "";
+ test(function() {
+ if (Notification.permission != "granted") {
+ this.force_timeout()
+ this.set_status(this.NOTRUN, "You must allow notifications for this origin before running this test.")
+ }
+ var notification = new Notification("This is a notification.", {
+ lang: language
+ });
+ assert_equals(notification.lang, expected, "notification.lang");
+ notification.onshow = function() {
+ notification.close();
+ };
+ },
+ "Roundtripping lang \"" + language + "\". Expecting \"" + expected + "\".");
+}
+
+for (var i=0; i<valid_langs.length; i++) {
+ test_lang(valid_langs[i], true);
+}
+
+for (var i=0; i<well_formed_langs.length; i++) {
+ test_lang(well_formed_langs[i], false);
+}
+
+for (var i=0; i<invalid_langs.length; i++) {
+ test_lang(invalid_langs[i], false);
+}
+
+done();
+</script>
diff --git a/testing/web-platform/tests/notifications/noop-sw.js b/testing/web-platform/tests/notifications/noop-sw.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/notifications/noop-sw.js
diff --git a/testing/web-platform/tests/notifications/permission.html b/testing/web-platform/tests/notifications/permission.html
new file mode 100644
index 0000000000..d8b201e42e
--- /dev/null
+++ b/testing/web-platform/tests/notifications/permission.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.permission (basic)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_in_array(Notification.permission,
+ ["default", "denied", "granted"],
+ "Notification.permission")
+}, "Checked the Notification.permission property.")
+</script>
diff --git a/testing/web-platform/tests/notifications/permissions-non-secure.html b/testing/web-platform/tests/notifications/permissions-non-secure.html
new file mode 100644
index 0000000000..0f4724c9b6
--- /dev/null
+++ b/testing/web-platform/tests/notifications/permissions-non-secure.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification permissions should be denied in non-secure contexts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+ return Notification.requestPermission().then(result => {
+ assert_equals(result, "denied");
+ });
+}, "Notification.requestPermission must be called from a secure context");
+
+test(t => {
+ assert_equals(Notification.permission, "denied");
+}, "Notification.permission must be called from a secure context");
+</script>
diff --git a/testing/web-platform/tests/notifications/requestPermission-denied-manual.https.html b/testing/web-platform/tests/notifications/requestPermission-denied-manual.https.html
new file mode 100644
index 0000000000..a7ec052dba
--- /dev/null
+++ b/testing/web-platform/tests/notifications/requestPermission-denied-manual.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.requestPermission (permission=denied)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ explicit_timeout: true })
+Notification.requestPermission()
+if (Notification.permission != "denied") {
+ alert("TEST NOT RUN. Change your browser settings so that notifications"
+ + " for this origin are blocked, and then reload this page.")
+} else {
+ async_test(function (t) {
+ t.step(function () {
+ Notification.requestPermission()
+ t.done()
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/requestPermission-granted-manual.https.html b/testing/web-platform/tests/notifications/requestPermission-granted-manual.https.html
new file mode 100644
index 0000000000..970f4e3cbc
--- /dev/null
+++ b/testing/web-platform/tests/notifications/requestPermission-granted-manual.https.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.requestPermission (permission=granted)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ t.done()
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/requireInteraction-manual.https.html b/testing/web-platform/tests/notifications/requireInteraction-manual.https.html
new file mode 100644
index 0000000000..23e9e4bbb3
--- /dev/null
+++ b/testing/web-platform/tests/notifications/requireInteraction-manual.https.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>requireInteraction: true</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>
+ <button id="button">Push me to open a requireInteraction=true notification!</button>
+ <button id="finish">Push me if you are done</button>
+</p>
+Steps:
+<ol>
+ <li>Make sure you didn't block the notification permission.</li>
+ <li>Allow the notification permission if the prompt opens.</li>
+ <li>Click the first button.</li>
+ <li>See whether the notification disappears from the screen without interaction. It must not.</li>
+ <li>If you are sure it's not disappearing, then click that second button.</li>
+</ol>
+Why this is manual? Because
+<ol>
+ <li>
+ One need to wait for more than arbitrary platform-specific time to see
+ it really does not disappear automatically.
+ </li>
+ <li>There's simply no API to tell it's disappeared from the screen or not</li>
+</ol>
+<script>
+ setup({ explicit_timeout: true })
+
+ promise_test(async () => {
+ const permission = await Notification.requestPermission();
+ if (permission === "denied") {
+ throw new Error("Permission is denied, can't proceed");
+ }
+ await new Promise(r => button.onclick = r);
+ const n = new Notification("Test notification", { requireInteraction: true });
+ await new Promise((resolve, reject) => {
+ n.onshow = resolve;
+ n.onerror = () => reject(new Error(
+ "Notification failed, and there's no good error message. Maybe some permission issue?"
+ ));
+ });
+ await Promise.race([
+ new Promise(r => finish.onclick = r),
+ new Promise((r, reject) => {
+ n.onclose = n.onclick = () => reject(new Error(
+ "Uh, you should finish the test before you interact with the notification."
+ ));
+ }),
+ ]);
+ });
+</script>
diff --git a/testing/web-platform/tests/notifications/resources/custom-data.js b/testing/web-platform/tests/notifications/resources/custom-data.js
new file mode 100644
index 0000000000..b21d28a1bb
--- /dev/null
+++ b/testing/web-platform/tests/notifications/resources/custom-data.js
@@ -0,0 +1,66 @@
+var fakeCustomData = (function() {
+ var buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 42, true);
+ var canvas = document.createElement("canvas");
+ canvas.width = canvas.height = 100;
+ var context = canvas.getContext("2d");
+
+ var map = new Map();
+ var set = new Set();
+ map.set("test", 42);
+ set.add(4);
+ set.add(2);
+
+ return {
+ primitives: {
+ a: 123,
+ b: "test",
+ c: true,
+ d: [1, 2, 3],
+ },
+ date: new Date(2013, 2, 1, 1, 10),
+ regexp: new RegExp("[^.]+"),
+ arrayBuffer: buffer,
+ imageData: context.createImageData(100, 100),
+ map,
+ set,
+ };
+})();
+
+function assert_custom_data(dataObj) {
+ assert_equals(typeof dataObj, "object", "data should be a JS object");
+ assert_equals(
+ JSON.stringify(dataObj.primitives),
+ JSON.stringify(fakeCustomData.primitives),
+ "data.primitives should be preserved"
+ );
+ assert_equals(
+ dataObj.date.toDateString(),
+ fakeCustomData.date.toDateString(),
+ "data.date should be preserved"
+ );
+ assert_equals(
+ dataObj.regexp.exec("http://www.domain.com")[0].substr(7),
+ "www",
+ "data.regexp should be preserved"
+ );
+ assert_equals(
+ new Int16Array(dataObj.arrayBuffer)[0],
+ 42,
+ "data.arrayBuffer should be preserved"
+ );
+ assert_equals(
+ JSON.stringify(dataObj.imageData.data),
+ JSON.stringify(fakeCustomData.imageData.data),
+ "data.imageData should be preserved"
+ )
+ assert_equals(
+ dataObj.map.get("test"),
+ 42,
+ "data.map should be preserved"
+ );
+ assert_true(
+ dataObj.set.has(4) && dataObj.set.has(2),
+ "data.set should be preserved"
+ );
+}
diff --git a/testing/web-platform/tests/notifications/resources/helpers.js b/testing/web-platform/tests/notifications/resources/helpers.js
new file mode 100644
index 0000000000..8c30173336
--- /dev/null
+++ b/testing/web-platform/tests/notifications/resources/helpers.js
@@ -0,0 +1,20 @@
+function unregisterAllServiceWorker() {
+ return navigator.serviceWorker.getRegistrations().then(registrations => {
+ return Promise.all(registrations.map(r => r.unregister()));
+ });
+}
+
+async function getActiveServiceWorker(script) {
+ await unregisterAllServiceWorker();
+ const reg = await navigator.serviceWorker.register(script);
+ add_completion_callback(() => reg.unregister());
+ await navigator.serviceWorker.ready;
+ return reg;
+}
+
+
+async function closeAllNotifications() {
+ for (const n of await registration.getNotifications()) {
+ n.close();
+ }
+}
diff --git a/testing/web-platform/tests/notifications/resources/icon.png b/testing/web-platform/tests/notifications/resources/icon.png
new file mode 100644
index 0000000000..ee919cd512
--- /dev/null
+++ b/testing/web-platform/tests/notifications/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/notifications/resources/shownotification-sw.js b/testing/web-platform/tests/notifications/resources/shownotification-sw.js
new file mode 100644
index 0000000000..63a1569460
--- /dev/null
+++ b/testing/web-platform/tests/notifications/resources/shownotification-sw.js
@@ -0,0 +1,27 @@
+self.onmessage = event => {
+ // Checking for a particular value, so more tests can be added in future.
+ if (event.data !== 'test-shownotification') return;
+
+ // Random number, so we can identify the notification we create.
+ const random = Math.random().toString();
+ const start = Date.now();
+
+ event.waitUntil(
+ self.registration.showNotification('test', {
+ tag: random,
+ // ?pipe=trickle(d2) delays the icon request by two seconds
+ icon: 'icon.png?pipe=trickle(d2)'
+ }).then(() => {
+ const resolveDuration = Date.now() - start;
+
+ return self.registration.getNotifications().then(notifications => {
+ event.source.postMessage({
+ type: 'notification-data',
+ resolveDuration,
+ // Check if our notification is in notifications
+ notificationReturned: notifications.some(n => n.tag == random)
+ });
+ });
+ })
+ );
+}; \ No newline at end of file
diff --git a/testing/web-platform/tests/notifications/shownotification-resolve-manual.https.html b/testing/web-platform/tests/notifications/shownotification-resolve-manual.https.html
new file mode 100644
index 0000000000..a73b11d100
--- /dev/null
+++ b/testing/web-platform/tests/notifications/shownotification-resolve-manual.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const worker = 'resources/shownotification-sw.js';
+
+function reset() {
+ return navigator.serviceWorker.getRegistrations().then(registrations => {
+ return Promise.all(registrations.map(r => r.unregister()));
+ });
+}
+
+function getNewestWorker(reg) {
+ return reg.installing || reg.waiting || reg.active;
+}
+
+function registerSwAndGetWorker() {
+ return reset()
+ .then(() => navigator.serviceWorker.register(worker))
+ .then(getNewestWorker);
+}
+
+promise_test(() => {
+ // Get notification permission
+ return Notification.requestPermission().then(permission => {
+ if (permission != "granted") {
+ throw Error('You must allow notifications for this origin before running this test.');
+ }
+ return registerSwAndGetWorker();
+ }).then(worker => {
+ return new Promise(resolve => {
+ // Wait for the service worker to post a message with type 'notification-data'.
+ navigator.serviceWorker.onmessage = event => {
+ if (event.data && event.data.type == 'notification-data') {
+ resolve(event.data);
+ navigator.serviceWorker.onmessage = null;
+ }
+ };
+
+ // Ask the service worker to run the test.
+ worker.postMessage('test-shownotification');
+ })
+ }).then(result => {
+ assert_true(result.notificationReturned, `Notification appeared in getNotifications`);
+ // The icon is delayed by 2000ms, so showNotification should have taken at least 1900 to resolve.
+ assert_greater_than(result.resolveDuration, 1900, `showNotification appeared to wait for icon load`);
+ });
+}, 'showNotification resolves after icon fetch');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/notifications/shownotification-without-permission.https.window.js b/testing/web-platform/tests/notifications/shownotification-without-permission.https.window.js
new file mode 100644
index 0000000000..37b3dbbef6
--- /dev/null
+++ b/testing/web-platform/tests/notifications/shownotification-without-permission.https.window.js
@@ -0,0 +1,28 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=resources/helpers.js
+
+"use strict";
+
+/** @type {ServiceWorkerRegistration} */
+let registration;
+
+promise_setup(async () => {
+ registration = await getActiveServiceWorker("noop-sw.js");
+});
+
+promise_test(async (t) => {
+ t.add_cleanup(closeAllNotifications);
+
+ try {
+ await test_driver.set_permission({ name: "notifications" }, "prompt");
+ } catch {
+ // Not all implementations support this yet, but it may already be "prompt" to be able to continue
+ }
+
+ assert_equals(Notification.permission, "default", "Should have the default permission to continue");
+
+ await promise_rejects_js(t, TypeError, registration.showNotification(""), "Should throw TypeError");
+ const notifications = await registration.getNotifications();
+ assert_equals(notifications.length, 0, "Should return zero notification");
+}, "showNotificaiton should not be listed with permission=default")
diff --git a/testing/web-platform/tests/notifications/shownotification.https.window.js b/testing/web-platform/tests/notifications/shownotification.https.window.js
new file mode 100644
index 0000000000..3875f5fdb4
--- /dev/null
+++ b/testing/web-platform/tests/notifications/shownotification.https.window.js
@@ -0,0 +1,87 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=resources/helpers.js
+// META: script=resources/custom-data.js
+
+"use strict";
+
+/** @type {ServiceWorkerRegistration} */
+let registration;
+
+promise_setup(async () => {
+ await test_driver.set_permission({ name: "notifications" }, "granted");
+ registration = await getActiveServiceWorker("noop-sw.js");
+});
+
+promise_test(async () => {
+ const notifications = await registration.getNotifications();
+ assert_equals(notifications.length, 0, "Should return zero notification");
+}, "fetching no notifications");
+
+promise_test(async t => {
+ t.add_cleanup(closeAllNotifications);
+ await registration.showNotification("");
+ const notifications = await registration.getNotifications();
+ assert_equals(notifications.length, 1, "Should return one notification");
+ assert_equals(notifications[0].title, "", "Should return an empty title");
+}, "fetching notification with an empty title");
+
+promise_test(async t => {
+ t.add_cleanup(closeAllNotifications);
+ await Promise.all([
+ registration.showNotification("thunder", { tag: "fire" }),
+ registration.showNotification("bird", { tag: "fox" }),
+ registration.showNotification("supernova", { tag: "quantum" }),
+ ]);
+ const notifications = await registration.getNotifications({ tag: "quantum" });
+ assert_equals(
+ notifications.length,
+ 1,
+ "Should return only the matching notification"
+ );
+ assert_equals(notifications[0].title, "supernova", "title should match");
+ assert_equals(notifications[0].tag, "quantum", "tag should match");
+}, "fetching notification by tag filter");
+
+promise_test(async t => {
+ t.add_cleanup(closeAllNotifications);
+ await Promise.all([
+ registration.showNotification("thunder"),
+ registration.showNotification("bird"),
+ registration.showNotification("supernova"),
+ ]);
+ const notifications = await registration.getNotifications();
+ assert_equals(notifications.length, 3, "Should return three notifications");
+}, "fetching multiple notifications");
+
+// https://notifications.spec.whatwg.org/#dom-serviceworkerregistration-getnotifications
+// Step 5.2: Let notifications be a list of all notifications in the list of
+// notifications ... whose service worker registration is this ...
+promise_test(async t => {
+ t.add_cleanup(closeAllNotifications);
+ const another = await navigator.serviceWorker.register("noop-sw.js", { scope: "./scope" });
+ await registration.showNotification("Hello");
+ const notifications = await another.getNotifications();
+ assert_equals(notifications.length, 0, "Should return no notification");
+}, "fetching from another registration")
+
+// https://notifications.spec.whatwg.org/#non-persistent-notification
+// A non-persistent notification is a notification without an associated
+// service worker registration.
+promise_test(async t => {
+ t.add_cleanup(closeAllNotifications);
+ const nonPersistent = new Notification("Non-persistent");
+ t.add_cleanup(() => nonPersistent.close());
+ await registration.showNotification("Hello");
+ const notifications = await registration.getNotifications();
+ assert_equals(notifications.length, 1, "Should return a notification");
+ assert_equals(notifications[0].title, "Hello", "Title should match");
+}, "fetching only persistent notifications")
+
+promise_test(async t => {
+ t.add_cleanup(closeAllNotifications);
+ await registration.showNotification("Hello", { data: fakeCustomData });
+ const notifications = await registration.getNotifications();
+ assert_equals(notifications.length, 1, "Should return a notification");
+ assert_custom_data(notifications[0].data);
+}, "fetching a notification with custom data")
diff --git a/testing/web-platform/tests/notifications/tag-different-manual.https.html b/testing/web-platform/tests/notifications/tag-different-manual.https.html
new file mode 100644
index 0000000000..e463e97670
--- /dev/null
+++ b/testing/web-platform/tests/notifications/tag-different-manual.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.tag (two tags with different values)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<div id=passfail></div>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification1 = null,
+ notification2 = null,
+ notifications = [],
+ text1 = "This is the body: Room 101",
+ text2 = "This is the body: Room 202"
+ createPassFail("If two notifications appear: First one with the"
+ + " text \"" + text1 + "\", followed by one with the text \""
+ + text2 + "\"",
+ t, closeNotifications, notifications)
+ notification1 = new Notification("New Email Received", {
+ body: text1,
+ tag: "Tom"
+ })
+ notification2 = new Notification("New Email Received", {
+ body: text2,
+ tag: "Rose"
+ })
+ notifications.push(notification1)
+ notifications.push(notification2)
+ })
+ })
+}
+</script>
diff --git a/testing/web-platform/tests/notifications/tag-same-manual.https.html b/testing/web-platform/tests/notifications/tag-same-manual.https.html
new file mode 100644
index 0000000000..4454944c53
--- /dev/null
+++ b/testing/web-platform/tests/notifications/tag-same-manual.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Notification.tag (two tags with same value)</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="author" title="Xin Liu" href="mailto:xinx.liu@intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="common.js"></script>
+<div id=passfail></div>
+<script>
+setup({ explicit_timeout: true })
+if (hasNotificationPermission()) {
+ async_test(function (t) {
+ t.step(function () {
+ var notification1 = null,
+ notification2 = null,
+ notifications = [],
+ text1 = "This is the body: Room 101",
+ text2 = "This is the body: Room 202"
+ createPassFail("If a notification with the text \""
+ + text2 + "\", replaces the notification with the text \""
+ + text1 + "\" in the same position",
+ t, closeNotifications, notifications)
+ notification1 = new Notification("New Email Received", {
+ body: text1,
+ tag: "Tom"
+ })
+ notification2 = new Notification("New Email Received", {
+ body: text2,
+ tag: "Tom"
+ })
+ notifications.push(notification1)
+ notifications.push(notification2)
+ })
+ })
+}
+</script>