nord vpnnord vpn
Ad

Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
7.8 kB
2
Indexable
Never
package ru.tensor.sbis.business.payment_draft.impl.ui.host

import android.app.Application
import android.content.pm.ActivityInfo
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import org.mockito.kotlin.*
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyString
import org.robolectric.RobolectricTestRunner
import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
import ru.tensor.sbis.android_ext_decl.viewprovider.OverlayFragmentHolder
import ru.tensor.sbis.base_components.fragment.ActivityOverlayFragmentHolder
import ru.tensor.sbis.business.payment.decl.data.PaymentDocType
import ru.tensor.sbis.business.payment_draft.decl.data.EditPayment
import ru.tensor.sbis.common.testing.mockStatic
import ru.tensor.sbis.common.util.ResourceProvider
import ru.tensor.sbis.design.utils.KeyboardUtils
import java.util.*
import ru.tensor.sbis.design.R as RDesign
import android.os.Bundle
import android.os.Looper
import ru.tensor.sbis.mvvm.utils.retain.FragmentAttendant

@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.R])
internal class PaymentDraftHostRouterTest {

    private val mockResourceProvider = mock<ResourceProvider> {
        on { getString(any()) } doReturn ""
    }
    private lateinit var router: PaymentDraftHostRouter
    private lateinit var mockFragmentManager: FragmentManager
    private var mockFragmentTransaction: FragmentTransaction = mock {
        on { commit() } doReturn 0
    }
    private lateinit var mockFragmentAttendant: FragmentAttendant
    private var returnFragment = true

    private var backStackCount = 1

    @After
    fun tearDown() {
        backStackCount = 1
        returnFragment = true
    }

    @Test
    fun `On bind router to fragment verify that it has acquired lifecycle handler`() {
        launchDefaultScenario()
        assertFalse(router.hasLifecycleHandler)

        val hostFragment = spy(Fragment())
        router.bind(hostFragment)
        assertTrue(router.hasLifecycleHandler)
    }

    @Test
    fun `On goBack() if allowed to pop back stack, then pop last back stack state`() {
        launchDefaultScenario()
        router.goBack()

        verify(mockFragmentManager).popBackStackImmediate()
    }

    @Test
    fun `On goBack() if can't pop back stack and return confirmed then remove fragment`() {
        launchDefaultScenario {
            backStackCount = 0
            router.isReturnConfirmed = true

            router.goBack()

            verify(it).removeFragment()
        }
    }

    @Test
    fun `On goBack() if can't pop back stack and return not confirmed then show interrupt dialog`() {
        launchDefaultScenario()
        backStackCount = 0
        router.isReturnConfirmed = false

        router.goBack()
        shadowOf(Looper.getMainLooper()).idle()

        verify(router).showInterruptDialog(argThat {
            // При нажатии на кнопку "ОК", послать событие onConfirmationGoBack
            invoke()
            router.onConfirmationGoBackFlow.replayCache.isNotEmpty()
        })
    }

    @Test
    fun `On showPaymentDraft() show new screen with correct transaction`() {
        launchDefaultScenario()
        val args = EditPayment(UUID.randomUUID(), PaymentDocType.BANK)

        returnFragment = false
        router.showPaymentDraft(args)

        verify(router).runCommandSticky(any())
        verify(mockFragmentManager, atLeastOnce()).beginTransaction() // первый раз при моке, второй раз боевой

        verify(mockFragmentTransaction, never()).addToBackStack(anyString()) // не добавляем документ в backstack
        verify(mockFragmentTransaction, never()).setMaxLifecycle(any(), eq(Lifecycle.State.STARTED)) // currentToPause = false
        verify(mockFragmentTransaction).setCustomAnimations(0, 0, 0, 0) // без анимации
    }

    @Test
    fun `On showExpenseItems() show with animation and hide keyboard`() {
        launchDefaultScenario()
        var keyboardIsHidden = false
        mockStatic<KeyboardUtils> {
            on<Unit> { KeyboardUtils.hideKeyboard(any()) } doAnswer { keyboardIsHidden = true }
        }

        doNothing().whenever(router).closeDraftKeyboard()
        router.showExpenseItems()

        assertTrue(keyboardIsHidden)
        verify(mockFragmentManager, times(2)).beginTransaction() // первый раз при моке, второй раз боевой
        verify(mockFragmentTransaction).addToBackStack(anyString()) // добавляем в backstack
        verify(mockFragmentTransaction).setCustomAnimations( // с анимацией справа налево
            RDesign.anim.right_in,
            RDesign.anim.right_out,
            RDesign.anim.right_in,
            RDesign.anim.right_out
        )
    }

    private fun launchDefaultScenario(onActivityVerifier: ((TestActivity) -> Unit)? = null) {
        val appContext: Application = ApplicationProvider.getApplicationContext()
        val activityInfo = ActivityInfo().apply {
            name = TestActivity::class.java.name
            packageName = appContext.packageName
        }
        shadowOf(appContext.packageManager).addOrUpdateActivity(activityInfo)

        ActivityScenario.launch(TestActivity::class.java).apply {
            moveToState(Lifecycle.State.RESUMED)
        }.onActivity { testActivity ->
            val fragment = spy(Fragment()) {
                on { activity } doReturn testActivity
            }
            mockFragmentAttendant = mock {
                on { component } doReturn fragment
            }
            testActivity.showFragmentWithCommit(fragment, false)
            mockFragmentManager = spy(fragment.parentFragmentManager) {
                on { backStackEntryCount } doAnswer { backStackCount }
                //on { beginTransaction() } doReturn mockFragmentTransaction
                on { findFragmentByTag(any()) } doAnswer { fragment.takeIf { returnFragment } }
            }
            router = spy(PaymentDraftHostRouter(mock(), mockResourceProvider, mockFragmentAttendant))
            router.resume(fragment, mockFragmentManager)
            onActivityVerifier?.invoke(spy(testActivity))
        }
    }

    private fun TestActivity.showFragmentWithCommit(
        fragment: Fragment, swipeable: Boolean
    ) {
        setFragment(fragment, swipeable)
    }
}

internal class TestActivity : AppCompatActivity(), OverlayFragmentHolder {

    private val spyActivityOverlayFragmentHolder = ActivityOverlayFragmentHolder(this)

    override fun onPostCreate(savedInstanceState: Bundle?) {
        setTheme(RDesign.style.AppTheme)
        super.onPostCreate(savedInstanceState)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setTheme(RDesign.style.AppTheme)
        setContentView(ru.tensor.sbis.business.payment_draft.impl.test.R.layout.payment_draft_activity_main)
    }
    override fun setFragment(fragment: Fragment, swipeable: Boolean)
        = spyActivityOverlayFragmentHolder.setFragment(fragment, swipeable)
    override fun hasFragment() = spyActivityOverlayFragmentHolder.hasFragment()
    override fun removeFragment() = spyActivityOverlayFragmentHolder.removeFragment()
    override fun handlePressed() = spyActivityOverlayFragmentHolder.handlePressed()
}

nord vpnnord vpn
Ad