test(deeplink): pin terminal-failure replay and referendum path matching

These fail on main: a link that fails for good is kept as pending and
replayed on every launch, and /open/governance matches the referendum
handler.
This commit is contained in:
Satoshi Qazi Muhammed committed 2026-10-19 13:08:52 +04:00
1 parent 5a6eb62a1b
commit 910716c55c
4 files changed
+93

No files matched your search

+2
View File
@@ -31,6 +31,8 @@ dependencies {
implementation daggerDep
ksp daggerCompiler
testImplementation project(':test-shared')
androidTestImplementation androidTestRunnerDep
androidTestImplementation androidTestRulesDep
androidTestImplementation androidJunitDep
@@ -0,0 +1,51 @@
package io.novafoundation.nova.feature_deep_linking.presentation.handling
import android.net.Uri
import io.novafoundation.nova.feature_deep_linking.presentation.handling.common.DeepLinkHandlingException.ReferendumHandlingException
import io.novafoundation.nova.test_shared.whenever
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
class RootDeepLinkHandlerTest {
private val link = mock(Uri::class.java)
private val pendingDeepLinkProvider = mock(PendingDeepLinkProvider::class.java)
private class FailingHandler(private val error: Throwable) : DeepLinkHandler {
override val callbackFlow: Flow<CallbackEvent> = emptyFlow()
override suspend fun matches(data: Uri) = true
override suspend fun handleDeepLink(data: Uri): Result<Unit> = Result.failure(error)
}
private fun rootWith(error: Throwable) = RootDeepLinkHandler(pendingDeepLinkProvider, listOf(FailingHandler(error)))
// A link that reaches a handler and fails for good was kept as pending and replayed on every
// launch, showing "Referendum not found" each time the app opened.
@Test
fun `a fresh link that fails for good is not kept as pending`() = runBlocking {
rootWith(ReferendumHandlingException.ReferendumIsNotSpecified).handleDeepLink(link)
verify(pendingDeepLinkProvider).clear()
}
@Test
fun `a pending link that fails for good is dropped`() = runBlocking {
whenever(pendingDeepLinkProvider.get()).thenReturn(link)
rootWith(ReferendumHandlingException.ReferendumIsNotSpecified).checkAndHandlePendingDeepLink()
verify(pendingDeepLinkProvider).clear()
}
@Test
fun `a link that fails for another reason stays pending for a retry`() = runBlocking {
rootWith(IllegalStateException("not ready yet")).handleDeepLink(link)
verify(pendingDeepLinkProvider, never()).clear()
}
}
+1
View File
@@ -65,4 +65,5 @@ dependencies {
testImplementation jUnitDep
testImplementation mockitoDep
testImplementation project(':test-shared')
}
@@ -0,0 +1,39 @@
package io.novafoundation.nova.feature_governance_impl.presentation.referenda.details.deeplink
import android.net.Uri
import io.novafoundation.nova.common.utils.sequrity.AutomaticInteractionGate
import io.novafoundation.nova.feature_governance_api.data.MutableGovernanceState
import io.novafoundation.nova.feature_governance_impl.presentation.GovernanceRouter
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.test_shared.whenever
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.mockito.Mockito.mock
class ReferendumDeepLinkHandlerTest {
private val handler = ReferendumDeepLinkHandler(
router = mock(GovernanceRouter::class.java),
chainRegistry = mock(ChainRegistry::class.java),
mutableGovernanceState = mock(MutableGovernanceState::class.java),
automaticInteractionGate = mock(AutomaticInteractionGate::class.java)
)
private fun linkWithPath(path: String): Uri = mock(Uri::class.java).also {
whenever(it.path).thenReturn(path)
}
@Test
fun `matches a referendum link`() = runBlocking {
assertTrue(handler.matches(linkWithPath("/open/gov")))
}
// "/open/governance" starts with the referendum prefix "/open/gov"; matching it sent the
// governance banner link to the referendum screen, which failed without a referendum id.
@Test
fun `does not match a link that only starts with the referendum path`() = runBlocking {
assertFalse(handler.matches(linkWithPath("/open/governance")))
}
}