2016-05-18 7 views
1

Espresso wird mit der Funktion angekündigt, dass es immer darauf wartet, dass der UI-Thread von Android im Leerlauf ist, so dass Sie sich um kein Timing kümmern müssen Probleme. Aber ich habe anscheinend eine Ausnahme gefunden: -/Espresso wartet nicht darauf, dass der Wischvorgang auf einem ViewPager beendet wird

Die Einstellung ist ein ViewPager mit einem EditText in jedem Fragment. Ich möchte Espresso Text in das EditText auf das erste Fragment geben, streichen Sie mit dem zweiten Fragment und das gleiche zu tun mit dem EditText in diesem Fragment (3-mal):

@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)); 
} 

Aber ich diesen Fehler erhalten, während die erste Durchführung streichen:

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 in eine EditText mit der ID schreiben will EXTERN_HOURS_INPUT, die sichtbar ist. Da die Swipe-Aktion noch nicht beendet ist, sind sowohl das EditTexts im ersten als auch das zweite Fragment sichtbar, weshalb der passende onView(withIdInActiveFragment(EXTERN_HOURS_INPUT)) mit 2 Übereinstimmungen fehlschlägt.

Wenn ich manuell eine Pause erzwinge, indem ich Thread.sleep(2000); nach der Swipe-Aktion hinzufüge, ist alles in Ordnung.

Kann jemand Espresso warten, bis die Wischaktion ausgeführt wird? Oder weiß jemand zumindest, warum das passiert? Da der UI-Thread nicht inaktiv sein kann, wenn eine Wischaktion ausgeführt wird, kann er? Hier

ist die 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> 

Und die 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" > 

+0

Ich bin nicht sicher ViewPager nur ein Fragment 'active' macht. Es hält auch benachbarte Fragmente. –

+0

Es behält benachbarte Fragmente (in meinem Fall eine vorherige und eine folgende), aber sie sind nicht sichtbar. Wenn also Espresso warten würde, dass die Wischaktion beendet wird, würde nur ein'EditText' sichtbar sein und der Abgleich würde gelingen. – Ruik

+0

Ich vermute 'withIdInActiveFragment'. Ist das Ihre benutzerdefinierte 'Matcher'-Implementierung? Nicht alle Matchierer filtern nach Sichtbarkeit. –

Antwort

3

Ich glaube nicht, dass Espresso etwas mit dieser Funktionalität eingebaut, sie möchte, dass du 012 verwendest. Das beste, das ich mir ausgedacht habe, benutzt immer noch den Schlafmodus, fragt aber alle 100 Millisekunden ab und kehrt im schlimmsten Fall 100 ms zurück, nachdem die Ansicht sichtbar wird.

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); 
} 

Anschließend können Sie es so nennen:

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