From 9d8232472fb2233dc3088ef570f95d4b8267559a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2018 18:24:30 +0200 Subject: [PATCH] tests: dismiss dialogs in the emulator with back button before run The ARM emulator can show ANRs for 'system' on boot, so that dialog needs to be dismissed before the Espresso tests can happen. https://android.googlesource.com/platform/frameworks/testing/+/master/uiautomator_test_libraries/src/com/android/uiautomator/common/UiWatchers.java --- .../fdroid/MainActivityEspressoTest.java | 12 ++ .../java/org/fdroid/fdroid/UiWatchers.java | 156 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 app/src/androidTest/java/org/fdroid/fdroid/UiWatchers.java diff --git a/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java b/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java index 5f4871240..7fd5a57b9 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java @@ -9,6 +9,9 @@ import android.support.test.filters.LargeTest; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObjectNotFoundException; +import android.support.test.uiautomator.UiSelector; import android.util.Log; import android.view.View; import org.fdroid.fdroid.views.BannerUpdatingRepos; @@ -71,6 +74,15 @@ public class MainActivityEspressoTest { e.printStackTrace(); } SystemAnimations.disableAll(InstrumentationRegistry.getTargetContext()); + + // dismiss the ANR or any other system dialogs that might be there + UiObject button = new UiObject(new UiSelector().text("Wait").enabled(true)); + try { + button.click(); + } catch (UiObjectNotFoundException e) { + Log.d(TAG, e.getLocalizedMessage()); + } + new UiWatchers().registerAnrAndCrashWatchers(); } @AfterClass diff --git a/app/src/androidTest/java/org/fdroid/fdroid/UiWatchers.java b/app/src/androidTest/java/org/fdroid/fdroid/UiWatchers.java new file mode 100644 index 000000000..1458653e8 --- /dev/null +++ b/app/src/androidTest/java/org/fdroid/fdroid/UiWatchers.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.fdroid.fdroid; + +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObjectNotFoundException; +import android.support.test.uiautomator.UiSelector; +import android.support.test.uiautomator.UiWatcher; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@SuppressWarnings("MemberName") +public class UiWatchers { + private static final String LOG_TAG = UiWatchers.class.getSimpleName(); + private final List mErrors = new ArrayList(); + + /** + * We can use the UiDevice registerWatcher to register a small script to be executed when the + * framework is waiting for a control to appear. Waiting may be the cause of an unexpected + * dialog on the screen and it is the time when the framework runs the registered watchers. + * This is a sample watcher looking for ANR and crashes. it closes it and moves on. You should + * create your own watchers and handle error logging properly for your type of tests. + */ + public void registerAnrAndCrashWatchers() { + UiDevice.getInstance().registerWatcher("ANR", new UiWatcher() { + @Override + public boolean checkForCondition() { + UiObject window = new UiObject(new UiSelector().className( + "com.android.server.am.AppNotRespondingDialog")); + String errorText = null; + if (window.exists()) { + try { + errorText = window.getText(); + } catch (UiObjectNotFoundException e) { + Log.e(LOG_TAG, "dialog gone?", e); + } + onAnrDetected(errorText); + postHandler("Wait"); + return true; // triggered + } + return false; // no trigger + } + }); + // class names may have changed + UiDevice.getInstance().registerWatcher("ANR2", new UiWatcher() { + @Override + public boolean checkForCondition() { + UiObject window = new UiObject(new UiSelector().packageName("android") + .textContains("isn't responding.")); + if (window.exists()) { + String errorText = null; + try { + errorText = window.getText(); + } catch (UiObjectNotFoundException e) { + Log.e(LOG_TAG, "dialog gone?", e); + } + onAnrDetected(errorText); + postHandler("Wait"); + return true; // triggered + } + return false; // no trigger + } + }); + UiDevice.getInstance().registerWatcher("CRASH", new UiWatcher() { + @Override + public boolean checkForCondition() { + UiObject window = new UiObject(new UiSelector().className( + "com.android.server.am.AppErrorDialog")); + if (window.exists()) { + String errorText = null; + try { + errorText = window.getText(); + } catch (UiObjectNotFoundException e) { + Log.e(LOG_TAG, "dialog gone?", e); + } + onCrashDetected(errorText); + postHandler("OK"); + return true; // triggered + } + return false; // no trigger + } + }); + UiDevice.getInstance().registerWatcher("CRASH2", new UiWatcher() { + @Override + public boolean checkForCondition() { + UiObject window = new UiObject(new UiSelector().packageName("android") + .textContains("has stopped")); + if (window.exists()) { + String errorText = null; + try { + errorText = window.getText(); + } catch (UiObjectNotFoundException e) { + Log.e(LOG_TAG, "dialog gone?", e); + } + onCrashDetected(errorText); + postHandler("OK"); + return true; // triggered + } + return false; // no trigger + } + }); + Log.i(LOG_TAG, "Registed GUI Exception watchers"); + } + + public void onAnrDetected(String errorText) { + mErrors.add(errorText); + } + + public void onCrashDetected(String errorText) { + mErrors.add(errorText); + } + + public void reset() { + mErrors.clear(); + } + + public List getErrors() { + return Collections.unmodifiableList(mErrors); + } + + /** + * Current implementation ignores the exception and continues. + */ + public void postHandler(String buttonText) { + // TODO: Add custom error logging here + String formatedOutput = String.format("UI Exception Message: %-20s\n", UiDevice + .getInstance().getCurrentPackageName()); + Log.e(LOG_TAG, formatedOutput); + UiObject buttonOK = new UiObject(new UiSelector().text(buttonText).enabled(true)); + // sometimes it takes a while for the OK button to become enabled + buttonOK.waitForExists(5000); + try { + buttonOK.click(); + } catch (UiObjectNotFoundException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file