chinwag-android/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt
UlrichKu 6cbcf3eef0
Properly summarize all notifications (#4848)
Do summary notifications like the Api defines it:
* Schedule and summarize without delay (in order for summerization to
work)
* Always have a summary notification: simplify code with this and make
more reliable
* Do not care about single notification count (the system already does
that as well)
* **Bugfix: Schedule summary first: This avoids a rate limit problem
that (then) not groups at all**

Testing this is probably the most difficult part.
For example I couldn't get any notification to ring with older Api
versions in the debugger. (Same as for current develop)
However one hack to always get notifications: Fix "minId" in
"fetchNewNotifications()" to a somewhat older value.


Next possible step: Have only one summary notification at all (for all
channels/notification types). You can still configure single channels
differently.
Or: For very many notifications: Only use a true summary one (something
like "you have 28 favorites and 7 boosts").

Generally: The notification timeline must be improved now. Because that
must be the go-to solution for any large number of notifications. It
must be easy to read. E. g. with grouping per post.
2025-01-12 20:37:05 +01:00

152 lines
5.5 KiB
Kotlin

package com.keylesspalace.tusky
import android.app.Activity
import android.app.NotificationManager
import android.content.ComponentName
import android.content.Intent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.viewpager2.widget.ViewPager2
import androidx.work.testing.WorkManagerTestInitHelper
import at.connyduck.calladapter.networkresult.NetworkResult
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.systemnotifications.NotificationHelper
import com.keylesspalace.tusky.db.entity.AccountEntity
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.util.getSerializableExtraCompat
import java.util.Date
import kotlinx.coroutines.test.TestScope
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.robolectric.Robolectric
import org.robolectric.Shadows.shadowOf
import org.robolectric.android.util.concurrent.BackgroundExecutor.runInBackground
import org.robolectric.annotation.Config
@Config(sdk = [28])
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
private val context = InstrumentationRegistry.getInstrumentation().targetContext
private val account = Account(
id = "1",
localUsername = "",
username = "",
displayName = "",
createdAt = Date(),
note = "",
url = "",
avatar = "",
header = ""
)
private val accountEntity = AccountEntity(
id = 1,
domain = "test.domain",
accessToken = "fakeToken",
clientId = "fakeId",
clientSecret = "fakeSecret",
isActive = true
)
@Before
fun setup() {
WorkManagerTestInitHelper.initializeTestWorkManager(context)
}
@After
fun teardown() {
WorkManagerTestInitHelper.closeWorkDatabase()
}
@Test
fun `clicking notification of type FOLLOW shows notification tab`() {
val intent = showNotification(Notification.Type.FOLLOW)
val activity = startMainActivity(intent)
val currentTab = activity.findViewById<ViewPager2>(R.id.viewPager).currentItem
val notificationTab = defaultTabs().indexOfFirst { it.id == NOTIFICATIONS }
assertEquals(currentTab, notificationTab)
}
@Test
fun `clicking notification of type FOLLOW_REQUEST shows follow requests`() {
val intent = showNotification(Notification.Type.FOLLOW_REQUEST)
val activity = startMainActivity(intent)
val nextActivity = shadowOf(activity).peekNextStartedActivity()
assertNotNull(nextActivity)
assertEquals(ComponentName(context, AccountListActivity::class.java.name), nextActivity.component)
assertEquals(AccountListActivity.Type.FOLLOW_REQUESTS, nextActivity.getSerializableExtraCompat("type"))
}
private fun showNotification(type: Notification.Type): Intent {
val notificationManager = context.getSystemService(NotificationManager::class.java)
val shadowNotificationManager = shadowOf(notificationManager)
NotificationHelper.createNotificationChannelsForAccount(accountEntity, context)
runInBackground {
val notification = NotificationHelper.makeBaseNotification(
context,
notificationManager,
Notification(
type = type,
id = "id",
account = TimelineAccount(
id = "1",
localUsername = "connyduck",
username = "connyduck@mastodon.example",
displayName = "Conny Duck",
note = "This is their bio",
url = "https://mastodon.example/@ConnyDuck",
avatar = "https://mastodon.example/system/accounts/avatars/000/150/486/original/ab27d7ddd18a10ea.jpg"
),
status = null,
report = null
),
accountEntity
)
notificationManager.notify("id", 1, notification)
}
val notification = shadowNotificationManager.allNotifications.first()
return shadowOf(notification.contentIntent).savedIntent
}
private fun startMainActivity(intent: Intent): Activity {
val controller = Robolectric.buildActivity(MainActivity::class.java, intent)
val activity = controller.get()
activity.eventHub = EventHub()
activity.accountManager = mock {
on { activeAccount } doReturn accountEntity
}
activity.draftsAlert = mock {}
activity.shareShortcutHelper = mock {}
activity.externalScope = TestScope()
activity.mastodonApi = mock {
onBlocking { accountVerifyCredentials() } doReturn NetworkResult.success(account)
onBlocking { announcements() } doReturn NetworkResult.success(emptyList())
}
activity.preferences = mock(defaultAnswer = {
when (it.method.returnType) {
String::class.java -> "test"
Boolean::class.java -> false
else -> null
}
})
controller.create().start()
return activity
}
}