lundi 25 novembre 2019

Showing a Dialog(Dialog Fragment) inside a fragment in UI testing

I am writing UI test cases for a fragment. I am using launchFragmentInContainer to launch fragment independent of activity.

Scenario is, on click of a button, a dialog fragment should be shown but when I do that nothing appears on the screen.

This is my primary fragment

    package com.cbre.host.onboarding.locationaccess

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.navigation.fragment.findNavController
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.cbre.host.common.AppNavigator
import com.cbre.host.common.BaseFragment
import com.cbre.host.common.utils.Constants
import com.cbre.host.core.permission.PermissionProvider
import com.cbre.host.onboarding.R
import com.cbre.host.onboarding.databinding.LocationAccessFragmentBinding
import kotlinx.android.synthetic.main.location_access_fragment.*
import org.koin.android.ext.android.inject

class LocationAccessFragment : BaseFragment() {

    private lateinit var binding: LocationAccessFragmentBinding
    private val _viewModel: LocationAccessViewModel by fragmentViewModel()
    private val _permissionProvider: PermissionProvider by inject()
    private val _appNavigator: AppNavigator by inject()


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = LocationAccessFragmentBinding.inflate(inflater, container, false)
        binding.lifecycleOwner = viewLifecycleOwner
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        requireActivity().onBackPressedDispatcher.addCallback(
            viewLifecycleOwner,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    // DO NOTHING
                }
            })

        may_be_later.setOnClickListener { findNavController().navigate(R.id.next_action_a) }
        access_location.setOnClickListener { handleLocationAccessPermission() }
        tv_privacy_notice.setOnClickListener {
            _appNavigator.openInChrome(
                context!!,
                Constants.PRIVACY_URL
            )
        }
    }

    override fun invalidate() = withState(_viewModel) { state ->
        binding.run {
            buttonOneText = state.onBoardingContent.button1Text
            buttonTwoText = state.onBoardingContent.button2Text
            imageHelpText = state.onBoardingContent.imageHelpText
            imageText = state.onBoardingContent.imageText
            imageUrl = state.onBoardingContent.imageUrl
        }
    }

    private fun handleLocationAccessPermission() = activity?.let {
        _permissionProvider.checkSelfPermission(
            it,
            permission = Manifest.permission.ACCESS_FINE_LOCATION,
            requestPermission = { requestPermission() },
            granted = {
                findNavController().navigate(R.id.next_action_b)
            },
            shouldShowExplanation = { showDialog() })
    }

    private fun showDialog() {
        val fm = fragmentManager
        fm ?: return
        val dialogFragment = LocationAccessDialogFragment.newInstance()
        dialogFragment.show(fm, "locationAccessDialog")
        dialogFragment.callback = object : LocationAccessDialogFragment.Callback {
            override fun onAllow() {
                requestPermission()
            }
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        when (requestCode) {
            PermissionProvider.REQUEST_CODE -> {
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    findNavController().navigate(R.id.next_action_b)
                }
            }
        }
    }

    private fun requestPermission() = requestPermissions(
        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
        PermissionProvider.REQUEST_CODE
    )
}

This is my Dialog Fragment

package com.cbre.host.onboarding.locationaccess

import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import androidx.fragment.app.DialogFragment
import com.cbre.host.onboarding.databinding.LocationAccessDialogBinding


class LocationAccessDialogFragment : DialogFragment() {

    private lateinit var binding: LocationAccessDialogBinding
    var callback: Callback? = null

    interface Callback {
        fun onAllow()
    }

    companion object {
        fun newInstance() = LocationAccessDialogFragment()
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        binding =
            LocationAccessDialogBinding.inflate(LayoutInflater.from(activity), null, false)
        val builder = AlertDialog.Builder(activity)
            .setView(binding.root)

        val d = builder.create()

        d?.window?.decorView?.setBackgroundResource(android.R.color.transparent)

        binding.dontAllow.setOnClickListener {
            this.dismiss()
        }

        binding.allow.setOnClickListener {
            callback?.onAllow()
            this.dismiss()
        }
        return d
    }
}

and this is my test

@Test
fun a_checkBtnAccessLocationClickForDenyPermission() {
        val scenario = launchFragmentInContainer<LocationAccessFragment>()
        scenario.onFragment { fragment ->
            Navigation.setViewNavController(fragment.requireView(), navController)
        }

        onView(withId(R.id.access_location)).perform(click())
    }
}

Aucun commentaire:

Enregistrer un commentaire