Skip to content

Commit

Permalink
Merge pull request #230 from rubensousa/api_level_tests
Browse files Browse the repository at this point in the history
Run UI tests in more API levels
  • Loading branch information
rubensousa authored Jun 19, 2024
2 parents f689f65 + 6629dca commit d9fe261
Show file tree
Hide file tree
Showing 26 changed files with 224 additions and 120 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
matrix:
arch: [ x86 ]
target: [ android-tv ]
api-level: [27]
api-level: [27, 28, 29, 30, 31]
profile: [tv_1080p]
steps:
- name: checkout
Expand Down
1 change: 0 additions & 1 deletion dpadrecyclerview-compose/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments useTestStorageService: 'true'
testInstrumentationRunnerArguments additionalTestOutputDir: 'storage/emulated/0/recordings/com.rubensousa.dpadrecyclerview.compose.test'
testInstrumentationRunnerArguments listener: 'com.rubensousa.dpadrecyclerview.testfixtures.recording.TestRecordingListener'
}

buildTypes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,24 @@ import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.ExtraLayoutSpaceStrategy
import com.rubensousa.dpadrecyclerview.compose.test.ComposeFocusTestActivity
import com.rubensousa.dpadrecyclerview.testfixtures.DpadFocusEvent
import com.rubensousa.dpadrecyclerview.testfixtures.recording.ScreenRecorderRule
import com.rubensousa.dpadrecyclerview.testing.KeyEvents
import com.rubensousa.dpadrecyclerview.testing.R
import com.rubensousa.dpadrecyclerview.testing.actions.DpadRecyclerViewActions
import com.rubensousa.dpadrecyclerview.testing.actions.DpadViewActions
import com.rubensousa.dpadrecyclerview.testing.rules.DisableIdleTimeoutRule
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class DpadComposeFocusViewHolderTest {

@get:Rule
val idleTimeoutRule = DisableIdleTimeoutRule()

@get:Rule
val screenRecorderRule = ScreenRecorderRule()

@get:Rule
val composeTestRule = createAndroidComposeRule<ComposeFocusTestActivity>()

@Before
fun setup() {
composeTestRule.waitForIdle()
}

@Test
fun testFirstItemHasFocus() {
assertFocus(item = 0, isFocused = true)
Expand Down Expand Up @@ -113,6 +111,7 @@ class DpadComposeFocusViewHolderTest {

@Test
fun testCompositionIsNotClearedWhenDetachingFromWindow() {
// given
composeTestRule.activityRule.scenario.onActivity { activity ->
activity.getRecyclerView()
.setExtraLayoutSpaceStrategy(object : ExtraLayoutSpaceStrategy {
Expand All @@ -121,19 +120,24 @@ class DpadComposeFocusViewHolderTest {
}
})
}

// when
repeat(3) {
KeyEvents.pressDown()
waitForIdleScroll()
}

// then
composeTestRule.onNodeWithText("0").assertExists()
composeTestRule.onNodeWithText("0").assertIsNotDisplayed()
}

@Test
fun testCompositionIsClearedWhenViewHolderIsRecycled() {
KeyEvents.pressDown(times = 10)
waitForIdleScroll()
repeat(times = 10) {
KeyEvents.pressDown()
waitForIdleScroll()
}

composeTestRule.onNodeWithText("0").assertDoesNotExist()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.ExtraLayoutSpaceStrategy
import com.rubensousa.dpadrecyclerview.compose.test.ViewFocusTestActivity
import com.rubensousa.dpadrecyclerview.testfixtures.DpadFocusEvent
import com.rubensousa.dpadrecyclerview.testfixtures.recording.ScreenRecorderRule
import com.rubensousa.dpadrecyclerview.testing.KeyEvents
import com.rubensousa.dpadrecyclerview.testing.R
import com.rubensousa.dpadrecyclerview.testing.actions.DpadRecyclerViewActions
Expand All @@ -40,9 +39,6 @@ import org.junit.Test

class DpadComposeViewHolderTest {

@get:Rule
val screenRecorderRule = ScreenRecorderRule()

@get:Rule
val composeTestRule = createAndroidComposeRule<ViewFocusTestActivity>()

Expand Down Expand Up @@ -131,8 +127,10 @@ class DpadComposeViewHolderTest {

@Test
fun testCompositionIsClearedWhenViewHolderIsRecycled() {
KeyEvents.pressDown(times = 10)
waitForIdleScroll()
repeat(times = 10) {
KeyEvents.pressDown()
waitForIdleScroll()
}

composeTestRule.onNodeWithText("0").assertDoesNotExist()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,23 +98,20 @@ class ComposeFocusTestActivity : AppCompatActivity() {
parent: ViewGroup,
viewType: Int
): DpadComposeFocusViewHolder<Int> {
return DpadComposeFocusViewHolder(
parent = parent,
content = { item ->
TestComposableFocus(
modifier = Modifier
.fillMaxWidth()
.height(150.dp),
item = item,
onClick = {
clicks.add(item)
},
onDispose = {
onDispose(item)
}
)
},
)
return DpadComposeFocusViewHolder(parent) { item ->
TestComposableFocus(
modifier = Modifier
.fillMaxWidth()
.height(150.dp),
item = item,
onClick = {
clicks.add(item)
},
onDispose = {
onDispose(item)
}
)
}
}

override fun getItemCount(): Int = items.size
Expand All @@ -123,5 +120,9 @@ class ComposeFocusTestActivity : AppCompatActivity() {
holder.setItemState(items[position])
}

override fun onViewRecycled(holder: DpadComposeFocusViewHolder<Int>) {
holder.setItemState(null)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ class DpadComposeFocusViewHolder<T>(

fun setFocusable(focusable: Boolean) {
composeView.apply {
isFocusable = focusable
isFocusableInTouchMode = focusable
descendantFocusability = if (focusable) {
ViewGroup.FOCUS_AFTER_DESCENDANTS
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ internal class DpadComposeView @JvmOverloads constructor(
init {
addView(composeView)
clipChildren = false
composeView.isFocusable = false
composeView.isFocusableInTouchMode = false
super.setOnFocusChangeListener(internalFocusListener)
}

Expand All @@ -53,8 +55,6 @@ internal class DpadComposeView @JvmOverloads constructor(
dispatchFocusToComposable: Boolean
) {
if (dispatchFocusToComposable) {
composeView.isFocusable = isFocusable
composeView.isFocusableInTouchMode = isFocusable
composeView.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
this.isFocusable = false
this.isFocusableInTouchMode = false
Expand Down
1 change: 0 additions & 1 deletion dpadrecyclerview-testing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments useTestStorageService: 'true'
testInstrumentationRunnerArguments additionalTestOutputDir: 'storage/emulated/0/recordings/com.rubensousa.dpadrecyclerview.testing.test'
testInstrumentationRunnerArguments listener: 'com.rubensousa.dpadrecyclerview.testfixtures.recording.TestRecordingListener'
multiDexEnabled true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,33 @@ class KeyEventsTest : RecyclerViewTest() {
fun testFastHorizontalScroll() {
launchGridFragment()
Espresso.onIdle()
performActions(DpadRecyclerViewActions.waitForAdapterUpdate())

KeyEvents.pressRight(times = 10)
assert(DpadRecyclerViewAssertions.isFocused(position = 10))
KeyEvents.pressRight(times = 8)
performActions(DpadRecyclerViewActions.waitForIdleScroll())

assert(DpadRecyclerViewAssertions.isFocused(position = 8))

KeyEvents.pressLeft(times = 8)
performActions(DpadRecyclerViewActions.waitForIdleScroll())
KeyEvents.pressLeft(times = 10)

assert(DpadRecyclerViewAssertions.isFocused(position = 0))
}

@Test
fun testFastVerticalScroll() {
launchGridFragment()
Espresso.onIdle()
performActions(DpadRecyclerViewActions.waitForAdapterUpdate())

KeyEvents.pressDown(times = 5)
performActions(DpadRecyclerViewActions.waitForIdleScroll())

assert(DpadRecyclerViewAssertions.isFocused(position = 5 * 5))

performActions(DpadRecyclerViewActions.waitForIdleScroll())
KeyEvents.pressUp(times = 5)
performActions(DpadRecyclerViewActions.waitForIdleScroll())

assert(DpadRecyclerViewAssertions.isFocused(position = 0))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,12 @@ import androidx.test.espresso.ViewAssertion
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.matcher.ViewMatchers
import com.google.common.truth.Truth.assertThat
import com.rubensousa.dpadrecyclerview.testfixtures.recording.ScreenRecorderRule
import org.junit.Rule

abstract class RecyclerViewTest {

private lateinit var subPositionFragment: FragmentScenario<DpadSubPositionFragment>
private lateinit var gridFragment: FragmentScenario<DpadGridFragment>

@get:Rule
val screenRecordingRule = ScreenRecorderRule()

protected fun onGridFragment(block: (fragment: DpadGridFragment) -> Unit) {
gridFragment.onFragment { fragment ->
block(fragment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import android.os.SystemClock
import android.view.KeyEvent
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import kotlin.math.max

object KeyEvents {

Expand All @@ -31,8 +32,9 @@ object KeyEvents {
fun pressKey(key: Int, times: Int = 1, delay: Long = DEFAULT_KEY_PRESS_DELAY) {
repeat(times) {
device.pressKeyCode(key)
if (delay > 0) {
SystemClock.sleep(delay)
if (times > 1) {
val actualDelay = max(25L, delay)
SystemClock.sleep(actualDelay)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class TestNestedListFragment : Fragment(R.layout.dpadrecyclerview_test_container
onViewFocusedListener: OnViewFocusedListener,
) : RecyclerView.ViewHolder(view) {

val adapter = TestAdapter(
val adapter = TestAdapter(
adapterConfiguration = configuration,
onViewHolderSelected = { position -> },
onViewHolderDeselected = { position -> }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ import com.rubensousa.dpadrecyclerview.test.TestAdapterConfiguration
import com.rubensousa.dpadrecyclerview.test.helpers.assertFocusAndSelection
import com.rubensousa.dpadrecyclerview.test.helpers.onRecyclerView
import com.rubensousa.dpadrecyclerview.test.helpers.waitForCondition
import com.rubensousa.dpadrecyclerview.test.helpers.waitForIdleScrollState
import com.rubensousa.dpadrecyclerview.testing.KeyEvents
import com.rubensousa.dpadrecyclerview.testing.R
import org.junit.Before
import org.junit.Test

class DragHelperGridTest {


private lateinit var fragmentScenario: FragmentScenario<RecyclerViewFragment>
private lateinit var dragHelper: DpadDragHelper<Int>
private lateinit var testAdapter: TestAdapter
Expand Down Expand Up @@ -94,7 +94,10 @@ class DragHelperGridTest {
startDragging(position = 0)

// when
KeyEvents.pressRight(times = spanCount)
repeat(spanCount) {
KeyEvents.pressRight()
waitForIdleScrollState()
}

// then
assertFocusAndSelection(position = endRowPosition)
Expand All @@ -114,7 +117,10 @@ class DragHelperGridTest {
startDragging(position = endRowPosition)

// when
KeyEvents.pressLeft(times = spanCount)
repeat(spanCount) {
KeyEvents.pressLeft()
waitForIdleScrollState()
}

// then
assertFocusAndSelection(position = 0)
Expand All @@ -135,7 +141,7 @@ class DragHelperGridTest {
startDragging(position = topColumnPosition)

// when
KeyEvents.pressDown(times = 1)
KeyEvents.pressDown()

// then
assertFocusAndSelection(position = bottomColumnPosition)
Expand All @@ -157,7 +163,7 @@ class DragHelperGridTest {
startDragging(position = bottomColumnPosition)

// when
KeyEvents.pressUp(times = 1)
KeyEvents.pressUp()

// then
assertFocusAndSelection(position = topColumnPosition)
Expand All @@ -177,8 +183,14 @@ class DragHelperGridTest {
startDragging(position = 0)

// when
KeyEvents.pressDown(times = numberOfItems / spanCount)
KeyEvents.pressRight(times = spanCount)
repeat(numberOfItems / spanCount) {
KeyEvents.pressDown()
waitForIdleScrollState()
}
repeat(spanCount) {
KeyEvents.pressRight()
waitForIdleScrollState()
}

// then
assertFocusAndSelection(position = numberOfItems - 1)
Expand All @@ -196,8 +208,14 @@ class DragHelperGridTest {
startDragging(position = numberOfItems - 1)

// when
KeyEvents.pressUp(times = numberOfItems / spanCount)
KeyEvents.pressLeft(times = spanCount)
repeat(numberOfItems / spanCount) {
KeyEvents.pressUp()
waitForIdleScrollState()
}
repeat(spanCount) {
KeyEvents.pressLeft()
waitForIdleScrollState()
}

// then
assertFocusAndSelection(position = 0)
Expand All @@ -215,12 +233,6 @@ class DragHelperGridTest {
}
}

private fun stopDragging() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
dragHelper.stopDrag()
}
}

private fun launchFragment(): FragmentScenario<RecyclerViewFragment> {
return launchFragmentInContainer<RecyclerViewFragment>(
themeResId = R.style.DpadRecyclerViewTestTheme
Expand Down
Loading

0 comments on commit d9fe261

Please sign in to comment.