Verifique se uma caixa de diálogo é exibida com o Espresso

86

Estou tentando escrever alguns testes com o novo kit android-test (Espresso) . Mas não consigo encontrar nenhuma informação sobre como verificar se uma caixa de diálogo é exibida e realizar algumas ações nela (como clicar nos botões positivo e negativo, etc). Observe que uma caixa de diálogo também pode ser exibida por um WebView, não pelo próprio aplicativo.

Qualquer ajuda seria apreciada. Eu só preciso de um link ou algum código de exemplo para o básico:

  1. Verifique se uma caixa de diálogo aparece
  2. Executar cliques nos botões de diálogo
  3. Interaja com a visão interna da caixa de diálogo (se for uma visão personalizada)
  4. A pré-forma clica fora da caixa de diálogo e verifique se ela está sendo exibida ou não (por exemplo, se setCancelable(false)foi chamada no criador da caixa de diálogo e queremos verificar isso)

Obrigado em conselhos!

Serj Lotutovici
fonte
Algum comentário sobre minha resposta abaixo?
denys

Respostas:

123
  1. Para verificar se a caixa de diálogo aparece, você pode simplesmente verificar se Exibir com um texto presente dentro da caixa de diálogo é mostrado:

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

    ou, com base em texto com id

    onView(withId(R.id.myDialogTextId)).check(matches(allOf(withText(myDialogText), isDisplayed()));
    
  2. Para clicar no botão das caixas de diálogo, faça o seguinte (botão1 - OK, botão2 - Cancelar):

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

    ATUALIZAR

  3. Acho que é possível, pois o Espresso tem suporte para várias janelas .
  4. Não tenho certeza sobre clicar fora da visualização da caixa de diálogo personalizada, mas para verificar se ela está sendo exibida ou não, você precisa criar seu matcher personalizado e verificar dentro dele.
denys
fonte
3
A etapa 1 não funcionou para mim em um ProgressDialog. Apenas tentando validar o título e a mensagem do diálogo
Tim Boland
1
O que há com café expresso e importações estáticas? De quais classes esses métodos vêm? Por que você está usando importações estáticas em uma resposta de estouro de pilha?
2
@jvrodrigues cada tutorial do Espresso usa importações estáticas. Eu sugiro que você apenas se acostume (embora eu entenda a frustração). Isso ajuda: google.github.io/android-testing-support-library/docs
AutonomousApps
Para a etapa 4, em vez de clicar fora da caixa de diálogo, você pode chamar "pressBack ();" que descarta a caixa de diálogo. é o equivalente a usar o botão Voltar do hardware.
Ethan
O projeto @denys foi movido. parece que o link está morto.
Neon Warge de
67

Atualmente, eu uso isso e parece funcionar bem.

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

Se você tiver um AlertDialog como esse:

insira a descrição da imagem aqui

Você pode verificar se os componentes são exibidos:

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

e realizar uma ação:

onView(withId(android.R.id.button3)).perform(click());
Luiz augusto
fonte
2
O texto no meu caso tinha id android.R.id.messagee o título tinha um id oculto de android.R.id.alertTitle.
Jason Robinson
2
Se você usar AlertDialog (ou DialogFragment) que vem da biblioteca de suporte AppCompat, use este:int alertDialogTitleId = android.support.v7.appcompat.R.id.alertTitle;
Mr-IDE
3

Para responder à pergunta 4, que a resposta aceita não, modifiquei o código a seguir, que encontrei aqui no Stack Overflow ( link ) para testar se um Toast foi exibido.

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

O idpassado é o id de um Viewatualmente exibido em sua caixa de diálogo. Você também pode escrever o método assim:

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

E agora ele está procurando por um Viewcontendo uma string de texto específica.

Use-o assim:

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

Os IDs de botão R.id.button1 e R.id.button2 não serão iguais em todos os dispositivos. Os Ids podem mudar com as versões do sistema operacional.

A maneira correta de fazer isso é usar o UIAutomator. Inclua a dependência UIAutomator em seu build.gradle

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

E 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
fonte
1
Na verdade, android.R.id.button1, android.R.id.button2e android.R.id.button3para "positivo", "neutro" e "negativo", são símbolos globais que podem ser usados. Se você escolher selecionar os botões por meio de seu texto - o que é totalmente correto - você não precisa do UIAutomator, mas pode fazer o mesmo com o Espresso onView(withText("ButtonTest")).perform(click()).
Thomas Keller
Usei essa solução com uma estrutura de teste Robotium e consegui selecionar os botões da caixa de diálogo do sistema operacional Android com facilidade. Me economizou muito tempo. Obrigado jaydeepw!
Ray
@ThomasKeller Eu usei ids de button1, button2 no passado, meus testes falharam quando os executei em vários dispositivos. A caixa de diálogo exibida é o controle do sistema. Não é seu controle / IU. Para qualquer coisa fora de sua IU, UIAutomator é recomendado.
JaydeepW
É isso aí. Muito obrigado
1lb3r
3

Apenas no caso de alguém tropeçar nesta questão como eu. Todas as respostas funcionarão apenas para caixas de diálogo COM botões de diálogo. Não tente usar isso para caixas de diálogo de progresso sem interação do usuário. O Espresso fica esperando que o aplicativo entre no estado ocioso. Enquanto a caixa de diálogo de progresso estiver visível, o aplicativo não estará inativo.

Diana Farin
fonte