Last active
February 5, 2021 08:37
-
-
Save marcellogalhardo/9c111ff481e6718da3c1553f795174b9 to your computer and use it in GitHub Desktop.
A simple scenario to run test against a view in a isolated fragment container.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Launches a [View] in an [ViewHostFragment] root view container (onCreateView). | |
* [ViewHostFragment] is hosted by an empty [FragmentActivity] which will [instantiate] | |
* the [Fragment] and waits for it to reach a resumed state. | |
* | |
* If your testing [View] has a dependency to specific theme such as [R.style.Theme_AppCompat], | |
* use the theme ID parameter in [launchViewInFragment] method. | |
* | |
* Usage example: | |
* | |
* ``` | |
* launchViewInFragment { Button(context) } | |
* .onFragment { | |
* onView(instanceOf(Button::class.java)).check(matches(not(isEnabled()))) | |
* } | |
* ``` | |
* | |
* @param themeResId a style resource id to be set to the host [Activity]'s theme | |
* @param instantiate method which will be used to instantiate the [View] when | |
* [ViewHostFragment.onCreateView] is invoked. | |
* | |
* @see FragmentScenario for more details. | |
*/ | |
fun <T : View> launchViewInFragment( | |
@StyleRes themeResId: Int = R.style.FragmentScenarioEmptyFragmentActivityTheme, | |
instantiate: ViewFactory<T> | |
): FragmentScenario<ViewHostFragment<T>> = launchFragmentInContainer( | |
themeResId = themeResId, | |
instantiate = { ViewHostFragment(instantiate) } | |
) | |
typealias ViewFactory<T> = (ViewBuilder) -> T | |
/** | |
* Runs the function on the main thread in a blocking way. | |
* | |
* In the lambda you have access to the view that is tested | |
*/ | |
fun <T : View> FragmentScenario<ViewHostFragment<T>>.onView(action: (T) -> Unit): FragmentScenario<ViewHostFragment<T>> { | |
onFragment { fragment -> action(requireNotNull(fragment.viewInTest)) } | |
return this | |
} | |
/** | |
* An empty [Fragment]. This [Fragment] is used to host a [View] in [launchViewInFragment]. | |
* | |
* @see [launchViewInFragment] for more details. | |
*/ | |
class ViewHostFragment <T : View>( | |
private val viewFactory: ViewFactory<T> | |
) : Fragment() { | |
internal var viewInTest: T? = null | |
override fun onCreateView( | |
inflater: LayoutInflater, | |
container: ViewGroup?, | |
savedInstanceState: Bundle? | |
): View { | |
val args = ViewBuilder(requireContext(), inflater, container, savedInstanceState) | |
return viewFactory(args).also { viewInTest = it } | |
} | |
override fun onDestroyView() { | |
viewInTest = null | |
super.onDestroyView() | |
} | |
} | |
/** | |
* [ViewBuilder] is a generic builder of [View]'s which will be invoked | |
* when [ViewHostFragment.onViewCreated] is invoked. | |
* | |
* @see launchViewInFragment for more details. | |
*/ | |
data class ViewBuilder internal constructor( | |
val context: Context, | |
val inflater: LayoutInflater, | |
val container: ViewGroup? = null, | |
val savedInstanceState: Bundle? = null | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment