Espresso不需要等待ViewPager上的滑动操作完成 [英] Espresso doesn't wait for swipe action on a ViewPager to be finished

查看:65
本文介绍了Espresso不需要等待ViewPager上的滑动操作完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Espresso的广告功能是始终等待Android的UI-Thread空闲,因此您不必担心任何计时问题.但我似乎发现了一个例外:-/

Espresso is advertised with the feature that it always waits for the UI-Thread of Android to be idle so that you don't have to take care of any timing issues. But I seem to have found an exception :-/

设置为每个片段中带有EditTextViewPager.我希望Espresso在第一个片段的EditText中键入文本,滑动到第二个片段,并对该片段中的EditText进行相同的操作(3次):

The setting is a ViewPager with an EditText in each fragment. I want Espresso to type text into theEditText on the first fragment, swipe to the second fragment and do the same with the EditText in that fragment (3 times):

@MediumTest
public void testSwipe() throws InterruptedException {
    onView(withIdInActiveFragment(EXTERN_HOURS_INPUT))
            .perform(typeText("8.0"));
    onView(withIdInActiveFragment(DAY_PAGER))
            .perform(swipeLeft());
    //Thread.sleep(2000); // <--- uncomment this and the test runs fine
    onView(withIdInActiveFragment(EXTERN_HOURS_INPUT))
            .perform(typeText("8.0"));
    onView(withIdInActiveFragment(DAY_PAGER))
            .perform(swipeLeft());
    //Thread.sleep(2000);
    onView(withIdInActiveFragment(EXTERN_HOURS_INPUT))
            .perform(typeText("8.0"));
    onView(withIdInActiveFragment(DAY_PAGER))
            .perform(swipeLeft());
}

public static Matcher<View> withIdInActiveFragment(int id) {
    return Matchers.allOf(withParent(isDisplayed()), withId(id));
}

但是在执行第一次滑动时出现此错误:

But I get this error while performing the first swipe:

android.support.test.espresso.AmbiguousViewMatcherException: '(has parent matching: is displayed on the screen to the user and with id: de.cp.cp_app_android:id/extern_hours_input)' matches multiple views in the hierarchy.
Problem views are marked with '****MATCHES****' below.

View Hierarchy:
...

+-------->AppCompatEditText{id=2131558508, res-name=extern_hours_input, visibility=VISIBLE, width=110, height=91, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=true, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=true, editor-info=[inputType=0x2002 imeOptions=0x6 privateImeOptions=null actionLabel=null actionId=0 initialSelStart=3 initialSelEnd=3 initialCapsMode=0x0 hintText=null label=null packageName=null fieldId=0 fieldName=null extras=null ], x=165.0, y=172.0, text=8.0, input-type=8194, ime-target=true, has-links=false} ****MATCHES****

...  


+-------->AppCompatEditText{id=2131558508, res-name=extern_hours_input, visibility=VISIBLE, width=110, height=91, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=true, editor-info=[inputType=0x2002 imeOptions=0x6 privateImeOptions=null actionLabel=null actionId=0 initialSelStart=0 initialSelEnd=0 initialCapsMode=0x2000 hintText=null label=null packageName=null fieldId=0 fieldName=null extras=null ], x=165.0, y=172.0, text=, input-type=8194, ime-target=false, has-links=false} ****MATCHES****

Espresso希望以可见的ID EXTERN_HOURS_INPUT写入EditText.由于尚未完成滑动操作,因此第一个片段和第二个片段中的EditTexts都可见,这就是为什么匹配onView(withIdInActiveFragment(EXTERN_HOURS_INPUT))失败且匹配2次的原因.

Espresso wants to write into an EditText with the ID EXTERN_HOURS_INPUT that is visible. Because the swipe action is not finished yet, both the EditTexts in the first and the second fragment are visible, wich is why the matching onView(withIdInActiveFragment(EXTERN_HOURS_INPUT)) fails with 2 matches.

如果我在滑动操作之后通过添加Thread.sleep(2000);来手动强行休息,那么一切都很好.

If I manually force a break by adding Thread.sleep(2000); after the swipe action, everything is fine.

有人知道如何让Espresso等到划动动作完成吗?还是至少有人知道,为什么会这样?因为执行滑动操作时UI线程不能处于空闲状态,所以可以吗?

这是activity_day_time_record.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">

<data>
    <variable
        name="timerecord"
        type="de.cp.cp_app_android.model.TimerecordDatabindingWrapper" />
</data>

<ScrollView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        style="@style/cp_relative_layout"
        android:descendantFocusability="afterDescendants"
        tools:context=".activities.DayRecordActivity">

        <include
            android:id="@+id/toolbar"
            layout="@layout/cp_toolbar"></include>


        <!-- Arbeitsstunden -->
        <TextView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/section_title_workhours"
            style="?android:attr/listSeparatorTextViewStyle"
            android:layout_width="match_parent"
            android:layout_height="25dip"
            android:layout_below="@id/toolbar"
            android:text="@string/dayrecord_section_workhours" />

        <TextView
            android:id="@+id/extern_hours"
            style="@style/dayrecord_label"
            android:layout_below="@id/section_title_workhours"
            android:text="@string/dayrecord_label_extern_hours" />

        <EditText
            android:id="@+id/extern_hours_input"
            style="@style/dayrecord_decimal_input"
            android:layout_alignBaseline="@id/extern_hours"
            android:layout_toEndOf="@id/extern_hours"
            android:layout_toRightOf="@id/extern_hours"
            bind:addTextChangedListener="@{timerecord.changed}"
            bind:binding="@{timerecord.hoursExtern}"
            bind:setOnFocusChangeListener="@{timerecord.hoursExternChanged}" />
        <!--    android:text='@{timerecord.hoursExtern != null ? String.format("%.1f", timerecord.hoursExtern) : ""}' -->


    </RelativeLayout>
</ScrollView>

activity_swipe_day.xml:

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/day_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >

推荐答案

我不认为Espresso具有此功能的内置功能,他们希望您使用

I don't think Espresso has anything built in with this functionality, they want you to use idling-resource. The best I've come up with is still using sleep but polls every 100 milliseconds, so at worst will return 100 ms after the view becomes visible.

private final int TIMEOUT_MILLISECONDS = 5000;
private final int SLEEP_MILLISECONDS = 100;
private int time = 0;
private boolean wasDisplayed = false;

public Boolean isVisible(ViewInteraction interaction) throws InterruptedException {
    interaction.withFailureHandler((error, viewMatcher) -> wasDisplayed = false);
    if (wasDisplayed) {
        return true;
    }
    if (time >= TIMEOUT_MILLISECONDS) {
        return false;
    }

    //set it to true if failing handle should set it to false again.
    wasDisplayed = true;
    Thread.sleep(SLEEP_MILLISECONDS);
    time += SLEEP_MILLISECONDS;

    interaction.check(matches(isDisplayed()));
    Log.i("ViewChecker","sleeping");
    return isVisible(interaction);
}

然后您可以这样称呼它:

You can then call it like this:

ViewInteraction interaction = onView(
        allOf(withId(R.id.someId), withText(someText), isDisplayed()));
boolean objectIsVisible = isVisible(interaction);
assertThat(objectIsVisible, is(true));

这篇关于Espresso不需要等待ViewPager上的滑动操作完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