Android Espresso - Как проверить, готов ли вид к щелчку - PullRequest
0 голосов
/ 29 мая 2020

У меня есть приложение с заставкой, которая остается около 2 секунд.

После этого оно переключается на другое действие A. В A я устанавливаю значение в SeekBar, а после этого щелкаю Button для подтверждения.

Когда я просто запускаю записанный тест эспрессо, делая это, он пытается воспроизвести, пока заставка. Поэтому, когда он пытался установить значение SeekBar или щелкнуть Button, я получил NoMatchingViewException. Итак, моей первой попыткой исправить это было просто добавить sleep(5000). Это сработало.

Однако я не хочу переводить в спящий режим вручную после каждого переключения активности.

  1. Потому что это кажется ненужным кодом
  2. Потому что это будет означать ненужное время ожидания для запуска теста
  3. Время может быть произвольным и может отличаться для разных устройств

Поэтому я попытался проверить, прав ли я Активность / может видеть правильные просмотры. Я сделал это с помощью некоторых ссылок SO: Ожидание активности и Ожидание просмотра .

Однако даже это не работает на 100%.

У меня есть две функции:

fun <T: AppCompatActivity> waitForActivity(activity: Class<T>, timeout: Int = 5000, waitTime: Int = 100) {
    val maxTries = timeout / waitTime
    var tries = 0

    for(i in 0..maxTries) {
        var currentActivity: Activity? = null
        getInstrumentation().runOnMainSync { run { currentActivity = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
            Stage.RESUMED).elementAtOrNull(0) } }
        if(activity.isInstance(currentActivity)) {
            break
        } else {
            tries++
            sleep(waitTime.toLong())
        }
    }
}
fun waitForView(
    @IntegerRes id: Int,
    waitMillis: Int = 5000,
    waitMillisPerTry: Long = 100
): ViewInteraction {

    // Derive the max tries
    val viewMatcher = allOf(
        withId(id),
        isDisplayed()
    )
    val maxTries = waitMillis / waitMillisPerTry.toInt()
    var tries = 0
    for (i in 0..maxTries)
        try {
            tries++
            val element = onView(viewMatcher)
            element.check { view, noViewFoundException ->
                if(view == null) {
                    throw noViewFoundException ?: Exception("TEST")
                }
                if(view.hasWindowFocus()) {
                    throw noViewFoundException ?: Exception("TEST2")
                }
            }
            return element
        } catch (e: Exception) {
            if (tries == maxTries) {
                throw e
            }
            sleep(waitMillisPerTry)
        }
    throw Exception("Error finding a view matching $viewMatcher")
}

Ни одна из них не работает на 100%. Оба они, кажется, возвращаются в рамках ограничений тайм-аута и «нашли» действие / представление. Однако ожидаемый вид, например Button, еще не готов к выполнению, например, element.perform(click()). Это не приводит к NoMatchingViewException, но и не выполняет щелчок, который я сделал. Для SeekBar я использую это:

private fun setSeekValue(seekBar: ViewInteraction, age: Int) {
        val fullPercentage = .9f
        val step = 1/99f

        seekBar.perform(
            GeneralClickAction(
                Tap.SINGLE,
                CoordinatesProvider { view ->
                    val pos = IntArray(2)
                    view?.getLocationOnScreen(pos)
                    FloatArray(2).apply {
                        this[0] = pos[0] + view!!.width * (.05f + fullPercentage*step*age)
                        this[1] = pos[1] + view.height * .5f
                    }
                },
                PrecisionDescriber {
                    FloatArray(2).apply {
                        this[0] = .1f
                        this[1] = 1f
                    }
                },
                InputDevice.SOURCE_MOUSE,
                MotionEvent.ACTION_BUTTON_PRESS
            )
        )
    }

Однако, когда я использую эти функции и просто помещаю очень короткий сон, например sleep(100) после него, он работает. Это опять же go противоречит трем причинам, перечисленным выше, которых я здесь пытаюсь избежать.

Как вы можете видеть в функции waitForView, я попытался проверить, является ли View " пригодный для использования », используя hasWindowFocus(). Но при этом щелчок по-прежнему не выполняется, за исключением тех случаев, когда я снова ставлю sleep(80) или что-то после него. Поэтому он ждет, пока экран-заставка переключится на A, находит вид, который ищет, а затем не может выполнить щелчок, за исключением тех случаев, когда я немного подожду.

Я также пробовал эти функции View:

  • isEnabled
  • isShown
  • видимость
  • getDrawingRect
  • isFocusable
  • isFocused
  • isLayoutDirectionResolved

Ни один из них не работал так, как я ожидал. Со всеми из них после того, как необходимое значение было возвращено в element.check части waitForView, они все равно были бы недоступны, если бы после него не было короткого sleep.

Есть ли способ чтобы надежно проверить, могу ли я выполнить щелчок по представлению / безопасно выполнить ViewInteraction.perform()

Либо путем проверки, полностью ли загружено действие до точки, в которой его представления можно использовать. Или напрямую проверив, можно ли использовать представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...