Espresso per il Web

Espresso-Web è un punto di accesso per lavorare con i componenti UI di Android WebView. Espresso-Web riutilizza gli elementi della popolare API WebDriver per esaminare e controllare il comportamento di una WebView.

Quando utilizzare Espresso-Web

Utilizza Espresso-Web per testare le tue app ibride, in particolare l'integrazione dei componenti UI nativi della tua app con i suoi componenti UI WebView. Puoi utilizzare l'API Espresso-Web insieme ad altre API Espresso per interagire completamente con gli elementi web all'interno degli oggetti WebView.

Se devi testare solo WebView e non le interazioni tra WebView e i componenti nativi della tua app, valuta la possibilità di scrivere un test web generale utilizzando un framework come WebDriver. Se utilizzi un framework di test web, non devi utilizzare un dispositivo Android o una Java Virtual Machine, il che rende i test più rapidi e affidabili. Ciò detto, Espresso-Web ti consente di riutilizzare gli atomi WebDriver personalizzati, il che ti offre molta flessibilità, soprattutto quando scrivi test che prevedi di eseguire su app web autonome e app che includono un'interfaccia utente Android.

Come funziona

Analogamente al metodo onData() di Espresso, un'interazione WebView comprende diversi atomi. Le interazioni WebView utilizzano una combinazione del linguaggio di programmazione Java e di un bridge JavaScript per svolgere il proprio lavoro. Poiché non esiste la possibilità di introdurre condizioni di competizione esponendo i dati dell'ambiente JavaScript (tutto ciò che Espresso vede sul lato basato su Java è una copia isolata), la restituzione dei dati dagli oggetti Web.WebInteraction è completamente supportata, consentendoti di verificare tutti i dati restituiti da una richiesta.

Che cos'è un atomo WebDriver?

Il framework WebDriver utilizza Atoms per trovare e manipolare gli elementi web in modo programmatico. Gli atomi vengono utilizzati da WebDriver per consentire la manipolazione del browser. Un atomo è concettualmente simile a un ViewAction, un'unità autonoma che esegue un'azione nella tua UI. Espone gli atomi utilizzando un elenco di metodi definiti, come findElement() e getElement(), per controllare il browser dal punto di vista dell'utente. Tuttavia, se utilizzi direttamente il framework WebDriver, gli elementi devono essere orchestrati correttamente, il che richiede una logica piuttosto dettagliata.

In Espresso, le classi Web e Web.WebInteraction racchiudono questo boilerplate e danno un aspetto simile a Espresso all'interazione con gli oggetti WebView. Quindi, nel contesto di un WebView, gli atomi vengono utilizzati come sostituzione dei tradizionali ViewMatchers e ViewActions di Espresso.

L'API appare quindi piuttosto semplice:

Kotlin

onWebView()
    .withElement(Atom)
    .perform(Atom)
    .check(WebAssertion)

Java

onWebView()
    .withElement(Atom)
    .perform(Atom)
    .check(WebAssertion);

Per saperne di più, leggi la documentazione di Selenium sugli atomi.

Implementare WebView

Segui le indicazioni riportate nelle sezioni seguenti per utilizzare WebView nei test della tua app.

Pacchetti

Per includere Espresso-Web nel tuo progetto, completa i seguenti passaggi:

  1. Apri il file build.gradle dell'app. Di solito non si tratta del file build.gradle di primo livello, ma di app/build.gradle.
  2. Aggiungi la seguente riga all'interno delle dipendenze:

    Groovy

        androidTestImplementation 'androidx.test.espresso:espresso-web:3.6.1'
        

    Kotlin

        androidTestImplementation('androidx.test.espresso:espresso-web:3.6.1')
        
  3. Espresso-Web è compatibile solo con Espresso 2.2 o versioni successive e con la versione 0.3 o successive della libreria di test, quindi assicurati di aggiornare anche queste righe:

    Groovy

        androidTestImplementation 'androidx.test:runner:1.6.1'
        androidTestImplementation 'androidx.test:rules:1.6.1'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
        

    Kotlin

        androidTestImplementation('androidx.test:runner:1.6.1')
        androidTestImplementation('androidx.test:rules:1.6.1')
        androidTestImplementation('androidx.test.espresso:espresso-core:3.6.1')
        

Utilizzo comune dell'API

Il metodo onWebView() è il punto di accesso principale quando si utilizza WebView su Android con Espresso. Utilizzi questo metodo per eseguire test Espresso-Web, ad esempio i seguenti:

Kotlin

onWebView()
    .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
    .perform(webClick()) // Similar to perform(click())

    // Similar to check(matches(...))
    .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")))

Java

onWebView()
    .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
    .perform(webClick()) // Similar to perform(click())

    // Similar to check(matches(...))
    .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")));

In questo esempio, Espresso-Web individua un elemento DOM il cui ID è "link_2" e ci fa clic sopra. Lo strumento verifica quindi che WebView invii una richiesta GET contenente la stringa "navigation_2.html".

Supporto di JavaScript

