File size: 6,337 Bytes
f871013 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | package com.b44t.messenger;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.test.espresso.NoMatchingViewException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.util.TreeIterables;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import org.hamcrest.Matcher;
import org.thoughtcrime.securesms.ConversationListActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.AccountManager;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.AccessibilityUtil;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
public class TestUtils {
private static int createdAccountId = 0;
private static boolean resetEnterSends = false;
public static void cleanupCreatedAccount(Context context) {
DcAccounts accounts = DcHelper.getAccounts(context);
if (createdAccountId != 0) {
accounts.removeAccount(createdAccountId);
createdAccountId = 0;
}
}
public static void cleanup() {
Context context = getInstrumentation().getTargetContext();
cleanupCreatedAccount(context);
if (resetEnterSends) {
Prefs.setEnterSendsEnabled(getInstrumentation().getTargetContext(), false);
}
}
public static void createOfflineAccount() {
Context context = getInstrumentation().getTargetContext();
cleanupCreatedAccount(context);
createdAccountId = AccountManager.getInstance().beginAccountCreation(context);
DcContext c = DcHelper.getContext(context);
c.setConfig("configured_addr", "alice@example.org");
c.setConfig("configured_mail_pw", "abcd");
c.setConfig("configured", "1");
}
@NonNull
public static ActivityScenarioRule<ConversationListActivity> getOfflineActivityRule(boolean useExistingChats) {
Intent intent =
Intent.makeMainActivity(
new ComponentName(getInstrumentation().getTargetContext(), ConversationListActivity.class));
if (!useExistingChats) {
createOfflineAccount();
}
prepare();
return new ActivityScenarioRule<>(intent);
}
@NonNull
public static <T extends Activity> ActivityScenarioRule<T> getOnlineActivityRule(Class<T> activityClass) {
Context context = getInstrumentation().getTargetContext();
AccountManager.getInstance().beginAccountCreation(context);
prepare();
return new ActivityScenarioRule<>(new Intent(getInstrumentation().getTargetContext(), activityClass));
}
private static void prepare() {
Prefs.setBooleanPreference(getInstrumentation().getTargetContext(), Prefs.DOZE_ASKED_DIRECTLY, true);
if (!AccessibilityUtil.areAnimationsDisabled(getInstrumentation().getTargetContext())) {
throw new RuntimeException("To run the tests, disable animations at Developer options' " +
"-> 'Window/Transition/Animator animation scale' -> Set all 3 to 'off'");
}
}
/**
* Perform action of waiting for a certain view within a single root view
*
* @param matcher Generic Matcher used to find our view
*/
private static ViewAction searchFor(Matcher<View> matcher) {
return new ViewAction() {
public Matcher<View> getConstraints() {
return isRoot();
}
public String getDescription() {
return "searching for view $matcher in the root view";
}
public void perform(UiController uiController, View view) {
Iterable<View> childViews = TreeIterables.breadthFirstViewTraversal(view);
// Look for the match in the tree of childviews
for (View it : childViews) {
if (matcher.matches(it)) {
// found the view
return;
}
}
throw new NoMatchingViewException.Builder()
.withRootView(view)
.withViewMatcher(matcher)
.build();
}
};
}
/**
* Perform action of implicitly waiting for a certain view.
* This differs from EspressoExtensions.searchFor in that,
* upon failure to locate an element, it will fetch a new root view
* in which to traverse searching for our @param match
*
* @param viewMatcher ViewMatcher used to find our view
*/
public static ViewInteraction waitForView(
Matcher<View> viewMatcher,
int waitMillis,
int waitMillisPerTry
) {
// Derive the max tries
int maxTries = (int) (waitMillis / waitMillisPerTry);
int tries = 0;
for (int i = 0; i < maxTries; i++)
try {
// Track the amount of times we've tried
tries++;
// Search the root for the view
onView(isRoot()).perform(searchFor(viewMatcher));
// If we're here, we found our view. Now return it
return onView(viewMatcher);
} catch (Exception e) {
if (tries == maxTries) {
throw e;
}
Util.sleep(waitMillisPerTry);
}
throw new RuntimeException("Error finding a view matching $viewMatcher");
}
/**
* Normally, you would do
* onView(withId(R.id.send_button)).perform(click());
* to send the draft message. However, in order to change the send button to the attach button
* while there is no draft, the send button is made invisible and the attach button is made
* visible instead. This confuses the test framework.<br/><br/>
*
* So, this is a workaround for pressing the send button.
*/
public static void pressSend() {
if (!Prefs.isEnterSendsEnabled(getInstrumentation().getTargetContext())) {
resetEnterSends = true;
Prefs.setEnterSendsEnabled(getInstrumentation().getTargetContext(), true);
}
waitForView(withHint(R.string.chat_input_placeholder), 10000, 100).perform(typeText("\n"));
}
}
|