From 7cc29410531a4b46145d196b8d0b2e3a0915608a Mon Sep 17 00:00:00 2001 From: Rhodey Orbits Date: Mon, 25 May 2015 20:59:07 -0700 Subject: [PATCH] 1) created a new build flavor for espresso tests 2) create a new source set full of espresso tests 3) updated proguard-testing.pro 4) added test device numbers to .gitignore // FREEBIE --- .gitignore | 1 + build.gradle | 18 +- proguard-testing.pro | 1 + ...ApplicationPreferencesActivityActions.java | 51 ++++ .../ApplicationPreferencesActivityTest.java | 58 ++++ .../ConversationActivityActions.java | 53 ++++ .../ConversationListActivityActions.java | 79 +++++ .../ConversationListActivityTest.java | 279 ++++++++++++++++++ .../thoughtcrime/securesms/EspressoUtil.java | 119 ++++++++ .../securesms/GroupCreateActivityTest.java | 56 ++++ .../securesms/ImportExportActivityTest.java | 61 ++++ .../NewConversationActivityActions.java | 42 +++ .../NewConversationActivityTest.java | 125 ++++++++ .../PassphraseChangeActivityActions.java | 48 +++ .../PassphraseChangeActivityTest.java | 119 ++++++++ .../RegistrationActivityActions.java | 73 +++++ .../securesms/RegistrationActivityTest.java | 53 ++++ .../securesms/RegistrationBypassUtil.java | 95 ++++++ .../securesms/TextSecureEspressoTestCase.java | 132 +++++++++ .../securesms/TextSecureWakingTestRunner.java | 46 +++ .../ViewLocalIdentityActivityTest.java | 48 +++ .../thoughtcrime/securesms/ViewMatchers.java | 72 +++++ .../AdvancedPreferenceFragmentActions.java | 43 +++ .../AdvancedPreferenceFragmentTest.java | 112 +++++++ ...ppProtectionPreferenceFragmentActions.java | 51 ++++ .../AppProtectionPreferenceFragmentTest.java | 136 +++++++++ .../AppearancePreferenceFragmentActions.java | 35 +++ .../AppearancePreferenceFragmentTest.java | 57 ++++ ...otificationsPreferenceFragmentActions.java | 31 ++ .../NotificationsPreferenceFragmentTest.java | 97 ++++++ .../SmsMmsPreferenceFragmentActions.java | 43 +++ .../StoragePreferenceFragmentActions.java | 39 +++ test/espresso/AndroidManifest.xml | 8 + 33 files changed, 2280 insertions(+), 1 deletion(-) create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationActivityActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/EspressoUtil.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/GroupCreateActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ImportExportActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationBypassUtil.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureEspressoTestCase.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureWakingTestRunner.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewLocalIdentityActivityTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewMatchers.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentTest.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/SmsMmsPreferenceFragmentActions.java create mode 100644 test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/StoragePreferenceFragmentActions.java create mode 100644 test/espresso/AndroidManifest.xml diff --git a/.gitignore b/.gitignore index f84281fbed..9279cd5b9c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ signing.properties library/lib/ library/obj/ ffpr +test/androidTestEspresso/res/values/arrays.xml diff --git a/build.gradle b/build.gradle index 5e0d140351..1c426ea026 100644 --- a/build.gradle +++ b/build.gradle @@ -78,7 +78,9 @@ dependencies { androidTestCompile ('com.squareup.assertj:assertj-android:1.0.0') { exclude group: 'org.hamcrest', module: 'hamcrest-core' } - androidTestCompile 'com.android.support.test:runner:0.2' + androidTestCompile ('com.android.support.test.espresso:espresso-core:2.1') { + exclude group: 'javax.inject' + } } dependencyVerification { @@ -144,6 +146,13 @@ android { buildConfigField "String", "PUSH_URL", "\"https://textsecure-service.whispersystems.org\"" } + productFlavors { + base { } + espresso { + testInstrumentationRunner "org.thoughtcrime.securesms.TextSecureWakingTestRunner" + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 @@ -201,9 +210,16 @@ android { res.srcDirs = ['res'] assets.srcDirs = ['assets'] } + espresso { + manifest.srcFile 'test/espresso/AndroidManifest.xml' + } androidTest { java.srcDirs = ['test/androidTest/java'] } + androidTestEspresso { + java.srcDirs = ['test/androidTestEspresso/java'] + res.srcDirs = ['test/androidTestEspresso/res'] + } } lintOptions { diff --git a/proguard-testing.pro b/proguard-testing.pro index affdfd8b0e..9932571902 100644 --- a/proguard-testing.pro +++ b/proguard-testing.pro @@ -4,6 +4,7 @@ -dontwarn android.test.** -dontwarn com.android.support.test.** -dontwarn sun.reflect.** +-dontwarn sun.misc.** -dontwarn org.assertj.** -dontwarn org.hamcrest.** -dontwarn org.mockito.** diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityActions.java new file mode 100644 index 0000000000..4794bd6d72 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityActions.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; + +public class ApplicationPreferencesActivityActions { + + public static void clickSmsAndMmsSetting() throws Exception { + onData(Matchers.allOf(withKey("preference_category_sms_mms"))).perform(click()); + } + + public static void clickNotificationsSetting() throws Exception { + onData(Matchers.allOf(withKey("preference_category_notifications"))).perform(click()); + } + + public static void clickAppProtectionSetting() throws Exception { + onData(Matchers.allOf(withKey("preference_category_app_protection"))).perform(click()); + } + + public static void clickAppearanceSetting() throws Exception { + onData(Matchers.allOf(withKey("preference_category_appearance"))).perform(click()); + } + + public static void clickDeleteOldMessagesSetting() throws Exception { + onData(Matchers.allOf(withKey("preference_category_storage"))).perform(click()); + } + + public static void clickAdvancedSetting() throws Exception { + onData(Matchers.allOf(withKey("preference_category_advanced"))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityTest.java new file mode 100644 index 0000000000..ef4ccf1497 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ApplicationPreferencesActivityTest.java @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.test.suitebuilder.annotation.LargeTest; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static org.thoughtcrime.securesms.EspressoUtil.waitOn; + +@LargeTest +public class ApplicationPreferencesActivityTest extends TextSecureEspressoTestCase { + + public ApplicationPreferencesActivityTest() { + super(ConversationListActivity.class); + } + + private void checkAllPreferencesDisplayed() throws Exception { + onData(Matchers.allOf(withKey("preference_category_sms_mms"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("preference_category_notifications"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("preference_category_app_protection"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("preference_category_appearance"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("preference_category_storage"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("preference_category_advanced"))) + .check(matches(isDisplayed())); + } + + public void testClickSettings() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + ConversationListActivityActions.clickSettings(getContext()); + waitOn(ApplicationPreferencesActivity.class); + checkAllPreferencesDisplayed(); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationActivityActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationActivityActions.java new file mode 100644 index 0000000000..b0be6884f5 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationActivityActions.java @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.content.Context; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.thoughtcrime.securesms.EspressoUtil.typeTextAndCloseKeyboard; + +public class ConversationActivityActions { + + public static void clickAddAttachment(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.conversation__menu_add_attachment)).perform(click()); + } + + public static void clickAllImages(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.conversation__menu_view_media)).perform(click()); + } + + public static void clickDeleteThread(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.conversation__menu_delete_thread)).perform(click()); + } + + public static void toggleEmojiKeyboard() throws Exception { + onView(withId(R.id.emoji_toggle)).perform(click()); + } + + public static void typeMessage(String message) throws Exception { + typeTextAndCloseKeyboard(onView(withId(R.id.embedded_text_editor)), message); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityActions.java new file mode 100644 index 0000000000..915a0f2704 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityActions.java @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.content.Context; + +import org.thoughtcrime.securesms.R; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +public class ConversationListActivityActions { + + public static void dismissReminder() throws Exception { + onView(withId(R.id.cancel)).perform(click()); + } + + public static void clickNewConversation() throws Exception { + onView(withId(R.id.fab)).perform(click()); + } + + public static void clickNewGroup(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.text_secure_normal__menu_new_group)).perform(click()); + } + + public static void clickLock(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.text_secure_normal__menu_clear_passphrase)).perform(click()); + } + + public static void clickMarkAllRead(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.text_secure_normal__mark_all_as_read)).perform(click()); + } + + public static void clickImportExport(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.arrays__import_export)).perform(click()); + } + + public static void clickMyIdentity(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.arrays__my_identity_key)).perform(click()); + } + + public static void clickSettings(Context context) throws Exception { + openActionBarOverflowOrOptionsMenu(context); + onView(withText(R.string.text_secure_normal__menu_settings)).perform(click()); + } + + public static void deleteSelected() throws Exception { + onView(withId(R.id.menu_delete_selected)).perform(click()); + onView(withText(R.string.delete)).perform(click()); + } + + public static void cancelDeleteSelected() throws Exception { + onView(withId(R.id.menu_delete_selected)).perform(click()); + onView(withText(android.R.string.cancel)).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityTest.java new file mode 100644 index 0000000000..292f3e2051 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ConversationListActivityTest.java @@ -0,0 +1,279 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.widget.TextView; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.thoughtcrime.securesms.components.DefaultSmsReminder; +import org.thoughtcrime.securesms.components.ExpiredBuildReminder; +import org.thoughtcrime.securesms.components.PushRegistrationReminder; +import org.thoughtcrime.securesms.components.SystemSmsImportReminder; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; +import static android.support.test.espresso.Espresso.pressBack; +import static android.support.test.espresso.action.ViewActions.longClick; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; +import static org.thoughtcrime.securesms.EspressoUtil.addContact; +import static org.thoughtcrime.securesms.EspressoUtil.waitOn; +import static org.thoughtcrime.securesms.ViewMatchers.withRecyclerItem; +import static org.thoughtcrime.securesms.ViewMatchers.withRecyclerItemCount; + +@LargeTest +public class ConversationListActivityTest extends TextSecureEspressoTestCase { + private final static String TAG = ConversationListActivityTest.class.getSimpleName(); + + public ConversationListActivityTest() { + super(ConversationListActivity.class); + } + + private void checkOptionsMenuItemsDisplayed() throws Exception { + onView(withContentDescription(getContext().getString(R.string.conversation_list__menu_search))) + .check(matches(isDisplayed())); + + openActionBarOverflowOrOptionsMenu(getContext()); + onView(withText(R.string.text_secure_normal__menu_new_group)).check(matches(isDisplayed())); + onView(withText(R.string.text_secure_normal__mark_all_as_read)).check(matches(isDisplayed())); + onView(withText(R.string.arrays__import_export)).check(matches(isDisplayed())); + onView(withText(R.string.arrays__my_identity_key)).check(matches(isDisplayed())); + onView(withText(R.string.text_secure_normal__menu_settings)).check(matches(isDisplayed())); + + if (!TextSecurePreferences.isPasswordDisabled(getContext())) { + onView(withText(R.string.text_secure_normal__menu_clear_passphrase)) + .check(matches(isDisplayed())); + } + + pressBack(); + } + + private boolean checkReminderIsDisplayed() throws Exception { + boolean reminderVisible = true; + Integer reminderTitleResId = null; + Integer reminderTextResId = null; + + if (ExpiredBuildReminder.isEligible(getContext())) { + reminderTitleResId = R.string.reminder_header_expired_build; + reminderTextResId = R.string.reminder_header_expired_build_details; + } else if (DefaultSmsReminder.isEligible(getContext())) { + reminderTitleResId = R.string.reminder_header_sms_default_title; + reminderTextResId = R.string.reminder_header_sms_default_text; + } else if (SystemSmsImportReminder.isEligible(getContext())) { + reminderTitleResId = R.string.reminder_header_sms_import_title; + reminderTextResId = R.string.reminder_header_sms_import_text; + } else if (PushRegistrationReminder.isEligible(getContext())) { + reminderTitleResId = R.string.reminder_header_push_title; + reminderTextResId = R.string.reminder_header_push_text; + } else { + reminderVisible = false; + } + + if (reminderVisible) { + onView(withId(R.id.reminder_title)).check(matches(isDisplayed())); + onView(withId(R.id.reminder_title)).check(matches(withText(reminderTitleResId))); + onView(withId(R.id.reminder_text)).check(matches(isDisplayed())); + onView(withId(R.id.reminder_text)).check(matches(withText(reminderTextResId))); + } + + return reminderVisible; + } + + private void loadAndCheckState() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + checkOptionsMenuItemsDisplayed(); + checkReminderIsDisplayed(); + } + + public void testDismissAllReminders() throws Exception { + loadAndCheckState(); + + int expectedReminders = 0; + if (ExpiredBuildReminder.isEligible(getContext())) expectedReminders++; + if (DefaultSmsReminder.isEligible(getContext())) expectedReminders++; + if (SystemSmsImportReminder.isEligible(getContext())) expectedReminders++; + + Log.d(TAG, "expecting to see " + expectedReminders + " reminders"); + while (expectedReminders > 0) { + if (!checkReminderIsDisplayed()) { + throw new IllegalStateException("expected to see " + expectedReminders + " more reminders"); + } + + Log.d(TAG, "found reminder, dismissing now"); + ConversationListActivityActions.dismissReminder(); + expectedReminders--; + + ConversationListActivityActions.clickSettings(getContext()); + waitOn(ApplicationPreferencesActivity.class); + pressBack(); + waitOn(ConversationListActivity.class); + } + + if (checkReminderIsDisplayed() && !PushRegistrationReminder.isEligible(getContext())) { + throw new IllegalStateException("only expected to see " + expectedReminders + " reminders"); + } + } + + public void testClickNewConversation() throws Exception { + loadAndCheckState(); + ConversationListActivityActions.clickNewConversation(); + waitOn(NewConversationActivity.class); + } + + public void testClickNewGroup() throws Exception { + loadAndCheckState(); + ConversationListActivityActions.clickNewGroup(getContext()); + waitOn(GroupCreateActivity.class); + } + + public void testClickImportExport() throws Exception { + loadAndCheckState(); + ConversationListActivityActions.clickImportExport(getContext()); + waitOn(ImportExportActivity.class); + } + + public void testClickMyIdentity() throws Exception { + loadAndCheckState(); + ConversationListActivityActions.clickMyIdentity(getContext()); + waitOn(ViewLocalIdentityActivity.class); + } + + public void testClickSettings() throws Exception { + loadAndCheckState(); + ConversationListActivityActions.clickSettings(getContext()); + waitOn(ApplicationPreferencesActivity.class); + } + + public static Matcher isThreadFrom(final String contactName) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("is thread from: " + contactName); + } + + @Override + public boolean matchesSafely(Object object) { + if (!(object instanceof ConversationListItem)) { + return false; + } + + ConversationListItem itemView = (ConversationListItem) object; + TextView fromView = (TextView) itemView.findViewById(R.id.from); + return fromView.getText().toString().equals(contactName); + } + }; + } + + public static Matcher withThreadSnippet(final String snippet) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("is thread with snippet: " + snippet); + } + + @Override + public boolean matchesSafely(Object object) { + if (!(object instanceof ConversationListItem)) { + return false; + } + + ConversationListItem itemView = (ConversationListItem) object; + TextView snippetView = (TextView) itemView.findViewById(R.id.subject); + return snippetView.getText().toString().equals(snippet); + } + }; + } + + @SuppressWarnings("unchecked") + public void testSaveTextDraft() throws Exception { + final String CONTACT_NAME = "Clement Duval"; + final String CONTACT_NUMBER = "55555555555"; + final String DRAFT_MESSAGE = "I struck him in the name of liberty"; + final String DRAFT_SNIPPET = getContext().getString(R.string.ThreadRecord_draft) + " " + DRAFT_MESSAGE; + + addContact(getContext(), CONTACT_NAME, CONTACT_NUMBER); + loadAndCheckState(); + + ConversationListActivityActions.clickNewConversation(); + waitOn(NewConversationActivity.class); + NewConversationActivityActions.clickContactWithName(CONTACT_NAME); + waitOn(ConversationActivity.class); + ConversationActivityActions.typeMessage(DRAFT_MESSAGE); + pressBack(); + waitOn(ConversationListActivity.class); + + onView(withId(R.id.list)).check(matches( + withRecyclerItemCount(1L) + )); + onView(withId(R.id.list)).check(matches( + withRecyclerItem(allOf( + isDisplayed(), + isThreadFrom(CONTACT_NAME), + withThreadSnippet(DRAFT_SNIPPET))) + )); + } + + /* + this is known to fail on some older devices due to some espresso + related app-compat bug + */ + @SuppressWarnings("unchecked") + public void testSaveDeleteTextDraft() throws Exception { + final String CONTACT_NAME = "Clement Duval"; + final String CONTACT_NUMBER = "55555555555"; + final String DRAFT_MESSAGE = "I struck him in the name of liberty"; + final String DRAFT_SNIPPET = getContext().getString(R.string.ThreadRecord_draft) + " " + DRAFT_MESSAGE; + + addContact(getContext(), CONTACT_NAME, CONTACT_NUMBER); + loadAndCheckState(); + + ConversationListActivityActions.clickNewConversation(); + waitOn(NewConversationActivity.class); + NewConversationActivityActions.clickContactWithName(CONTACT_NAME); + waitOn(ConversationActivity.class); + ConversationActivityActions.typeMessage(DRAFT_MESSAGE); + pressBack(); + waitOn(ConversationListActivity.class); + + onView(withId(R.id.list)).check(matches( + withRecyclerItemCount(1L) + )); + onView(withId(R.id.list)).check(matches( + withRecyclerItem(allOf( + isDisplayed(), + isThreadFrom(CONTACT_NAME), + withThreadSnippet(DRAFT_SNIPPET))) + )); + + onView(withText(CONTACT_NAME)).perform(longClick()); + ConversationListActivityActions.deleteSelected(); + + onView(withId(R.id.list)).check(matches( + withRecyclerItemCount(0L) + )); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/EspressoUtil.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/EspressoUtil.java new file mode 100644 index 0000000000..5fac6acdf2 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/EspressoUtil.java @@ -0,0 +1,119 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.app.Activity; +import android.app.Instrumentation.ActivityMonitor; +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.ContactsContract; +import android.support.test.espresso.NoActivityResumedException; +import android.support.test.espresso.ViewInteraction; +import android.util.Log; + +import java.util.ArrayList; + +import static android.support.test.espresso.action.ViewActions.replaceText; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.Espresso.closeSoftKeyboard; +import static android.support.test.espresso.Espresso.pressBack; + +public class EspressoUtil { + private final static String TAG = EspressoUtil.class.getSimpleName(); + + public static void waitOn(Class clazz) { + Log.w(TAG, "waiting for " + clazz.getName()); + new ActivityMonitor(clazz.getName(), null, true).waitForActivityWithTimeout(10000); + } + + public static void actuallyCloseSoftKeyboard() throws Exception { + closeSoftKeyboard(); + Thread.sleep(800); + } + + public static void typeTextAndCloseKeyboard(ViewInteraction view, String text) throws Exception { + view.perform(typeText(text)); + actuallyCloseSoftKeyboard(); + } + + public static void replaceTextAndCloseKeyboard(ViewInteraction view, String text) throws Exception { + view.perform(replaceText(text)); + actuallyCloseSoftKeyboard(); + } + + public static void closeAllActivities() throws Exception { + for (int i = 0; i < 10; i++) { + try { + + pressBack(); + + } catch (NoActivityResumedException e) { + Log.d(TAG, "you made me do this, android"); + return; + } + } + + throw new IllegalStateException("what are you doing with 10 open activities?!"); + } + + public static long addContact(Context context, String name, String number) throws Exception { + ArrayList operations = new ArrayList<>(); + + operations.add(ContentProviderOperation + .newInsert(ContactsContract.RawContacts.CONTENT_URI) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null) + .build()); + + operations.add(ContentProviderOperation + .newInsert(ContactsContract.Data.CONTENT_URI) + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) + .build()); + + operations.add(ContentProviderOperation. + newInsert(ContactsContract.Data.CONTENT_URI) + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, number) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) + .build()); + + return context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations).length; + } + + public static void removeAllContacts(Context context) throws Exception { + ContentResolver contentResolver = context.getContentResolver(); + Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); + + try { + + while (cursor.moveToNext()) { + String contactKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); + Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, contactKey); + contentResolver.delete(contactUri, null, null); + } + + } finally { + cursor.close(); + } + } +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/GroupCreateActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/GroupCreateActivityTest.java new file mode 100644 index 0000000000..b9656c8136 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/GroupCreateActivityTest.java @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.support.test.espresso.matcher.ViewMatchers; +import android.test.suitebuilder.annotation.LargeTest; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.not; + +@LargeTest +public class GroupCreateActivityTest extends TextSecureEspressoTestCase { + + public GroupCreateActivityTest() { + super(ConversationListActivity.class); + } + + private void clickNewGroup() throws Exception { + ConversationListActivityActions.clickNewGroup(getContext()); + EspressoUtil.waitOn(GroupCreateActivity.class); + } + + public void testLayoutWithPush() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickNewGroup(); + + onView(ViewMatchers.withId(R.id.push_disabled)).check(matches(not(isDisplayed()))); + onView(withId(R.id.push_disabled_reason)).check(matches(not(isDisplayed()))); + } + + public void testLayoutWithoutPush() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + clickNewGroup(); + + onView(ViewMatchers.withId(R.id.push_disabled)).check(matches(isDisplayed())); + onView(withId(R.id.push_disabled_reason)).check(matches(isDisplayed())); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ImportExportActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ImportExportActivityTest.java new file mode 100644 index 0000000000..e0f63b8ac8 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ImportExportActivityTest.java @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.support.test.espresso.matcher.ViewMatchers; +import android.test.suitebuilder.annotation.LargeTest; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.swipeLeft; +import static android.support.test.espresso.action.ViewActions.swipeRight; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; + +@LargeTest +public class ImportExportActivityTest extends TextSecureEspressoTestCase { + + public ImportExportActivityTest() { + super(ConversationListActivity.class); + } + + private void checkImportLayout() throws Exception { + onView(ViewMatchers.withId(R.id.import_sms)).check(matches(isDisplayed())); + onView(withId(R.id.import_encrypted_backup)).check(matches(isDisplayed())); + onView(withId(R.id.import_plaintext_backup)).check(matches(isDisplayed())); + } + + private void checkExportLayout() throws Exception { + onView(withId(R.id.export_plaintext_backup)).check(matches(isDisplayed())); + } + + private void clickImportExport() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + ConversationListActivityActions.clickImportExport(getContext()); + EspressoUtil.waitOn(ImportExportActivity.class); + } + + public void testLayout() throws Exception { + clickImportExport(); + checkImportLayout(); + onView(withId(R.id.import_sms)).perform(swipeLeft()); + checkExportLayout(); + onView(withId(R.id.export_plaintext_backup)).perform(swipeRight()); + checkImportLayout(); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityActions.java new file mode 100644 index 0000000000..e9fc2ba935 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityActions.java @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; + +public class NewConversationActivityActions { + + public static void filterNameOrNumber(String nameOrNumber) throws Exception { + EspressoUtil.replaceTextAndCloseKeyboard(onView(withId(R.id.filter)), nameOrNumber); + } + + @SuppressWarnings("unchecked") + public static void clickContactWithName(String name) throws Exception { + onView(allOf(withId(R.id.name), withText(name))).perform(click()); + } + + @SuppressWarnings("unchecked") + public static void clickContactWithNumber(String number) throws Exception { + onView(allOf(withId(R.id.number), withText(containsString(number)))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityTest.java new file mode 100644 index 0000000000..3f4f9b81af --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/NewConversationActivityTest.java @@ -0,0 +1,125 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.test.suitebuilder.annotation.LargeTest; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +import static org.hamcrest.Matchers.allOf; + +@LargeTest +public class NewConversationActivityTest extends TextSecureEspressoTestCase { + + final String[][] TEST_CONTACTS = { + {"Nadezhda Tolokonnikova", "11111111111", "Nad", "ezh", "ova"}, + {"Jules Bonnot", "22222222222", "Jul", "nno", "not"}, + {"Masha Kolenkia", "33333333333", "Mas", "len", "kia"}, + {"Chairman Meow", "44444444444", "Cha", "rma", "eow"}, + {"Clement Duval", "55555555555", "Cle", "eme", "val"}, + {"Nestor Makhno", "66666666666", "Nes", "sto", "hno"}, + {"Wilhelm Reich", "77777777777", "Wil", "hel", "ich"} + }; + + public NewConversationActivityTest() { + super(ConversationListActivity.class); + } + + private void populateContacts() throws Exception { + for(String[] TEST_CONTACT : TEST_CONTACTS) { + EspressoUtil.addContact(getContext(), TEST_CONTACT[0], TEST_CONTACT[1]); + } + } + + private void clickNewConversation() throws Exception{ + ConversationListActivityActions.clickNewConversation(); + EspressoUtil.waitOn(NewConversationActivity.class); + EspressoUtil.actuallyCloseSoftKeyboard(); + } + + @SuppressWarnings("unchecked") + public void testContactFilterPrefix() throws Exception { + populateContacts(); + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickNewConversation(); + + for (String[] TEST_CONTACT : TEST_CONTACTS) { + NewConversationActivityActions.filterNameOrNumber(TEST_CONTACT[2]); + onView(allOf(withId(R.id.name), withText(TEST_CONTACT[0]))).check(matches(isDisplayed())); + } + } + + // this is known to fail on some devices, see #2378 + @SuppressWarnings("unchecked") + public void testContactFilterMiddle() throws Exception { + populateContacts(); + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickNewConversation(); + + for (String[] TEST_CONTACT : TEST_CONTACTS) { + NewConversationActivityActions.filterNameOrNumber(TEST_CONTACT[3]); + onView(allOf(withId(R.id.name), withText(TEST_CONTACT[0]))).check(matches(isDisplayed())); + } + } + + // this is known to fail on some devices, see #2378 + @SuppressWarnings("unchecked") + public void testContactFilterPostfix() throws Exception { + populateContacts(); + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickNewConversation(); + + for (String[] TEST_CONTACT : TEST_CONTACTS) { + NewConversationActivityActions.filterNameOrNumber(TEST_CONTACT[4]); + onView(allOf(withId(R.id.name), withText(TEST_CONTACT[0]))).check(matches(isDisplayed())); + } + } + + public void testNewConversationWithNonPushContact() throws Exception { + populateContacts(); + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickNewConversation(); + + NewConversationActivityActions.clickContactWithName("Chairman Meow"); + EspressoUtil.waitOn(ConversationActivity.class); + } + + @SuppressWarnings("unchecked") + public void testNewConversationWithUnknownWhenRegistered() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickNewConversation(); + + NewConversationActivityActions.filterNameOrNumber("8888888888"); + NewConversationActivityActions.clickContactWithNumber("8888888888"); + EspressoUtil.waitOn(ConversationActivity.class); + } + + @SuppressWarnings("unchecked") + public void testNewConversationWithUnknownWhenUnregistered() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + clickNewConversation(); + + NewConversationActivityActions.filterNameOrNumber("8888888888"); + NewConversationActivityActions.clickContactWithNumber("8888888888"); + EspressoUtil.waitOn(ConversationActivity.class); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityActions.java new file mode 100644 index 0000000000..5d83d9533d --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityActions.java @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.ViewMatchers.withId; + +public class PassphraseChangeActivityActions { + + public static void clickOk() throws Exception { + onView(withId(R.id.ok_button)).perform(click()); + } + + public static void clickCancel() throws Exception { + onView(withId(R.id.cancel_button)).perform(click()); + } + + public static void typeNewPassphrase(String passphrase, String repeat) throws Exception { + EspressoUtil.typeTextAndCloseKeyboard(onView(withId(R.id.new_passphrase)), passphrase); + EspressoUtil.typeTextAndCloseKeyboard(onView(withId(R.id.repeat_passphrase)), repeat); + } + + public static void typeNewPassphrase(String passphrase) throws Exception { + typeNewPassphrase(passphrase, passphrase); + } + + public static void typeChangePassphrase(String oldPassphrase, String newPassphrase) throws Exception { + EspressoUtil.typeTextAndCloseKeyboard(onView(withId(R.id.old_passphrase)), oldPassphrase); + EspressoUtil.typeTextAndCloseKeyboard(onView(withId(R.id.new_passphrase)), newPassphrase); + EspressoUtil.typeTextAndCloseKeyboard(onView(withId(R.id.repeat_passphrase)), newPassphrase); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityTest.java new file mode 100644 index 0000000000..c49140c5a2 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/PassphraseChangeActivityTest.java @@ -0,0 +1,119 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.test.suitebuilder.annotation.LargeTest; + +import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragmentActions; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.not; + +@LargeTest +public class PassphraseChangeActivityTest extends TextSecureEspressoTestCase { + + private static final String ORIGINAL_PASSPHRASE = "badpass"; + private static final String CHANGE_PASSPHRASE = "worse"; + + public PassphraseChangeActivityTest() { + super(ConversationListActivity.class); + } + + private void checkState() throws Exception { + EspressoUtil.actuallyCloseSoftKeyboard(); + + if (TextSecurePreferences.isPasswordDisabled(getContext())) { + onView(withId(R.id.old_passphrase)).check(matches(not(isDisplayed()))); + onView(withId(R.id.old_passphrase_label)).check(matches(not(isDisplayed()))); + } else { + onView(withId(R.id.old_passphrase)).check(matches(isDisplayed())); + onView(withId(R.id.old_passphrase_label)).check(matches(isDisplayed())); + } + + onView(withId(R.id.new_passphrase)).check(matches(isDisplayed())); + onView(withId(R.id.repeat_passphrase)).check(matches(isDisplayed())); + } + + private void clickEnablePassphraseAndCheckState() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + ConversationListActivityActions.clickSettings(getContext()); + EspressoUtil.waitOn(ApplicationPreferencesActivity.class); + ApplicationPreferencesActivityActions.clickAppProtectionSetting(); + AppProtectionPreferenceFragmentActions.clickEnablePassphrase(); + EspressoUtil.waitOn(PassphraseChangeActivity.class); + checkState(); + } + + public void testEnablePassphrase() throws Exception { + clickEnablePassphraseAndCheckState(); + PassphraseChangeActivityActions.typeNewPassphrase(ORIGINAL_PASSPHRASE); + PassphraseChangeActivityActions.clickOk(); + + EspressoUtil.waitOn(ApplicationPreferencesActivity.class); + assertTrue(!TextSecurePreferences.isPasswordDisabled(getContext())); + } + + public void testEnablePassphraseCancel() throws Exception { + clickEnablePassphraseAndCheckState(); + EspressoUtil.actuallyCloseSoftKeyboard(); + PassphraseChangeActivityActions.clickCancel(); + + EspressoUtil.waitOn(ApplicationPreferencesActivity.class); + assertTrue(TextSecurePreferences.isPasswordDisabled(getContext())); + } + + public void testEnablePassphraseDoesNotMatch() throws Exception { + clickEnablePassphraseAndCheckState(); + PassphraseChangeActivityActions.typeNewPassphrase(ORIGINAL_PASSPHRASE, "nope"); + PassphraseChangeActivityActions.clickOk(); + PassphraseChangeActivityActions.clickCancel(); + + EspressoUtil.waitOn(ApplicationPreferencesActivity.class); + assertTrue(TextSecurePreferences.isPasswordDisabled(getContext())); + } + + private void clickChangePassphraseAndCheckState() throws Exception { + testEnablePassphrase(); + AppProtectionPreferenceFragmentActions.clickChangePassphrase(); + EspressoUtil.waitOn(PassphraseChangeActivity.class); + checkState(); + } + + public void testChangePassphrase() throws Exception { + clickChangePassphraseAndCheckState(); + PassphraseChangeActivityActions.typeChangePassphrase(ORIGINAL_PASSPHRASE, CHANGE_PASSPHRASE); + PassphraseChangeActivityActions.clickOk(); + + EspressoUtil.waitOn(ApplicationPreferencesActivity.class); + assertTrue(!TextSecurePreferences.isPasswordDisabled(getContext())); + } + + public void testChangePassphraseCancel() throws Exception { + clickChangePassphraseAndCheckState(); + + EspressoUtil.actuallyCloseSoftKeyboard(); + PassphraseChangeActivityActions.clickCancel(); + + EspressoUtil.waitOn(ApplicationPreferencesActivity.class); + assertTrue(!TextSecurePreferences.isPasswordDisabled(getContext())); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityActions.java new file mode 100644 index 0000000000..99aa28feca --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityActions.java @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +public class RegistrationActivityActions { + + public static void typeCountryCode(String countryCode) throws Exception { + EspressoUtil.replaceTextAndCloseKeyboard(onView(withId(R.id.country_code)), countryCode); + } + + public static void typeLocalNumber(String localNumber) throws Exception { + EspressoUtil.replaceTextAndCloseKeyboard(onView(withId(R.id.number)), localNumber); + } + + public static void clickRegister() throws Exception { + onView(withId(R.id.registerButton)).perform(click()); + } + + public static void clickCancel() throws Exception { + onView(withId(R.id.skipButton)).perform(click()); + } + + public static void clickContinue() throws Exception { + onView(withText(R.string.RegistrationActivity_continue)).perform(click()); + } + + public static void clickEdit() throws Exception { + onView(withText(R.string.RegistrationActivity_edit)).perform(click()); + } + + public static void enterPstnNumber(String pstnCountry, String pstnNumber) throws Exception { + typeCountryCode(pstnCountry); + typeLocalNumber(pstnNumber); + } + + public static void sleepTillRegistrationConnected() { + long timeout = 0L; + while (timeout < 10000L) { + try { + + Thread.sleep(1000); + timeout += 1000; + onView(withId(R.id.verification_progress)).check(matches(isDisplayed())); + return; + + } catch (InterruptedException e) { } + catch (AssertionError e) { } + } + throw new AssertionError("failed to connect to registration servers within 10 seconds"); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityTest.java new file mode 100644 index 0000000000..f8c112c5a0 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationActivityTest.java @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.support.test.espresso.matcher.ViewMatchers; +import android.test.suitebuilder.annotation.LargeTest; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.not; + +@LargeTest +public class RegistrationActivityTest extends TextSecureEspressoTestCase { + + public RegistrationActivityTest() { + super(ConversationListActivity.class); + } + + private void loadStateAndCheck() throws Exception { + loadActivity(RegistrationActivity.class, STATE_BASE); + onView(ViewMatchers.withId(R.id.skipButton)).check(matches(not(isDisplayed()))); + onView(withId(R.id.registerButton)).check(matches(isDisplayed())); + } + + public void testRegister() throws Exception { + loadStateAndCheck(); + RegistrationActivityActions.enterPstnNumber(pstnCountry, pstnNumber); + sleepThroughRegistrationLimit(); + RegistrationActivityActions.clickRegister(); + RegistrationActivityActions.clickContinue(); + EspressoUtil.waitOn(RegistrationProgressActivity.class); + RegistrationActivityActions.sleepTillRegistrationConnected(); + RegistrationBypassUtil.receiveVerificationSms(getContext(), pstnCountry, pstnNumber, verificationCode); + EspressoUtil.waitOn(ConversationListActivity.class); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationBypassUtil.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationBypassUtil.java new file mode 100644 index 0000000000..be220292d7 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/RegistrationBypassUtil.java @@ -0,0 +1,95 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Build.VERSION; +import android.util.Log; + +import org.thoughtcrime.securesms.service.SmsListener; +import org.thoughtcrime.securesms.util.SmsUtil; +import org.thoughtcrime.securesms.test.R; + +public class RegistrationBypassUtil { + + private static final String TAG = RegistrationBypassUtil.class.getSimpleName(); + + private static String getKeyForDevice() { + Log.d(TAG, "release: " + VERSION.RELEASE + ", model: " + Build.MODEL); + return VERSION.RELEASE + " - " + Build.MODEL; + } + + public static String getPstnStringForDevice(Context context) { + final String DEVICE_KEY = getKeyForDevice(); + final String[] TEST_DEVICES = context.getResources().getStringArray(R.array.test_devices); + final String[] PSTN_STRINGS = context.getResources().getStringArray(R.array.test_pstn_numbers); + int deviceIndex = -1; + + if (TEST_DEVICES.length == 0 || PSTN_STRINGS.length != TEST_DEVICES.length) { + throw new AssertionError("one test device per pstn number required"); + } + + for (int i = 0; i < TEST_DEVICES.length; i++) { + if (TEST_DEVICES[i].equals(DEVICE_KEY)) { + deviceIndex = i; + break; + } + } + + if (deviceIndex < 0) return PSTN_STRINGS[PSTN_STRINGS.length - 1]; + else return PSTN_STRINGS[deviceIndex]; + } + + public static String getVerificationCodeForPstnString(Context context, String pstnString) { + final String[] PSTN_STRINGS = context.getResources().getStringArray(R.array.test_pstn_numbers); + final String[] VERIFY_CODES = context.getResources().getStringArray(R.array.test_verification_codes); + int pstnIndex = -1; + + if (PSTN_STRINGS.length == 0 || PSTN_STRINGS.length != VERIFY_CODES.length) { + throw new AssertionError("one verification code per pstn number required"); + } + + for (int i = 0; i < PSTN_STRINGS.length; i++) { + if (PSTN_STRINGS[i].equals(pstnString)) { + pstnIndex = i; + break; + } + } + + if (pstnIndex < 0) throw new AssertionError("no verification code for " + pstnString); + else return VERIFY_CODES[pstnIndex]; + } + + public static void receiveVerificationSms(Context context, + String pstnCountry, + String pstnNumber, + String verificationCode) + throws Exception + { + final String smsVerifyMessage = "Your TextSecure verification code: " + verificationCode; + final Intent smsVerifyIntent = SmsUtil.buildSmsReceivedIntent(pstnCountry + pstnNumber, smsVerifyMessage); + + try { + new SmsListener().onReceive(context, smsVerifyIntent); + } catch (IllegalStateException e) { + Log.w(TAG, "some api levels are picky with abortBroadcast()", e); + } + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureEspressoTestCase.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureEspressoTestCase.java new file mode 100644 index 0000000000..05f603af6b --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureEspressoTestCase.java @@ -0,0 +1,132 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.app.Activity; +import android.content.Context; +import android.preference.PreferenceManager; +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; + +import org.thoughtcrime.securesms.crypto.MasterSecretUtil; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +public class TextSecureEspressoTestCase extends ActivityInstrumentationTestCase2 { + + private static final String TAG = TextSecureEspressoTestCase.class.getSimpleName(); + + public static final int STATE_BASE = 0x00000000; + public static final int STATE_REGISTRATION_SKIPPED = 0x00000001; + public static final int STATE_REGISTERED = 0x00000002; + + private static final long REGISTRATION_RATE_LIMIT_MS = 60000 + 10000; + private static long TIME_LAST_REGISTERED = 0L; + + protected String pstnCountry; + protected String pstnNumber; + protected String verificationCode; + + public TextSecureEspressoTestCase(Class clazz) { + super(clazz); + } + + protected static void sleepThroughRegistrationLimit() { + long msPassedSinceReg = System.currentTimeMillis() - TIME_LAST_REGISTERED; + long msSleepRemaining = REGISTRATION_RATE_LIMIT_MS - msPassedSinceReg; + + Log.d(TAG, "sleeping for " + msSleepRemaining + "ms to avoid registration rate limit"); + while (msSleepRemaining > 0) { + try { + + Thread.sleep(1000); + msSleepRemaining -= 1000; + + } catch (InterruptedException e) { } + } + TIME_LAST_REGISTERED = System.currentTimeMillis(); + } + + protected Context getContext() { + return getInstrumentation().getTargetContext(); + } + + private void initBaseState() throws Exception { + EspressoUtil.removeAllContacts(getContext()); + DatabaseFactory.getDraftDatabase(getContext()).clearAllDrafts(); + DatabaseFactory.getThreadDatabase(getContext()).deleteAllConversations(); + PreferenceManager.getDefaultSharedPreferences(getContext()).edit().clear().commit(); + getContext().getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0).edit().clear().commit(); + getContext().getSharedPreferences("SecureSMS", 0).edit().clear().commit(); + } + + protected void loadActivity(Class clazz, int state) throws Exception { + switch (state) { + case STATE_REGISTRATION_SKIPPED: + TextSecurePreferences.setPromptedPushRegistration(getContext(), true); + getActivity(); + break; + + case STATE_REGISTERED: + getActivity(); + EspressoUtil.waitOn(RegistrationActivity.class); + RegistrationActivityActions.enterPstnNumber(pstnCountry, pstnNumber); + sleepThroughRegistrationLimit(); + RegistrationActivityActions.clickRegister(); + RegistrationActivityActions.clickContinue(); + EspressoUtil.waitOn(RegistrationProgressActivity.class); + RegistrationActivityActions.sleepTillRegistrationConnected(); + RegistrationBypassUtil.receiveVerificationSms(getContext(), pstnCountry, pstnNumber, verificationCode); + break; + + default: + getActivity(); + } + + EspressoUtil.waitOn(clazz); + } + + private void initMockPstnState() throws Exception { + final Context context = getInstrumentation().getContext(); + final String pstnString = RegistrationBypassUtil.getPstnStringForDevice(context); + + pstnCountry = pstnString.split(":")[0].replace("+", ""); + pstnNumber = pstnString.split(":")[1]; + verificationCode = RegistrationBypassUtil.getVerificationCodeForPstnString(context, pstnString); + + Log.d(TAG, "using pstn id of " + pstnString + " with verification code " + verificationCode); + } + + @Override + public void setUp() throws Exception { + System.setProperty("dexmaker.dexcache", getContext().getCacheDir().getPath()); + super.setUp(); + + if (pstnCountry == null || pstnNumber == null || verificationCode == null) { + initMockPstnState(); + } + initBaseState(); + } + + @Override + public void tearDown() throws Exception { + EspressoUtil.actuallyCloseSoftKeyboard(); + EspressoUtil.closeAllActivities(); + super.tearDown(); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureWakingTestRunner.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureWakingTestRunner.java new file mode 100644 index 0000000000..0e439a21dc --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/TextSecureWakingTestRunner.java @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.app.Application; +import android.app.KeyguardManager; +import android.content.Context; +import android.os.PowerManager; +import android.support.test.runner.AndroidJUnitRunner; +import android.util.Log; + +public class TextSecureWakingTestRunner extends AndroidJUnitRunner { + + @Override public void onStart() { + runOnMainSync(new Runnable() { + @Override public void run() { + Application app = (Application) getTargetContext().getApplicationContext(); + String simpleName = TextSecureWakingTestRunner.class.getSimpleName(); + + ((KeyguardManager) app.getSystemService(Context.KEYGUARD_SERVICE)) + .newKeyguardLock(simpleName) + .disableKeyguard(); + + ((PowerManager) app.getSystemService(Context.POWER_SERVICE)) + .newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, simpleName) + .acquire(); + } + }); + super.onStart(); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewLocalIdentityActivityTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewLocalIdentityActivityTest.java new file mode 100644 index 0000000000..0382aa2c73 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewLocalIdentityActivityTest.java @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.support.test.espresso.matcher.ViewMatchers; +import android.test.suitebuilder.annotation.LargeTest; + +import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; +import org.whispersystems.libaxolotl.IdentityKey; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +@LargeTest +public class ViewLocalIdentityActivityTest extends TextSecureEspressoTestCase { + + public ViewLocalIdentityActivityTest() { + super(ConversationListActivity.class); + } + + private void clickMyIdentity() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + ConversationListActivityActions.clickMyIdentity(getContext()); + EspressoUtil.waitOn(ViewLocalIdentityActivity.class); + } + + public void testLayout() throws Exception { + clickMyIdentity(); + final IdentityKey idKey = IdentityKeyUtil.getIdentityKey(getContext()); + onView(ViewMatchers.withId(R.id.identity_fingerprint)).check(matches(withText(idKey.getFingerprint()))); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewMatchers.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewMatchers.java new file mode 100644 index 0000000000..bcabb0e407 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/ViewMatchers.java @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +public class ViewMatchers { + + public static Matcher withRecyclerItem(final Matcher itemMatcher) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("with recycler item: "); + itemMatcher.describeTo(description); + } + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof RecyclerView)) { + return false; + } + + RecyclerView recyclerView = ((RecyclerView) view); + for (int i = 0; i < recyclerView.getChildCount(); i++) { + if (itemMatcher.matches(recyclerView.getChildAt(i))) { + return true; + } + } + return false; + } + }; + } + + public static Matcher withRecyclerItemCount(final long itemCount) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("with recycler item count: " + itemCount); + } + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof RecyclerView)) { + return false; + } + + RecyclerView recyclerView = ((RecyclerView) view); + return recyclerView.getChildCount() == itemCount; + } + }; + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentActions.java new file mode 100644 index 0000000000..2fad603548 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentActions.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; + +public class AdvancedPreferenceFragmentActions { + + public static void clickTextSecureMessages() throws Exception { + onData(Matchers.allOf(withKey("pref_toggle_push_messaging"))).perform(click()); + } + + public static void clickEnterKeySends() throws Exception { + onData(Matchers.allOf(withKey("pref_enter_sends"))).perform(click()); + } + + public static void clickChooseIdentity() throws Exception { + onData(Matchers.allOf(withKey("pref_choose_identity"))).perform(click()); + } + + public static void clickSubmitDebugLog() throws Exception { + onData(Matchers.allOf(withKey("pref_submit_debug_logs"))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentTest.java new file mode 100644 index 0000000000..c2a4e78ebb --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragmentTest.java @@ -0,0 +1,112 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import android.test.suitebuilder.annotation.LargeTest; + +import org.hamcrest.Matchers; +import org.thoughtcrime.securesms.ApplicationPreferencesActivity; +import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.LogSubmitActivity; +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.RegistrationActivity; +import org.thoughtcrime.securesms.contacts.ContactIdentityManager; +import org.thoughtcrime.securesms.ApplicationPreferencesActivityActions; +import org.thoughtcrime.securesms.ConversationListActivityActions; +import org.thoughtcrime.securesms.TextSecureEspressoTestCase; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; +import static android.support.test.espresso.matcher.ViewMatchers.isChecked; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isNotChecked; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.thoughtcrime.securesms.EspressoUtil.waitOn; + +@LargeTest +public class AdvancedPreferenceFragmentTest extends TextSecureEspressoTestCase { + + public AdvancedPreferenceFragmentTest() { + super(ConversationListActivity.class); + } + + private void checkAllPreferencesDisplayed() throws Exception { + onData(Matchers.allOf(withKey("pref_toggle_push_messaging"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_enter_sends"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_submit_debug_logs"))) + .check(matches(isDisplayed())); + + ContactIdentityManager identity = ContactIdentityManager.getInstance(getContext()); + if (!identity.isSelfIdentityAutoDetected()) { + onData(Matchers.allOf(withKey("pref_choose_identity"))) + .check(matches(isDisplayed())); + } + } + + private void checkViewsMatchPreferences() throws Exception { + if (TextSecurePreferences.isPushRegistered(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_toggle_push_messaging")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_toggle_push_messaging")))); + } + + if (TextSecurePreferences.isEnterSendsEnabled(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_enter_sends")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_enter_sends")))); + } + } + + private void clickAdvancedSettingAndCheckState() throws Exception { + ConversationListActivityActions.clickSettings(getContext()); + waitOn(ApplicationPreferencesActivity.class); + ApplicationPreferencesActivityActions.clickAdvancedSetting(); + + checkAllPreferencesDisplayed(); + checkViewsMatchPreferences(); + } + + public void testEnableTextSecureMessages() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + clickAdvancedSettingAndCheckState(); + AdvancedPreferenceFragmentActions.clickTextSecureMessages(); + waitOn(RegistrationActivity.class); + } + + public void testDisableTextSecureMessages() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTERED); + clickAdvancedSettingAndCheckState(); + AdvancedPreferenceFragmentActions.clickTextSecureMessages(); + onView(withText(R.string.ApplicationPreferencesActivity_disable_push_messages)) + .check(matches(isDisplayed())); + onView(withText(android.R.string.cancel)).perform(click()); + } + + public void testSubmitDebugLog() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + clickAdvancedSettingAndCheckState(); + AdvancedPreferenceFragmentActions.clickSubmitDebugLog(); + waitOn(LogSubmitActivity.class); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentActions.java new file mode 100644 index 0000000000..323c7b124c --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentActions.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import org.hamcrest.Matchers; +import org.thoughtcrime.securesms.R; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +public class AppProtectionPreferenceFragmentActions { + + public static void clickEnablePassphrase() throws Exception { + onData(Matchers.allOf(withKey("pref_enable_passphrase_temporary"))).perform(click()); + } + + public static void disablePassphrase() throws Exception { + clickEnablePassphrase(); + onView(withText(R.string.ApplicationPreferencesActivity_disable)).perform(click()); + } + + public static void clickChangePassphrase() throws Exception { + onData(Matchers.allOf(withKey("pref_change_passphrase"))).perform(click()); + } + + public static void clickTimeoutPassphrase() throws Exception { + onData(Matchers.allOf(withKey("pref_timeout_passphrase"))).perform(click()); + } + + public static void clickScreenSecurity() throws Exception { + onData(Matchers.allOf(withKey("pref_screen_security"))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentTest.java new file mode 100644 index 0000000000..3cc9167e19 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppProtectionPreferenceFragmentTest.java @@ -0,0 +1,136 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import android.os.Build; +import android.test.suitebuilder.annotation.LargeTest; + +import org.hamcrest.Matchers; +import org.thoughtcrime.securesms.ApplicationPreferencesActivity; +import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.PassphraseChangeActivity; +import org.thoughtcrime.securesms.ApplicationPreferencesActivityActions; +import org.thoughtcrime.securesms.ConversationListActivityActions; +import org.thoughtcrime.securesms.PassphraseChangeActivityActions; +import org.thoughtcrime.securesms.TextSecureEspressoTestCase; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; +import static android.support.test.espresso.matcher.ViewMatchers.isChecked; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isNotChecked; +import static org.thoughtcrime.securesms.EspressoUtil.waitOn; + +@LargeTest +public class AppProtectionPreferenceFragmentTest extends TextSecureEspressoTestCase { + + private static final String ORIGINAL_PASSPHRASE = "badpass"; + + public AppProtectionPreferenceFragmentTest() { + super(ConversationListActivity.class); + } + + private void checkAllPreferencesDisplayed() throws Exception { + onData(Matchers.allOf(withKey("pref_enable_passphrase_temporary"))).check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_change_passphrase"))).check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_timeout_passphrase"))).check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_timeout_interval"))).check(matches(isDisplayed())); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + onData(Matchers.allOf(withKey("pref_screen_security"))) + .check(matches(isDisplayed())); + } + } + + private void checkViewsMatchPreferences() throws Exception { + if (!TextSecurePreferences.isPasswordDisabled(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_enable_passphrase_temporary")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_enable_passphrase_temporary")))); + } + + if (TextSecurePreferences.isPassphraseTimeoutEnabled(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_timeout_passphrase")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_timeout_passphrase")))); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + if (TextSecurePreferences.isScreenSecurityEnabled(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_screen_security")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_screen_security")))); + } + } + } + + private void checkState() throws Exception { + checkAllPreferencesDisplayed(); + checkViewsMatchPreferences(); + } + + private void clickAppProtectionSettingAndCheckState() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + ConversationListActivityActions.clickSettings(getContext()); + waitOn(ApplicationPreferencesActivity.class); + ApplicationPreferencesActivityActions.clickAppProtectionSetting(); + checkState(); + } + + public void testEnablePassphrase() throws Exception { + clickAppProtectionSettingAndCheckState(); + + AppProtectionPreferenceFragmentActions.clickEnablePassphrase(); + waitOn(PassphraseChangeActivity.class); + PassphraseChangeActivityActions.typeNewPassphrase(ORIGINAL_PASSPHRASE); + PassphraseChangeActivityActions.clickOk(); + waitOn(ApplicationPreferencesActivity.class); + + isChecked().matches(onData(Matchers.allOf(withKey("pref_enable_passphrase_temporary")))); + checkState(); + } + + public void testDisablePassphrase() throws Exception { + testEnablePassphrase(); + AppProtectionPreferenceFragmentActions.disablePassphrase(); + + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_enable_passphrase_temporary")))); + checkState(); + } + + public void testEnablePassphraseTimeout() throws Exception { + testEnablePassphrase(); + AppProtectionPreferenceFragmentActions.clickTimeoutPassphrase(); + + isChecked().matches(onData(Matchers.allOf(withKey("pref_timeout_passphrase")))); + checkState(); + } + + public void testDisableScreenSecurity() throws Exception { + clickAppProtectionSettingAndCheckState(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return; + } + + AppProtectionPreferenceFragmentActions.clickScreenSecurity(); + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_screen_security")))); + checkState(); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentActions.java new file mode 100644 index 0000000000..fd2bebed1b --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentActions.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; + +public class AppearancePreferenceFragmentActions { + + public static void clickTheme() throws Exception { + onData(Matchers.allOf(withKey("pref_theme"))).perform(click()); + } + + public static void clickLanguage() throws Exception { + onData(Matchers.allOf(withKey("pref_language"))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentTest.java new file mode 100644 index 0000000000..679d36d653 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/AppearancePreferenceFragmentTest.java @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import android.test.suitebuilder.annotation.LargeTest; + +import org.hamcrest.Matchers; +import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.TextSecureEspressoTestCase; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; +import static android.support.test.espresso.matcher.PreferenceMatchers.withSummaryText; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; + +@LargeTest +public class AppearancePreferenceFragmentTest extends TextSecureEspressoTestCase { + + public AppearancePreferenceFragmentTest() { + super(ConversationListActivity.class); + } + + private void checkAllPreferencesDisplayed() throws Exception { + onData(Matchers.allOf(withKey("pref_theme"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_language"))) + .check(matches(isDisplayed())); + } + + private void checkViewsMatchPreferences() throws Exception { + // todo :| + final String theme = TextSecurePreferences.getTheme(getContext()); + onData(Matchers.allOf(withKey("pref_theme"), withSummaryText(theme))) + .check(matches(isDisplayed())); + + final String language = TextSecurePreferences.getTheme(getContext()); + onData(Matchers.allOf(withKey("pref_language"), withSummaryText(language))) + .check(matches(isDisplayed())); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentActions.java new file mode 100644 index 0000000000..a19e6ff83b --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentActions.java @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; + +public class NotificationsPreferenceFragmentActions { + + public static void clickEnableNotifications() throws Exception { + onData(Matchers.allOf(withKey("pref_key_enable_notifications"))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentTest.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentTest.java new file mode 100644 index 0000000000..d9371cf8d4 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragmentTest.java @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import android.test.suitebuilder.annotation.LargeTest; + +import org.hamcrest.Matchers; +import org.thoughtcrime.securesms.ApplicationPreferencesActivity; +import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.ApplicationPreferencesActivityActions; +import org.thoughtcrime.securesms.ConversationListActivityActions; +import org.thoughtcrime.securesms.TextSecureEspressoTestCase; +import org.thoughtcrime.securesms.util.TextSecurePreferences; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; +import static android.support.test.espresso.matcher.ViewMatchers.isChecked; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isNotChecked; +import static org.thoughtcrime.securesms.EspressoUtil.waitOn; + +@LargeTest +public class NotificationsPreferenceFragmentTest extends TextSecureEspressoTestCase { + + public NotificationsPreferenceFragmentTest() { + super(ConversationListActivity.class); + } + + private void checkAllPreferencesDisplayed() throws Exception { + onData(Matchers.allOf(withKey("pref_key_enable_notifications"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_key_ringtone"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_key_vibrate"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_led_color"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_led_blink"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_key_inthread_notifications"))) + .check(matches(isDisplayed())); + onData(Matchers.allOf(withKey("pref_repeat_alerts"))) + .check(matches(isDisplayed())); + } + + private void checkViewsMatchPreferences() throws Exception { + if (TextSecurePreferences.isNotificationsEnabled(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_key_enable_notifications")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_key_enable_notifications")))); + } + + if (TextSecurePreferences.isNotificationVibrateEnabled(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_key_vibrate")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_key_vibrate")))); + } + + if (TextSecurePreferences.isInThreadNotifications(getContext())) { + isChecked().matches(onData(Matchers.allOf(withKey("pref_key_inthread_notifications")))); + } else { + isNotChecked().matches(onData(Matchers.allOf(withKey("pref_key_inthread_notifications")))); + } + } + + private void clickNotificationsSettingAndCheckState() throws Exception { + loadActivity(ConversationListActivity.class, STATE_REGISTRATION_SKIPPED); + ConversationListActivityActions.clickSettings(getContext()); + waitOn(ApplicationPreferencesActivity.class); + ApplicationPreferencesActivityActions.clickNotificationsSetting(); + + checkAllPreferencesDisplayed(); + checkViewsMatchPreferences(); + } + + public void testEnableNotifications() throws Exception { + clickNotificationsSettingAndCheckState(); + NotificationsPreferenceFragmentActions.clickEnableNotifications(); + isChecked().matches(onData(Matchers.allOf(withKey("pref_key_enable_notifications")))); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/SmsMmsPreferenceFragmentActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/SmsMmsPreferenceFragmentActions.java new file mode 100644 index 0000000000..c9f6b75f8e --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/SmsMmsPreferenceFragmentActions.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; + +public class SmsMmsPreferenceFragmentActions { + + public static void clickReceiveAllSms() throws Exception { + onData(Matchers.allOf(withKey("pref_all_sms"))).perform(click()); + } + + public static void clickReceiveAllMms() throws Exception { + onData(Matchers.allOf(withKey("pref_all_mms"))).perform(click()); + } + + public static void clickSmsDeliveryReports() throws Exception { + onData(Matchers.allOf(withKey("pref_delivery_report_sms"))).perform(click()); + } + + public static void clickWifiCallingCompat() throws Exception { + onData(Matchers.allOf(withKey("pref_wifi_sms"))).perform(click()); + } + +} diff --git a/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/StoragePreferenceFragmentActions.java b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/StoragePreferenceFragmentActions.java new file mode 100644 index 0000000000..b1f3ad6759 --- /dev/null +++ b/test/androidTestEspresso/java/org/thoughtcrime/securesms/preferences/StoragePreferenceFragmentActions.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.preferences; + +import org.hamcrest.Matchers; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.PreferenceMatchers.withKey; + +public class StoragePreferenceFragmentActions { + + public static void clickDeleteOldMessages() throws Exception { + onData(Matchers.allOf(withKey("pref_trim_threads"))).perform(click()); + } + + public static void clickConversationLengthLimit() throws Exception { + onData(Matchers.allOf(withKey("pref_trim_length"))).perform(click()); + } + + public static void clickTrimAllNow() throws Exception { + onData(Matchers.allOf(withKey("pref_trim_now"))).perform(click()); + } + +} diff --git a/test/espresso/AndroidManifest.xml b/test/espresso/AndroidManifest.xml new file mode 100644 index 0000000000..65b7a6350b --- /dev/null +++ b/test/espresso/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + +