Compruebe si se muestra un cuadro de diálogo con Espresso

86

Estoy intentando escribir algunas pruebas con el nuevo android-test-kit (Espresso) . Pero no puedo encontrar ninguna información sobre cómo verificar si se muestra un cuadro de diálogo y realizar algunas acciones en él (como hacer clic en los botones positivo y negativo, etc.). Tenga en cuenta que un cuadro de diálogo también puede ser mostrado por a WebView, no por la aplicación en sí.

Cualquier ayuda sería apreciada. Solo necesito un enlace o algún código de ejemplo para los conceptos básicos:

  1. Compruebe si aparece un cuadro de diálogo
  2. Realizar clics en los botones de diálogo
  3. Interactuar con la vista interna del cuadro de diálogo (si es una vista personalizada)
  4. Haga clic en la preforma fuera del cuadro de diálogo y verifique si se muestra o no (por ejemplo, si setCancelable(false)se llamó en el generador de cuadros de diálogo y queremos verificarlo)

¡Gracias por el consejo!

Serj Lotutovici
fuente
¿Algún comentario sobre mi respuesta a continuación?
niega el

Respuestas:

123
  1. Para verificar si aparece un cuadro de diálogo, simplemente puede verificar si se muestra Ver con un texto que se presenta dentro del cuadro de diálogo:

    onView(withText("dialogText")).check(matches(isDisplayed()));
    

    o, basado en texto con id

    onView(withId(R.id.myDialogTextId)).check(matches(allOf(withText(myDialogText), isDisplayed()));
    
  2. Para hacer clic en el botón de cuadros de diálogo, haga lo siguiente (botón1 - Aceptar, botón2 - Cancelar):

    onView(withId(android.R.id.button1)).perform(click());
    

    ACTUALIZAR

  3. Creo que es posible ya que Espresso tiene soporte para múltiples ventanas .
  4. No estoy seguro de hacer clic fuera de la vista del cuadro de diálogo personalizado, pero para verificar si se muestra o no, debe crear su comparador personalizado y verificar dentro de él.
niega
fuente
3
El paso 1 no funcionó para mí en un ProgressDialog. Solo intento validar el título y el mensaje del diálogo
Tim Boland
1
¿Qué pasa con el espresso y las importaciones estáticas? ¿De qué clases provienen esos métodos? ¿Por qué está utilizando importaciones estáticas en una respuesta de desbordamiento de pila?
2
@jvrodrigues cada tutorial de Espresso usa importaciones estáticas. Te sugiero que te acostumbres (aunque entiendo la frustración). Esto ayuda: google.github.io/android-testing-support-library/docs
AutonomousApps
Para el paso 4, en lugar de hacer clic fuera del cuadro de diálogo, puede llamar a "pressBack ();" que descarta el diálogo. es el equivalente a usar el botón de retroceso del hardware.
Ethan
El proyecto @denys se ha movido. parece que el vínculo está muerto.
Neon Warge
67

Actualmente uso esto y parece funcionar bien.

onView(withText(R.string.my_title))
    .inRoot(isDialog()) // <---
    .check(matches(isDisplayed()));
Kiruwka
fuente
27

Si tiene un AlertDialog como ese:

ingrese la descripción de la imagen aquí

Puede comprobar si se muestran los componentes:

int titleId = mActivityTestRule.getActivity().getResources()
        .getIdentifier( "alertTitle", "id", "android" );

onView(withId(titleId))
        .inRoot(isDialog())
        .check(matches(withText(R.string.my_title)))
        .check(matches(isDisplayed()));

onView(withId(android.R.id.text1))
        .inRoot(isDialog())
        .check(matches(withText(R.string.my_message)))
        .check(matches(isDisplayed()));

onView(withId(android.R.id.button2))
        .inRoot(isDialog())
        .check(matches(withText(android.R.string.no)))
        .check(matches(isDisplayed()));

onView(withId(android.R.id.button3))
        .inRoot(isDialog())
        .check(matches(withText(android.R.string.yes)))
        .check(matches(isDisplayed()));

y realizar una acción:

onView(withId(android.R.id.button3)).perform(click());
Luiz Augusto
fuente
2
El texto en mi caso tenía una identificación android.R.id.messagey el título tenía una identificación oculta de android.R.id.alertTitle.
Jason Robinson
2
Si usa AlertDialog (o DialogFragment) que proviene de la biblioteca de soporte de AppCompat, use esto:int alertDialogTitleId = android.support.v7.appcompat.R.id.alertTitle;
Mr-IDE
3

Para responder a la pregunta 4, que no es la respuesta aceptada, modifiqué el siguiente código, que encontré aquí en Stack Overflow ( enlace ) para probar si se mostró un Toast.

@NonNull
public static ViewInteraction getRootView(@NonNull Activity activity, @IdRes int id) {
    return onView(withId(id)).inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))));
}

El idpasado es la identificación de un Viewque se muestra actualmente en su diálogo. También puede escribir el método así:

@NonNull
public static ViewInteraction getRootView(@NonNull Activity activity, @NonNull String text) {
    return onView(withText(text)).inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))));
}

Y ahora está buscando que Viewcontenga una cadena de texto en particular.

Úselo así:

getRootView(getActivity(), R.id.text_id).perform(click());
AutonomousApps
fuente
3

Los ID de botón R.id.button1 y R.id.button2 no serán los mismos en todos los dispositivos. Los identificadores pueden cambiar con las versiones del sistema operativo.

La forma correcta de lograrlo es utilizar UIAutomator. Incluya la dependencia de UIAutomator en su build.gradle

// Set this dependency to build and run UI Automator tests
  androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'

y use

// Initialize UiDevice instance
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// Search for correct button in the dialog.
UiObject button = uiDevice.findObject(new UiSelector().text("ButtonText"));
if (button.exists() && button.isEnabled()) {
    button.click();
}
JaydeepW
fuente
1
En realidad, android.R.id.button1, android.R.id.button2y android.R.id.button3para "positivo", "neutral" y "negativo", son símbolos globales que pueden ser utilizados. Si elige seleccionar botones a través de su texto, lo cual está totalmente bien, no necesita UIAutomator, pero puede hacer lo mismo con Espresso onView(withText("ButtonTest")).perform(click()).
Thomas Keller
Utilicé esta solución con un marco de prueba de Robotium y pude seleccionar los botones del cuadro de diálogo del sistema operativo Android con facilidad. Me ahorró un montón de tiempo. ¡Gracias jaydeepw!
Ray
@ThomasKeller He usado los identificadores de button1, button2 en el pasado, mis pruebas se rompieron cuando las ejecuté en una variedad de dispositivos. El cuadro de diálogo que se muestra es el control del sistema. No es tu control / UI. Para cualquier cosa fuera de su interfaz de usuario, se recomienda UIAutomator.
JaydeepW
Eso es. Muchas gracias.
lb3r
3

En caso de que alguien se encuentre con esta pregunta como yo. Todas las respuestas solo funcionarán para cuadros de diálogo CON botones de diálogo. No intente utilizar esto para los cuadros de diálogo de progreso sin la interacción del usuario. Espresso sigue esperando que la aplicación entre en estado inactivo. Mientras el cuadro de diálogo de progreso esté visible, la aplicación no estará inactiva.

Diana Farin
fuente