diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5fe66e4d25..37599a7714 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -28,6 +28,8 @@ android { multiDexEnabled = true resourceConfigurations += listOf("ar", "bg", "bn", "bn-rIN", "bs", "cs", "da", "de", "el-rGR", "en", "eo", "es", "es-rAR", "fi", "fr", "he-rIL", "hi", "hr", "hu", "in-rID", "is", "it", "ja", "ko", "lt", "lv", "nb-rNO", "nl", "oc", "pl", "pt-rPT", "ro-rRO", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "zh-rCN", "zh-rTW") + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArguments["clearPackageData"] = "true" } buildTypes { @@ -94,6 +96,7 @@ dependencies { implementation("androidx.preference:preference:1.2.1") implementation("com.google.android.material:material:1.12.0") implementation("com.github.yalantis:ucrop:2.2.9") + implementation("androidx.tracing:tracing:1.2.0") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") // Splash Screen @@ -113,6 +116,16 @@ dependencies { testImplementation("androidx.test:core:1.5.0") testImplementation("junit:junit:4.13.2") testImplementation("org.robolectric:robolectric:4.12.2") + + // Espresso + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.0-beta01") + androidTestImplementation("androidx.test:core:1.5.0") + androidTestImplementation("androidx.test:rules:1.6.0-beta01") + androidTestImplementation("androidx.test.ext:junit:1.2.0-beta01") + androidTestImplementation("androidx.test:runner:1.5.2") + androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.0-beta01") + + androidTestUtil("androidx.test:orchestrator:1.1.0") } tasks.withType().configureEach { diff --git a/app/src/androidTest/java/protect/card_locker/LanguageChangeUITest.java b/app/src/androidTest/java/protect/card_locker/LanguageChangeUITest.java new file mode 100644 index 0000000000..fe4f3562fb --- /dev/null +++ b/app/src/androidTest/java/protect/card_locker/LanguageChangeUITest.java @@ -0,0 +1,173 @@ +package protect.card_locker; + + +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withClassName; +import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withParent; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.is; + +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.ViewInteraction; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class LanguageChangeUITest { + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(MainActivity.class); + + @Test + public void languageChangeUITest() { + ViewInteraction overflowMenuButton = onView( + allOf(withContentDescription(R.string.action_more_options), + isDisplayed())); + overflowMenuButton.perform(click()); + + String expectedText = getInstrumentation().getTargetContext().getString(R.string.settings); + ViewInteraction materialTextView = onView( + allOf(withId(androidx.recyclerview.R.id.title), withText(expectedText), + childAtPosition( + childAtPosition( + withId(androidx.appcompat.R.id.content), + 0), + 0), + isDisplayed())); + materialTextView.perform(click()); + + ViewInteraction recyclerView = onView( + allOf(withId(com.jaredrummler.android.colorpicker.R.id.recycler_view), + childAtPosition( + withId(android.R.id.list_container), + 0))); + recyclerView.perform(actionOnItemAtPosition(4, click())); + + String selectedLanguage = "de"; + int position = getPositionOfItem(selectedLanguage); + + DataInteraction appCompatCheckedTextView = onData(anything()) + .inAdapterView(allOf(withId(androidx.appcompat.R.id.select_dialog_listview), + childAtPosition( + withId(androidx.appcompat.R.id.contentPanel), + 0))) + .atPosition(position); + appCompatCheckedTextView.perform(click()); + + ViewInteraction textView = onView( + allOf(withText("Einstellungen"), + withParent(allOf(withId(R.id.toolbar), + withParent(IsInstanceOf.instanceOf(android.widget.LinearLayout.class)))), + isDisplayed())); + textView.check(matches(withText("Einstellungen"))); + + ViewInteraction recyclerView2 = onView( + allOf(withId(com.jaredrummler.android.colorpicker.R.id.recycler_view), + childAtPosition( + withId(android.R.id.list_container), + 0))); + recyclerView2.perform(actionOnItemAtPosition(4, click())); + + selectedLanguage = "el-rGR"; + position = getPositionOfItem(selectedLanguage); + + DataInteraction appCompatCheckedTextView2 = onData(anything()) + .inAdapterView(allOf(withId(androidx.appcompat.R.id.select_dialog_listview), + childAtPosition( + withId(androidx.appcompat.R.id.contentPanel), + 0))) + .atPosition(position); + appCompatCheckedTextView2.perform(click()); + + ViewInteraction textView2 = onView( + allOf(withText("Ρυθμίσεις"), + withParent(allOf(withId(R.id.toolbar), + withParent(IsInstanceOf.instanceOf(android.widget.LinearLayout.class)))), + isDisplayed())); + textView2.check(matches(withText("Ρυθμίσεις"))); + + ViewInteraction recyclerView3 = onView( + allOf(withId(com.jaredrummler.android.colorpicker.R.id.recycler_view), + childAtPosition( + withId(android.R.id.list_container), + 0))); + recyclerView3.perform(actionOnItemAtPosition(4, click())); + + DataInteraction appCompatCheckedTextView3 = onData(anything()) + .inAdapterView(allOf(withId(androidx.appcompat.R.id.select_dialog_listview), + childAtPosition( + withId(androidx.appcompat.R.id.contentPanel), + 0))) + .atPosition(0); + appCompatCheckedTextView3.perform(click()); + + ViewInteraction appCompatImageButton = onView( + allOf(withContentDescription("Navigate up"), + childAtPosition( + allOf(withId(R.id.toolbar), + childAtPosition( + withClassName(is("com.google.android.material.appbar.AppBarLayout")), + 0)), + 1), + isDisplayed())); + appCompatImageButton.perform(click()); + + ViewInteraction textView3 = onView( + allOf(withId(R.id.welcome_text), withText("Welcome to Catima"), + withParent(allOf(withId(R.id.helpSection), + withParent(withId(R.id.include)))), + isDisplayed())); + textView3.check(matches(withText("Welcome to Catima"))); + } + + private static Matcher childAtPosition( + final Matcher parentMatcher, final int position) { + + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("Child at position " + position + " in parent "); + parentMatcher.describeTo(description); + } + + @Override + public boolean matchesSafely(View view) { + ViewParent parent = view.getParent(); + return parent instanceof ViewGroup && parentMatcher.matches(parent) + && view.equals(((ViewGroup) parent).getChildAt(position)); + } + }; + } + + private static int getPositionOfItem(String selectedLanguage) { + String[] availableLocales = getInstrumentation().getTargetContext().getResources().getStringArray(R.array.locale_values); + return Arrays.asList(availableLocales).indexOf(selectedLanguage); + } +} diff --git a/app/src/androidTest/java/protect/card_locker/LoyaltyCardCreationTest.java b/app/src/androidTest/java/protect/card_locker/LoyaltyCardCreationTest.java new file mode 100644 index 0000000000..a8f1174c30 --- /dev/null +++ b/app/src/androidTest/java/protect/card_locker/LoyaltyCardCreationTest.java @@ -0,0 +1,196 @@ +package protect.card_locker; + +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; +import static androidx.test.espresso.action.ViewActions.replaceText; +import static androidx.test.espresso.action.ViewActions.scrollTo; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withClassName; +import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withParent; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.is; + +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.ViewInteraction; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.rule.GrantPermissionRule; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class LoyaltyCardCreationTest { + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(MainActivity.class); + + @Rule + public GrantPermissionRule mGrantPermissionRule = + GrantPermissionRule.grant( + "android.permission.CAMERA"); + + @Test + public void loyaltyCardCreationTest() { + String expectedText = getInstrumentation().getTargetContext().getString(R.string.noGiftCards); + ViewInteraction textView = onView( + allOf(withId(R.id.add_card_instruction), withText(expectedText), + withParent(allOf(withId(R.id.helpSection), + withParent(withId(R.id.include)))), + isDisplayed())); + textView.check(matches(withText(expectedText))); + + expectedText = getInstrumentation().getTargetContext().getString(R.string.action_add); + ViewInteraction floatingActionButton = onView( + allOf(withId(R.id.fabAdd), withContentDescription(expectedText), + childAtPosition( + childAtPosition( + withId(android.R.id.content), + 0), + 2), + isDisplayed())); + floatingActionButton.perform(click()); + + expectedText = getInstrumentation().getTargetContext().getString(R.string.action_more_options); + ViewInteraction extendedFloatingActionButton = onView( + allOf(withId(R.id.fabOtherOptions), withText(expectedText), + childAtPosition( + allOf(withId(R.id.zxing_barcode_scanner), + childAtPosition( + withClassName(is("android.widget.RelativeLayout")), + 1)), + 0), + isDisplayed())); + extendedFloatingActionButton.perform(click()); + + DataInteraction materialTextView = onData(anything()) + .inAdapterView(allOf(withId(androidx.appcompat.R.id.select_dialog_listview), + childAtPosition( + withId(androidx.appcompat.R.id.contentPanel), + 0))) + .atPosition(0); + materialTextView.perform(click()); + + ViewInteraction editText = onView( + allOf(childAtPosition( + childAtPosition( + withId(androidx.appcompat.R.id.custom), + 0), + 1), + isDisplayed())); + editText.perform(replaceText("123456789"), closeSoftKeyboard()); + + expectedText = getInstrumentation().getTargetContext().getString(R.string.ok); + ViewInteraction materialButton = onView( + allOf(withId(android.R.id.button1), withText(expectedText), + childAtPosition( + childAtPosition( + withId(androidx.appcompat.R.id.buttonPanel), + 0), + 3))); + materialButton.perform(scrollTo(), click()); + + ViewInteraction editText2 = onView( + allOf(withId(R.id.cardIdView), withText("123456789"), + withParent(withParent(withId(R.id.cardIdField))), + isDisplayed())); + editText2.check(matches(withText("123456789"))); + + ViewInteraction textInputEditText = onView( + allOf(withId(R.id.storeNameEdit), + childAtPosition( + childAtPosition( + withId(R.id.storeNameField), + 0), + 0), + isDisplayed())); + textInputEditText.perform(replaceText("CatimaUITestCard"), closeSoftKeyboard()); + + expectedText = getInstrumentation().getTargetContext().getString(R.string.options); + ViewInteraction tabView = onView( + allOf(withContentDescription(expectedText), + childAtPosition( + childAtPosition( + withId(R.id.tabs), + 0), + 1), + isDisplayed())); + tabView.perform(click()); + + ViewInteraction textInputEditText2 = onView( + allOf(withId(R.id.balanceField), withText("0"), + childAtPosition( + childAtPosition( + withId(R.id.balanceView), + 0), + 0), + isDisplayed())); + textInputEditText2.perform(replaceText("10000")); + + ViewInteraction textInputEditText3 = onView( + allOf(withId(R.id.balanceField), withText("10000"), + childAtPosition( + childAtPosition( + withId(R.id.balanceView), + 0), + 0), + isDisplayed())); + textInputEditText3.perform(closeSoftKeyboard()); + + expectedText = getInstrumentation().getTargetContext().getString(R.string.save); + ViewInteraction floatingActionButton2 = onView( + allOf(withId(R.id.fabSave), withContentDescription(expectedText), + childAtPosition( + childAtPosition( + withId(android.R.id.content), + 0), + 2), + isDisplayed())); + floatingActionButton2.perform(click()); + + expectedText = getInstrumentation().getTargetContext().getResources().getQuantityString(R.plurals.balancePoints, 5, 10000); + ViewInteraction textView2 = onView( + allOf(withId(R.id.balance), withText(expectedText), + withParent(withParent(withId(R.id.row))), + isDisplayed())); + textView2.check(matches(withText(expectedText))); + } + + private static Matcher childAtPosition( + final Matcher parentMatcher, final int position) { + + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("Child at position " + position + " in parent "); + parentMatcher.describeTo(description); + } + + @Override + public boolean matchesSafely(View view) { + ViewParent parent = view.getParent(); + return parent instanceof ViewGroup && parentMatcher.matches(parent) + && view.equals(((ViewGroup) parent).getChildAt(position)); + } + }; + } +} \ No newline at end of file