summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt')
-rw-r--r--mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt386
1 files changed, 386 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt
new file mode 100644
index 0000000000..469fd049ce
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt
@@ -0,0 +1,386 @@
+package org.mozilla.geckoview.test
+
+import android.os.Parcel
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.hamcrest.Matchers.* // ktlint-disable no-wildcard-imports
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mozilla.geckoview.GeckoResult
+import org.mozilla.geckoview.GeckoSession
+import org.mozilla.geckoview.GeckoSession.PermissionDelegate
+import org.mozilla.geckoview.WebNotification
+import org.mozilla.geckoview.WebNotificationDelegate
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
+
+const val VERY_LONG_IMAGE_URL = "https://example.com/this/is/a/very/long/address/that/is/meant/to/be/longer/than/is/one/hundred/and/fifth/characters/long/for/testing/imageurl/length.ico"
+
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+class WebNotificationTest : BaseSessionTest() {
+
+ @Before fun setup() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
+
+ // Grant "desktop notification" permission
+ mainSession.delegateUntilTestEnd(object : PermissionDelegate {
+ override fun onContentPermissionRequest(session: GeckoSession, perm: PermissionDelegate.ContentPermission):
+ GeckoResult<Int>? {
+ assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
+ return GeckoResult.fromValue(PermissionDelegate.ContentPermission.VALUE_ALLOW)
+ }
+ })
+
+ val result = mainSession.waitForJS("Notification.requestPermission()")
+ assertThat(
+ "Permission should be granted",
+ result as String,
+ equalTo("granted"),
+ )
+ }
+
+ @Test fun onSilentNotification() {
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.silent.enabled" to true))
+ val notificationResult = GeckoResult<Void>()
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ assertThat("Title should match", notification.title, equalTo("The Title"))
+ assertThat("Silent should match", notification.silent, equalTo(true))
+ assertThat("Vibrate should match", notification.vibrate, equalTo(intArrayOf()))
+ assertThat("Source should match", notification.source, equalTo(createTestUrl(HELLO_HTML_PATH)))
+ notificationResult.complete(null)
+ }
+ })
+
+ mainSession.evaluateJS(
+ """
+ new Notification('The Title', { body: 'The Text', silent: true });
+ """.trimIndent(),
+ )
+
+ sessionRule.waitForResult(notificationResult)
+ }
+
+ fun assertNotificationData(notification: WebNotification, requireInteraction: Boolean) {
+ assertThat("Title should match", notification.title, equalTo("The Title"))
+ assertThat("Body should match", notification.text, equalTo("The Text"))
+ assertThat("Tag should match", notification.tag, endsWith("Tag"))
+ assertThat("ImageUrl should match", notification.imageUrl, endsWith("icon.png"))
+ assertThat("Language should match", notification.lang, equalTo("en-US"))
+ assertThat("Direction should match", notification.textDirection, equalTo("ltr"))
+ assertThat(
+ "Require Interaction should match",
+ notification.requireInteraction,
+ equalTo(requireInteraction),
+ )
+ assertThat("Vibrate should match", notification.vibrate, equalTo(intArrayOf(1, 2, 3, 4)))
+ assertThat("Silent should match", notification.silent, equalTo(false))
+ assertThat("Source should match", notification.source, equalTo(createTestUrl(HELLO_HTML_PATH)))
+ }
+
+ @GeckoSessionTestRule.Setting.List(
+ GeckoSessionTestRule.Setting(
+ key = GeckoSessionTestRule.Setting.Key.USE_PRIVATE_MODE,
+ value = "true",
+ ),
+ )
+ @Ignore // Bug 1843046 - Disabled because private notifications are temporarily disabled.
+ @Test
+ fun onShowNotification() {
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.vibrate.enabled" to true))
+ val notificationResult = GeckoResult<Void>()
+ val requireInteraction =
+ sessionRule.getPrefs("dom.webnotifications.requireinteraction.enabled")[0] as Boolean
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ assertNotificationData(notification, requireInteraction)
+ assertThat("privateBrowsing should match", notification.privateBrowsing, equalTo(true))
+ notificationResult.complete(null)
+ }
+ })
+
+ mainSession.evaluateJS(
+ """
+ new Notification('The Title', { body: 'The Text', cookie: 'Cookie',
+ icon: 'icon.png', tag: 'Tag', dir: 'ltr', lang: 'en-US',
+ requireInteraction: true, vibrate: [1,2,3,4] });
+ """.trimIndent(),
+ )
+
+ sessionRule.waitForResult(notificationResult)
+ }
+
+ @Test fun onCloseNotification() {
+ val closeCalled = GeckoResult<Void>()
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onCloseNotification(notification: WebNotification) {
+ closeCalled.complete(null)
+ }
+ })
+
+ mainSession.evaluateJS(
+ """
+ const notification = new Notification('The Title', { body: 'The Text'});
+ notification.close();
+ """.trimIndent(),
+ )
+
+ sessionRule.waitForResult(closeCalled)
+ }
+
+ @Test fun clickNotificationParceled() {
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.vibrate.enabled" to true))
+ val notificationResult = GeckoResult<WebNotification>()
+ val requireInteraction =
+ sessionRule.getPrefs("dom.webnotifications.requireinteraction.enabled")[0] as Boolean
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ notificationResult.complete(notification)
+ }
+ })
+
+ val promiseResult = mainSession.evaluatePromiseJS(
+ """
+ new Promise(resolve => {
+ const notification = new Notification('The Title', {
+ body: 'The Text',
+ cookie: 'Cookie',
+ icon: 'icon.png',
+ tag: 'Tag',
+ dir: 'ltr',
+ lang: 'en-US',
+ requireInteraction: true,
+ vibrate: [1,2,3,4]
+ });
+ notification.onclick = function() {
+ resolve(1);
+ }
+ });
+ """.trimIndent(),
+ )
+
+ val notification = sessionRule.waitForResult(notificationResult)
+ assertNotificationData(notification, requireInteraction)
+ assertThat("privateBrowsing should match", notification.privateBrowsing, equalTo(false))
+
+ // Test that we can click from a deserialized notification
+ val parcel = Parcel.obtain()
+ notification.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+
+ val deserialized = WebNotification.CREATOR.createFromParcel(parcel)
+ assertNotificationData(deserialized, requireInteraction)
+ assertThat("privateBrowsing should match", deserialized.privateBrowsing, equalTo(false))
+
+ deserialized!!.click()
+ assertThat("Promise should have been resolved.", promiseResult.value as Double, equalTo(1.0))
+ }
+
+ @GeckoSessionTestRule.Setting.List(
+ GeckoSessionTestRule.Setting(
+ key = GeckoSessionTestRule.Setting.Key.USE_PRIVATE_MODE,
+ value = "true",
+ ),
+ )
+ @Ignore // Bug 1843046 - Disabled because private notifications are temporarily disabled.
+ @Test
+ fun clickPrivateNotificationParceled() {
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.vibrate.enabled" to true))
+ val notificationResult = GeckoResult<WebNotification>()
+ val requireInteraction =
+ sessionRule.getPrefs("dom.webnotifications.requireinteraction.enabled")[0] as Boolean
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ notificationResult.complete(notification)
+ }
+ })
+
+ val promiseResult = mainSession.evaluatePromiseJS(
+ """
+ new Promise(resolve => {
+ const notification = new Notification('The Title', {
+ body: 'The Text',
+ cookie: 'Cookie',
+ icon: 'icon.png',
+ tag: 'Tag',
+ dir: 'ltr',
+ lang: 'en-US',
+ requireInteraction: true,
+ vibrate: [1,2,3,4]
+ });
+ notification.onclick = function() {
+ resolve(1);
+ }
+ });
+ """.trimIndent(),
+ )
+
+ val notification = sessionRule.waitForResult(notificationResult)
+ assertNotificationData(notification, requireInteraction)
+ assertThat("privateBrowsing should match", notification.privateBrowsing, equalTo(true))
+
+ // Test that we can click from a deserialized notification
+ val parcel = Parcel.obtain()
+ notification.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+
+ val deserialized = WebNotification.CREATOR.createFromParcel(parcel)
+ assertNotificationData(deserialized, requireInteraction)
+ assertThat("privateBrowsing should match", deserialized.privateBrowsing, equalTo(true))
+
+ deserialized!!.click()
+ assertThat("Promise should have been resolved.", promiseResult.value as Double, equalTo(1.0))
+ }
+
+ @Test fun clickNotification() {
+ val notificationResult = GeckoResult<Void>()
+ var notificationShown: WebNotification? = null
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ notificationShown = notification
+ notificationResult.complete(null)
+ }
+ })
+
+ val promiseResult = mainSession.evaluatePromiseJS(
+ """
+ new Promise(resolve => {
+ const notification = new Notification('The Title', { body: 'The Text' });
+ notification.onclick = function() {
+ resolve(1);
+ }
+ });
+ """.trimIndent(),
+ )
+
+ sessionRule.waitForResult(notificationResult)
+ notificationShown!!.click()
+
+ assertThat("Promise should have been resolved.", promiseResult.value as Double, equalTo(1.0))
+ }
+
+ @Test fun dismissNotification() {
+ val notificationResult = GeckoResult<Void>()
+ var notificationShown: WebNotification? = null
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ notificationShown = notification
+ notificationResult.complete(null)
+ }
+ })
+
+ val promiseResult = mainSession.evaluatePromiseJS(
+ """
+ new Promise(resolve => {
+ const notification = new Notification('The Title', { body: 'The Text'});
+ notification.onclose = function() {
+ resolve(1);
+ }
+ });
+ """.trimIndent(),
+ )
+
+ sessionRule.waitForResult(notificationResult)
+ notificationShown!!.dismiss()
+
+ assertThat("Promise should have been resolved", promiseResult.value as Double, equalTo(1.0))
+ }
+
+ @Test fun writeToParcel() {
+ val notificationResult = GeckoResult<WebNotification>()
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ notificationResult.complete(notification)
+ }
+ })
+
+ val promiseResult = mainSession.evaluatePromiseJS(
+ """
+ new Promise(resolve => {
+ const notification = new Notification('The Title', { body: 'The Text' });
+ notification.onclose = function() {
+ resolve(1);
+ }
+ });
+ """.trimIndent(),
+ )
+
+ val notification = sessionRule.waitForResult(notificationResult)
+ notification.dismiss()
+
+ // Ensure we always have a non-null URL from js.
+ assertNotNull(notification.imageUrl)
+
+ // Test that we can serialize a notification
+ val parcel = Parcel.obtain()
+ notification.writeToParcel(parcel, /* ignored */ -1)
+
+ assertThat("Promise should have been resolved.", promiseResult.value as Double, equalTo(1.0))
+ }
+
+ @Test fun writeToParcelLongImageUrl() {
+ val notificationResult = GeckoResult<WebNotification>()
+
+ sessionRule.delegateDuringNextWait(object : WebNotificationDelegate {
+ @GeckoSessionTestRule.AssertCalled
+ override fun onShowNotification(notification: WebNotification) {
+ notificationResult.complete(notification)
+ }
+ })
+
+ val promiseResult = mainSession.evaluatePromiseJS(
+ """
+ new Promise(resolve => {
+ const notification = new Notification('The Title',
+ {
+ body: 'The Text',
+ icon: '$VERY_LONG_IMAGE_URL'
+ });
+ notification.onclose = function() {
+ resolve(1);
+ }
+ });
+ """.trimIndent(),
+ )
+
+ val notification = sessionRule.waitForResult(notificationResult)
+ notification.dismiss()
+
+ // Ensure we have an imageUrl longer than our max to start with.
+ assertNotNull(notification.imageUrl)
+ assertTrue(notification.imageUrl!!.length > 150)
+
+ // Test that we can serialize a notification with an imageUrl.length >= 150
+ val parcel = Parcel.obtain()
+ notification.writeToParcel(parcel, /* ignored */ -1)
+ parcel.setDataPosition(0)
+
+ val serializedNotification = WebNotification.CREATOR.createFromParcel(parcel)
+ assertTrue(serializedNotification.imageUrl!!.isBlank())
+
+ assertThat("Promise should have been resolved.", promiseResult.value as Double, equalTo(1.0))
+ }
+}