Durante l'esecuzione dei test, il sistema esegue tutte le interazioni WebView utilizzando JavaScript. Pertanto, per supportare la valutazione JavaScript, WebView in fase di test deve avere JavaScript abilitato.

Puoi forzare l'attivazione di JavaScript chiamando forceJavascriptEnabled() come azione nell'attività in test, come mostrato nello snippet di codice seguente.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule val activityScenarioRule =
        activityScenarioRule<MyWebViewActivity>()

    @Test fun testWebViewInteraction() {
        onWebView().forceJavascriptEnabled()
    }
}

Interazioni web comuni

Le interazioni più comuni con gli oggetti Web.WebInteraction includono:

  • withElement() fa riferimento a un elemento DOM all'interno di WebView.

    Esempio:

    Kotlin

    onWebView().withElement(findElement(Locator.ID, "teacher"))

    Java

    onWebView().withElement(findElement(Locator.ID, "teacher"));
  • withContextualElement() fa riferimento a un elemento DOM con ambito all'interno di WebView, rispetto a un altro elemento DOM. Devi chiamare withElement() per stabilire il riferimento Web.WebInteraction oggetto (elemento DOM).

    Esempio:

    Kotlin

    .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))

    Java

    .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"));
  • check() valuta una condizione, assicurandosi che restituisca true.

    Esempio:

    Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
        .check(webMatches(getText(), containsString("Socrates")))

    Java

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
        .check(webMatches(getText(), containsString("Socrates")));
  • perform() esegue un'azione all'interno di una WebView, ad esempio fare clic su un elemento.

    Esempio:

    Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .perform(webClick())

    Java

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .perform(webClick());
  • reset() ripristina lo stato iniziale di WebView. Ciò è necessario quando un'azione precedente, ad esempio un clic, introduce una modifica della navigazione che rende inaccessibili gli oggetti ElementReference e WindowReference.

    Nota:sebbene l'utilizzo di reset() sia utile quando si eseguono asserzioni su flussi di lavoro multipagina, come l'invio di moduli, i test devono in genere essere limitati nell'ambito e concentrarsi su una singola pagina.

    Esempio:

    Kotlin

    onWebView()
        .withElement(...)
        .perform(...)
        .reset()

    Java

    onWebView()
        .withElement(...)
        .perform(...)
        .reset();

Esempio

Il seguente esempio verifica se, dopo aver inserito del testo in una WebView e selezionato un pulsante Invia, lo stesso testo viene visualizzato in un elemento diverso della stessa WebView:

Kotlin

const val MACCHIATO = "Macchiato"

@RunWith(AndroidJUnit4::class)
class MyEspressoWebTestSuite {

    @Test fun typeTextInInput_clickButton_SubmitsForm() {
        // Create an intent that displays a web form.
        val webFormIntent = Intent()
        // ...

        // Lazily launch the Activity with a custom start Intent per test.
        ActivityScenario.launchActivity(webFormIntent)

        // Selects the WebView in your layout. If you have multiple WebView
        // objects, you can also use a matcher to select a given WebView,
        // onWebView(withId(R.id.web_view)).
        onWebView()
            // Find the input element by ID.
            .withElement(findElement(Locator.ID, "text_input"))

            // Clear previous input and enter new text into the input element.
            .perform(clearElement())
            .perform(DriverAtoms.webKeys(MACCHIATO))

            // Find the "Submit" button and simulate a click using JavaScript.
            .withElement(findElement(Locator.ID, "submitBtn"))
            .perform(webClick())

            // Find the response element by ID, and verify that it contains the
            // entered text.
            .withElement(findElement(Locator.ID, "response"))
            .check(webMatches(getText(), containsString(MACCHIATO)))
    }
}

Java

public static final String MACCHIATO = "Macchiato";

@Test
public void typeTextInInput_clickButton_SubmitsForm() {
    // Create an intent that displays a web form.
    Intent webFormIntent = new Intent();
    // ...

    // Lazily launch the Activity with a custom start Intent per test.
    ActivityScenario.launchActivity(webFormIntent);

    // Selects the WebView in your layout. If you have multiple WebView objects,
    // you can also use a matcher to select a given WebView,
    // onWebView(withId(R.id.web_view)).
    onWebView()
        // Find the input element by ID.
        .withElement(findElement(Locator.ID, "text_input"))

        // Clear previous input and enter new text into the input element.
        .perform(clearElement())
        .perform(DriverAtoms.webKeys(MACCHIATO))

        // Find the "Submit" button and simulate a click using JavaScript.
        .withElement(findElement(Locator.ID, "submitBtn"))
        .perform(webClick())

        // Find the response element by ID, and verify that it contains the
        // entered text.
        .withElement(findElement(Locator.ID, "response"))
        .check(webMatches(getText(), containsString(MACCHIATO)));
}

Risorse aggiuntive

Per saperne di più sull'utilizzo di Espresso-Web nei test Android, consulta le seguenti risorse.

Campioni

  • WebBasicSample: Utilizza Espresso-Web per interagire con gli oggetti WebView.