Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions android-snaptesting/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation(libs.androidx.test.monitor)
implementation(libs.androidx.test.runner)
implementation(libs.androidx.ui.test.junit4.android)
implementation(libs.espresso.core)
}

apply("${rootProject.projectDir}/mavencentral.gradle")
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ import android.app.Activity
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Looper
import android.view.View
import android.widget.EditText
import android.widget.HorizontalScrollView
import android.widget.ScrollView
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onRoot
import androidx.test.espresso.Espresso
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.screenshot.Screenshot
import com.dropbox.differ.ImageComparator
import com.dropbox.differ.Mask
Expand Down Expand Up @@ -62,6 +69,10 @@ public class ScreenshotsRule(
activity: Activity,
name: String? = null,
) {
val view = activity.findViewById<View>(android.R.id.content)

disableFlakyComponentsAndWaitForIdle(view)

val bitmap = Screenshot.capture(activity).bitmap
compareScreenshot(bitmap, name)
}
Expand Down Expand Up @@ -141,4 +152,58 @@ public class ScreenshotsRule(
)
}
}

private fun disableFlakyComponentsAndWaitForIdle(view: View? = null) {
if (view != null) {
disableAnimatedComponents(view)
}
if (notInAppMainThread()) {
waitForAnimationsToFinish()
}
}

private fun disableAnimatedComponents(view: View) {
runOnUi {
hideEditTextCursors(view)
hideScrollViewBars(view)
}
}

private fun hideEditTextCursors(view: View) {
view.childrenViews<EditText>().forEach {
it.isCursorVisible = false
}
}

private fun hideScrollViewBars(view: View) {
view.childrenViews<ScrollView>().forEach {
hideViewBars(it)
}

view.childrenViews<HorizontalScrollView>().forEach {
hideViewBars(it)
}
}

private fun hideViewBars(it: View) {
it.isHorizontalScrollBarEnabled = false
it.isVerticalScrollBarEnabled = false
it.overScrollMode = View.OVER_SCROLL_NEVER
}

public fun waitForAnimationsToFinish() {
getInstrumentation().waitForIdleSync()
Espresso.onIdle()
}

public fun runOnUi(block: () -> Unit) {
if (notInAppMainThread()) {
getInstrumentation().runOnMainSync { block() }
} else {
block()
}
}

private fun notInAppMainThread() = Looper.myLooper() != Looper.getMainLooper()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.telefonica.androidsnaptesting.screenshots

import android.view.View
import android.view.ViewGroup

@Suppress("UNCHECKED_CAST")
public inline fun <reified T : View> View.childrenViews(): List<T> = filterChildrenViews {
it is T
} as List<T>

public fun View.filterChildrenViews(filter: (View) -> Boolean): List<View> {
val children = mutableSetOf<View>()
val view = this
if (view !is ViewGroup) {
if (filter.invoke(view)) {
children.add(view)
}
} else {
for (i in 0 until view.childCount) {
view.getChildAt(i).let {
children.addAll(it.filterChildrenViews(filter))
if (filter.invoke(it)) {
children.add(it)
}
}
}
}

return children.toList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.telefonica.androidsnaptesting

import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.telefonica.androidsnaptesting.logs.LogsRecorder
import com.telefonica.androidsnaptesting.logs.LogsRule
import com.telefonica.androidsnaptesting.screenshots.ScreenshotsRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand Down