Skip to content

Commit

Permalink
Further refinement of testActivity and testFragment
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaran Flaath committed Mar 10, 2021
1 parent 56c3eb2 commit ebd6f15
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ class EventuallyActivityLaunchedTest {
@Test
fun launchingActivitiesCanBeCheckedWitheventuallyActivityLaunched() {

testActivity(MainActivity::class) { scenario ->
testActivity(MainActivity::class) {

scenario.onActivity { activity ->
activity.button(R.id.buttonLaunchAnotherActivity).performClick()
onActivity {
button(R.id.buttonLaunchAnotherActivity).performClick()
}

eventuallyActivityLaunched(activity = AnotherActivity::class)
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class SampleFragmentWithKoinTest : KoinTest {
@Test
fun verifyDependencyCalledOnButtonClick() {

testFragment(SampleFragment::class) { scenario ->
scenario.withFragment {
testFragment(SampleFragment::class) {
withFragment {
val buttonforTesting = button(R.id.buttonForTesting)
buttonforTesting.performClick()
Assert.assertEquals("Changed text", buttonforTesting.text.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,21 @@ class TestActivityExampleTest {
@Test
fun demonstrateUseOfTestActivity() {

testActivity(MainActivity::class) { scenario ->
scenario.onActivity { activity ->
activity.button(R.id.buttonLaunchAnotherActivity).performClick()
testActivity(MainActivity::class) {
onActivity {
button(R.id.buttonLaunchAnotherActivity).performClick()
}

eventuallyActivityLaunched(activity = AnotherActivity::class)
}
}

@Test
fun demonstrateUseOfTestActivity2() {

testActivity(MainActivity::class) { scenario ->
scenario.onActivity { activity ->
activity.button(R.id.buttonHello).performClick()
assertEquals("Activity says hello.", activity.textView(R.id.textDemo).text.toString())
testActivity(MainActivity::class) {
onActivity {
button(R.id.buttonHello).performClick()
assertEquals("Activity says hello.", textView(R.id.textDemo).text.toString())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ class TestFragmentExampleTest {
@Test
fun demonstrateTestFragment() {

testFragment(SampleFragment::class) { scenario ->
scenario.withFragment {

testFragment(SampleFragment::class) {
withFragment {
button(R.id.buttonForTesting).performClick()
assertEquals("Changed text", button(R.id.buttonForTesting).text.toString())
}
Expand All @@ -25,8 +24,8 @@ class TestFragmentExampleTest {
fun demonstrateTestFragmentWithArgs() {

val expectedInitialText = "Hi there!"
testFragment(SampleFragment::class, bundleOf("initial_button_text" to expectedInitialText)) { scenario ->
scenario.withFragment {
testFragment(SampleFragment::class, bundleOf("initial_button_text" to expectedInitialText)) {
withFragment {
assertEquals(expectedInitialText, button(R.id.buttonForTesting).text.toString())
}
}
Expand Down
2 changes: 1 addition & 1 deletion darjeeling-android-testing/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ android {
minSdkVersion(21)
targetSdkVersion(30)
versionCode = gitInfo.count
versionName = "0.90.b3"
versionName = "0.90.b4"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,22 @@ import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.intent.Intents
import kotlin.reflect.KClass

fun <T : Activity> testActivity(activityClass: KClass<T>, perform: (ActivityScenario<T>) -> Unit) {
fun <T : Activity> testActivity(activityClass: KClass<T>, perform: ActivityScenario<T>.() -> Unit) {

Intents.init()
try {
ActivityScenario.launch(activityClass.java).use { activityScenario ->
perform(activityScenario)
}
ActivityScenario.launch(activityClass.java).use { it.perform() }
} finally {
Intents.release()
}
}

fun <F : Fragment> testFragment(fragmentClass: KClass<F>, args: Bundle = bundleOf(),
perform: (FragmentScenario<F>) -> Unit) {
perform: FragmentScenario<F>.() -> Unit) {

Intents.init()
try {
val scenario: FragmentScenario<F> = FragmentScenario.launchInContainer(fragmentClass.java, args)
perform(scenario)
FragmentScenario.launchInContainer(fragmentClass.java, args).perform()
} finally {
Intents.release()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,61 +10,130 @@ import androidx.cardview.widget.CardView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.testing.FragmentScenario
import androidx.fragment.app.testing.withFragment
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ActivityScenario

fun Activity.relativeLayout(@IdRes resId: Int): RelativeLayout = view(resId)
fun Fragment.relativeLayout(@IdRes resId: Int): RelativeLayout = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.relativeLayout(@IdRes resId: Int): RelativeLayout = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.relativeLayout(@IdRes resId: Int): RelativeLayout = view(resId)

fun Activity.constraintLayout(@IdRes resId: Int): ConstraintLayout = view(resId)
fun Fragment.constraintLayout(@IdRes resId: Int): ConstraintLayout = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.constraintLayout(@IdRes resId: Int): ConstraintLayout =
view(resId)

inline fun <reified A : Activity> ActivityScenario<A>.constraintLayout(@IdRes resId: Int): ConstraintLayout =
view(resId)

fun Activity.linearLayout(@IdRes resId: Int): LinearLayout = view(resId)
fun Fragment.linearLayout(@IdRes resId: Int): LinearLayout = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.linearLayout(@IdRes resId: Int): LinearLayout = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.linearLayout(@IdRes resId: Int): LinearLayout = view(resId)

fun Activity.cardView(@IdRes resId: Int): CardView = view(resId)
fun Fragment.cardView(@IdRes resId: Int): CardView = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.cardView(@IdRes resId: Int): CardView = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.cardView(@IdRes resId: Int): CardView = view(resId)

fun Activity.progressBar(@IdRes resId: Int): ProgressBar = view(resId)
fun Fragment.progressBar(@IdRes resId: Int): ProgressBar = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.progressBar(@IdRes resId: Int): ProgressBar = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.progressBar(@IdRes resId: Int): ProgressBar = view(resId)

fun Activity.editText(@IdRes resId: Int): EditText = view(resId)
fun Fragment.editText(@IdRes resId: Int): EditText = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.editText(@IdRes resId: Int): EditText = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.editText(@IdRes resId: Int): EditText = view(resId)

fun Activity.textView(@IdRes resId: Int): TextView = view(resId)
fun Fragment.textView(@IdRes resId: Int): TextView = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.textView(@IdRes resId: Int): TextView = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.textView(@IdRes resId: Int): TextView = view(resId)

fun Activity.button(@IdRes resId: Int): Button = view(resId)
fun Fragment.button(@IdRes resId: Int): Button = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.button(@IdRes resId: Int): Button = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.button(@IdRes resId: Int): Button = view(resId)

fun Activity.imageButton(@IdRes resId: Int): ImageButton = view(resId)
fun Fragment.imageButton(@IdRes resId: Int): ImageButton = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.imageButton(@IdRes resId: Int): ImageButton = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.imageButton(@IdRes resId: Int): ImageButton = view(resId)

fun Activity.imageView(@IdRes resId: Int): ImageView = view(resId)
fun Fragment.imageView(@IdRes resId: Int): ImageView = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.imageView(@IdRes resId: Int): ImageView = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.imageView(@IdRes resId: Int): ImageView = view(resId)

fun Activity.checkBox(@IdRes resId: Int): CheckBox = view(resId)
fun Fragment.checkBox(@IdRes resId: Int): CheckBox = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.checkBox(@IdRes resId: Int): CheckBox = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.checkBox(@IdRes resId: Int): CheckBox = view(resId)

fun Activity.recyclerView(@IdRes resId: Int): RecyclerView = view(resId)
fun Fragment.recyclerView(@IdRes resId: Int): RecyclerView = view(resId)
inline fun <reified F : Fragment> FragmentScenario<F>.recyclerView(@IdRes resId: Int): RecyclerView = view(resId)
inline fun <reified A : Activity> ActivityScenario<A>.recyclerView(@IdRes resId: Int): RecyclerView = view(resId)

fun <T : View> Activity.view(@IdRes resId: Int): T = this.findViewById(resId)
fun <T : View> Fragment.view(@IdRes resId: Int): T = this.requireActivity().findViewById(resId)
inline fun <T : View, reified F : Fragment> FragmentScenario<F>.view(@IdRes resId: Int): T =
this.withFragment { this.requireActivity().findViewById(resId) }

fun <T : View, A : Activity> ActivityScenario<A>.view(@IdRes resId: Int): T {
lateinit var view: T
this.onActivity {
view = it.view(resId)
}
return view
}

fun Activity.string(@StringRes stringResId: Int): String =
this.resources.getString(stringResId)

fun Fragment.string(@StringRes stringResId: Int): String =
this.resources.getString(stringResId)

inline fun <reified F : Fragment> FragmentScenario<F>.string(@StringRes stringResId: Int): String =
withFragment { resources.getString(stringResId) }

inline fun <reified A : Activity> ActivityScenario<A>.string(@StringRes stringResId: Int): String {
lateinit var string: String
onActivity { string = it.resources.getString(stringResId) }
return string
}

fun Activity.drawable(@DrawableRes resId: Int): Drawable? =
ResourcesCompat.getDrawable(this.resources, resId, this.theme)

fun Fragment.drawable(@DrawableRes resId: Int): Drawable? =
ResourcesCompat.getDrawable(this.resources, resId, this.requireContext().theme)

inline fun <reified F : Fragment> FragmentScenario<F>.drawable(@DrawableRes resId: Int): Drawable? =
withFragment { resources.getDrawable(resId, this.requireContext().theme) }

inline fun <reified A : Activity> ActivityScenario<A>.drawable(@DrawableRes resId: Int): Drawable? {
var drawable: Drawable? = null
onActivity { drawable = ResourcesCompat.getDrawable(it.resources, resId, it.theme) }
return drawable
}

@RequiresApi(Build.VERSION_CODES.M)
fun Activity.color(@ColorRes resId: Int): Int = this.resources.getColor(resId, this.theme)

@RequiresApi(Build.VERSION_CODES.M)
fun Fragment.color(@ColorRes resId: Int): Int = this.resources.getColor(resId, this.requireContext().theme)
fun Fragment.color(@ColorRes resId: Int): Int = this.resources.getColor(resId, this.requireContext().theme)

@RequiresApi(Build.VERSION_CODES.M)
inline fun <reified F : Fragment> FragmentScenario<F>.color(@ColorRes resId: Int): Int =
withFragment { this.resources.getColor(resId, this.requireContext().theme) }

@RequiresApi(Build.VERSION_CODES.M)
inline fun <reified A : Activity> ActivityScenario<A>.color(@ColorRes resId: Int): Int {
var color: Int = 0
onActivity { color = it.resources.getColor(resId, it.theme) }
return color
}
26 changes: 18 additions & 8 deletions docs/userguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
Running tests on a fragment is done with the `testFragment` method:

```
testFragment(SampleFragment::class) { scenario ->
scenario.withFragment {
testFragment(SampleFragment::class) {
withFragment {
// TODO perform operations on the fragment and assertions here
}
}
Expand All @@ -17,8 +17,8 @@ You can find more documentation on testing fragments [here](https://developer.an
## Running activity tests

```
testActivity(MainActivity::class) { scenario ->
scenario.onActivity { activity ->
testActivity(MainActivity::class) {
onActivity { activity ->
// TODO perform operations on the activity and assertions here
}
}
Expand Down Expand Up @@ -60,10 +60,20 @@ was displayed to the user.

Darjeeling provides both Activity and Fragment tests with useful methods for looking up and interacting with your view components.

These are available as extension methods on the activity or fragment obtained from the respective scenarios.
These are available as extension methods for fragments and activities.

Example:
```
fragment.button(R.id.yourButton).performClick()
fragment.textView(R.id.textField).text = "New text"
activity.imageView(R.id.textField).background = ...
testFragment(MyFragment::class) {
withFragment {
textView(R.id.textField).text = "New text"
button(R.id.yourButton).performClick()
}
}
testActivity(MyActivity:class) {
onActivity {
imageView(R.id.textField).background = ...
}
}
```

0 comments on commit ebd6f15

Please sign in to comment.