diff --git a/.circleci/config.yml b/.circleci/config.yml index 81326d85fd..1d3e9d6c67 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: - store_artifacts: path: app/libs/ destination: libs - code-analysis: + run-unit-tests: docker: - image: circleci/android:api-29 environment: @@ -55,14 +55,17 @@ jobs: - ~/.gradle/wrapper key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "player/build.gradle" }}-{{ checksum "core/build.gradle" }}-{{ checksum "util/build.gradle" }}-{{ checksum "draw/build.gradle" }}-{{ checksum "emoji/build.gradle" }}-{{ checksum "suggestions/build.gradle" }} - run: - name: Run Lint + name: Run Lint command: ./gradlew lint - run: name: Run Unit test - command: ./gradlew test + command: ./gradlew --no-daemon testPlayDebugUnitTest - run: - name: Compile Instrumentation test - command: ./gradlew assembleAndroidTest + name: Generate reports + command: ./gradlew jacocoTestPlayDebugUnitTestReport + - run: + name: Send coverage + command: bash <(curl -s https://codecov.io/bash) - store_artifacts: path: app/build/reports/ destination: reports @@ -143,13 +146,12 @@ workflows: build-deploy: jobs: - build-kotlin-sdk - - code-analysis: + - run-unit-tests: requires: - build-kotlin-sdk filters: branches: ignore: # skip on merge commits. - - develop - develop-2.x - master - build-aab: diff --git a/HOW_TO_RUN_TESTS.md b/HOW_TO_RUN_TESTS.md new file mode 100644 index 0000000000..97682bf893 --- /dev/null +++ b/HOW_TO_RUN_TESTS.md @@ -0,0 +1,28 @@ +### How to run Unit tests and UI tests on local machine + +#### Unit tests + +1. Fork the repo and setup the project on your local machine. +2. Open Android Studio terminal +3. Run gradlew test + +#### UI tests + +1. Fork the repo and setup the project on your local machine. +2. Open Android Studio terminal and run the android emulator. +3. Run gradlew connectedAndroidTest command on your AS Terminal (To run Android tests on each module and build variant in the project) +4. Run gradlew connectedPlayDebugAndroidTest (for specific play variant) + +**Note:** +1. Before running UI tests on the emulator device uninstall the existing version of RC app from it. +2. It is advised to turn off all the animation of device, tests may fail if animations are on. To turn the animations off go to developer +option in device settings. +3. It is advised to have good network connection and sufficient ram in you machine while running the UI tests + + +### Any organization that forks RC can run tests against their own server +- Organisation using Rocket.Chat fork can also run the tests by doing some minor changes. +- For tests to work properly, Organisations have to follow the instructions mentioned in [Config file](https://github.com/GOVINDDIXIT/Rocket.Chat.Android/blob/develop/app/src/main/java/testConfig/Config.kt) carefully which also include creating new user. +- They have to create additional channels as mentioned in the config file. +- Also they need to customise the links present in the config file according to their server requirements. + diff --git a/app/build.gradle b/app/build.gradle index 9bfe286740..524d5e02f0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,6 +9,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' apply plugin: "com.github.ben-manes.versions" +apply plugin: 'jacoco-android' android { compileSdkVersion versions.compileSdk @@ -39,6 +40,35 @@ android { } } + kapt { + useBuildCache true + } + + dexOptions { + preDexLibraries true + jumboMode false + } + + testOptions { + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + unitTests{ + includeAndroidResources = true + returnDefaultValues = true + } + } + + tasks.withType(Test) { + testLogging { + exceptionFormat "full" + events "passed", "failed" + showStandardStreams true + } + } + signingConfigs { release { storeFile project.rootProject.file('Rocket.jks').getCanonicalFile() @@ -69,6 +99,7 @@ android { buildConfigField "String", "RECOMMENDED_SERVER_VERSION", '"0.64.2"' signingConfig signingConfigs.debug applicationIdSuffix ".dev" + testCoverageEnabled true } } @@ -180,6 +211,12 @@ dependencies { testImplementation libraries.truth androidTestImplementation libraries.espressoCore androidTestImplementation libraries.espressoIntents + androidTestImplementation libraries.espressoContrib + androidTestImplementation libraries.uiAutomator + testImplementation libraries.mockito + testImplementation libraries.mockitoInline + androidTestImplementation libraries.mockitoAndroid + androidTestImplementation libraries.runner } androidExtensions { diff --git a/app/jacoco.gradle b/app/jacoco.gradle new file mode 100644 index 0000000000..4ae662b39a --- /dev/null +++ b/app/jacoco.gradle @@ -0,0 +1,20 @@ +apply plugin: 'jacoco' + +task jacocoTestReport(type: JacocoReport, dependsOn: ['testPlayDebugUnitTest', 'createPlayDebugCoverageReport']) { + + reports { + xml.enabled = true + html.enabled = true + } + + def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] + def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter) + def mainSrc = "${project.projectDir}/src/main/java" + + sourceDirectories = files([mainSrc]) + classDirectories = files([debugTree]) + executionData = fileTree(dir: "$buildDir", includes: [ + "jacoco/testPlayDebugUnitTest.exec", + "outputs/code-coverage/playDebugAndroidTest/connected/*coverage.ec" + ]) +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/login/ui/LoginFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/login/ui/LoginFragmentTest.kt new file mode 100644 index 0000000000..eb3872d46a --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/login/ui/LoginFragmentTest.kt @@ -0,0 +1,83 @@ +package chat.rocket.android.authentication.login.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.withHint +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.hamcrest.Matchers.not +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.PASSWORD +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.USERNAME + +@LargeTest +class LoginFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + newInstance(SERVER_URL) + } + } + + @Test + fun check_UI_elements(){ + onView(withId(R.id.text_login)).check(matches(withText("Login"))) + onView(withId(R.id.text_username_or_email)).check(matches(withHint("Username or email"))) + onView(withId(R.id.text_password)).check(matches(withHint("Password"))) + onView(withId(R.id.button_log_in)).check(matches(withText("Login"))) + onView(withId(R.id.button_forgot_your_password)).check(matches(withText("Forgot your password?"))) + } + + @Test + fun login_button_enable_if_details_are_filled(){ + onView(withId(R.id.text_username_or_email)).perform( + typeText(USERNAME), closeSoftKeyboard() + ) + onView(withId(R.id.text_password)).perform( + typeText(PASSWORD), closeSoftKeyboard() + ) + onView(withId(R.id.button_log_in)).check(matches(isEnabled())) + } + + @Test + fun login_button_disable_if_details_are_not_filled(){ + onView(withId(R.id.text_username_or_email)).perform( + typeText(USERNAME), closeSoftKeyboard() + ) + onView(withId(R.id.button_log_in)).check(matches(not(isEnabled()))) + } + + @Test + fun check_login_with_email_and_logout(){ + onView(withId(R.id.text_username_or_email)).perform( + typeText(USERNAME), closeSoftKeyboard() + ) + onView(withId(R.id.text_password)).perform( + typeText(PASSWORD), closeSoftKeyboard() + ) + onView(withId(R.id.button_log_in)).perform(click()) + Thread.sleep(15000) + onView(withContentDescription(R.string.abc_action_bar_up_description)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_logout)).check(matches(isDisplayed())) + .perform(click()) + onView(withText("LOGOUT")).perform(click()) + Thread.sleep(2000) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragmentTest.kt new file mode 100644 index 0000000000..2bfc662bbb --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragmentTest.kt @@ -0,0 +1,97 @@ +package chat.rocket.android.authentication.loginoptions.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.authentication.ui.AuthenticationActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@LargeTest +class LoginOptionsFragmentTest { + + @Rule + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java) + + @Before + fun setUp() { + onView(withId(R.id.join_community_container)) + .perform(scrollTo(), click()) + Thread.sleep(5000) + } + + @Test + fun check_UI_element() { + onView(withId(R.id.button_facebook)).check(matches(withText("Continue with Facebook"))) + onView(withId(R.id.button_google)).check(matches(withText("Continue with Google"))) + onView(withId(R.id.button_gitlab)).check(matches(withText("Continue with GitLab"))) + } + + @Test + fun expand_collapse_accounts_and_check_UI_elements() { + onView(withId(R.id.button_expand_collapse_accounts)) + .perform(scrollTo(), click()) + onView(withId(R.id.button_linkedin)).check(matches(withText("Continue with LinkedIn"))) + onView(withId(R.id.button_github)).check(matches(withText("Continue with GitHub"))) + } + + @Test + fun click_login_with_email() { + onView(withId(R.id.button_login_with_email)).check(matches(withText("Login with e-mail"))) + .perform(scrollTo(), click()) + onView(withId(R.id.text_login)).check(matches(withText("Login"))) + } + + @Test + fun check_create_an_account() { + onView(withId(R.id.button_create_an_account)).check(matches(withText("Create an account"))) + .perform(scrollTo(), click()) + onView(withId(R.id.text_sign_up)).check(matches(withText("Sign up"))) + } + + @Test + fun check_facebook_button() { + onView(withId(R.id.button_facebook)) + .perform(scrollTo(), click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } + + @Test + fun check_github_button() { + onView(withId(R.id.button_github)) + .perform(scrollTo(), click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } + + @Test + fun check_google_button() { + onView(withId(R.id.button_google)).perform(scrollTo()) + .perform(scrollTo(), click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } + + @Test + fun check_linkedin_button() { + onView(withId(R.id.button_expand_collapse_accounts)) + .perform(scrollTo(), click()) + onView(withId(R.id.button_linkedin)) + .perform(scrollTo(), click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } + + @Test + fun check_gitlab_button() { + onView(withId(R.id.button_expand_collapse_accounts)) + .perform(scrollTo(), click()) + onView(withId(R.id.button_gitlab)) + .perform(scrollTo(), click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/onboarding/ui/OnBoardingFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/onboarding/ui/OnBoardingFragmentTest.kt new file mode 100644 index 0000000000..ecec403561 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/onboarding/ui/OnBoardingFragmentTest.kt @@ -0,0 +1,55 @@ +package chat.rocket.android.authentication.onboarding.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.authentication.ui.AuthenticationActivity +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.SERVER + +@LargeTest +class OnBoardingFragmentTest { + + @Rule + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java) + + @Test + fun check_UI_elements(){ + onView(withId(R.id.image_on_boarding)).check(matches(isDisplayed())) + onView(withId(R.id.text_on_boarding_title)).check(matches(isDisplayed())) + onView(withId(R.id.text_on_boarding_description)).check(matches(isDisplayed())) + onView(withId(R.id.text_connect_with_server)).check(matches(withText("Connect with a server"))) + onView(withId(R.id.text_join_community)).check(matches(withText("Join in the community"))) + onView(withId(R.id.text_create_a_new_server)).check(matches(withText("Create a new server"))) + } + + @Test + fun fill_detail_and_connect_with_server() { + onView(withId(R.id.connect_with_a_server_container)).perform(click()) + onView(withId(R.id.text_server_url)).perform( + typeText(SERVER), closeSoftKeyboard() + ) + onView(withId(R.id.button_connect)).perform(scrollTo(), click()) + } + + @Test + fun check_join_in_the_community_click() { + onView(withId(R.id.join_community_container)) + .perform(scrollTo(), click()) + Thread.sleep(3000) + onView(withId(R.id.button_login_with_email)).check(matches(isDisplayed())) + } + + @Test + fun check_create_new_server_click() { + onView(withId(R.id.create_server_container)) + .perform(scrollTo(), click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragmentTest.kt new file mode 100644 index 0000000000..2d14f3d5b1 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragmentTest.kt @@ -0,0 +1,50 @@ +package chat.rocket.android.authentication.registerusername.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import testConfig.Config.Companion.AUTH_TOKEN +import testConfig.Config.Companion.USERNAME +import testConfig.Config.Companion.USER_ID +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Run Separately") +@LargeTest +class RegisterUsernameFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(ScreenViewEvent.RegisterUsername.screenName, R.id.fragment_container) { + newInstance(USER_ID, AUTH_TOKEN) + } + } + + @Test + fun check_UI_elements(){ + onView(withId(R.id.text_sign_in_to_your_server)).check(matches(withText("Register username"))) + onView(withId(R.id.text_username)).check(matches(withHint("Username"))) + onView(withId(R.id.button_use_this_username)).check(matches(withText("Use this username"))) + } + + @Test + fun fill_username_and_register(){ + onView(withId(R.id.text_username)).perform(typeText(USERNAME), closeSoftKeyboard()) + onView(withId(R.id.button_use_this_username)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/resetpassword/ui/ResetPasswordFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/resetpassword/ui/ResetPasswordFragmentTest.kt new file mode 100644 index 0000000000..23c6943e75 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/resetpassword/ui/ResetPasswordFragmentTest.kt @@ -0,0 +1,50 @@ +package chat.rocket.android.authentication.resetpassword.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import testConfig.Config.Companion.EMAIL +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.util.withHint +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@LargeTest +class ResetPasswordFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(ScreenViewEvent.ResetPassword.screenName, R.id.fragment_container) { + newInstance() + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_reset_password)).check(matches(withText("Reset password"))) + onView(withId(R.id.text_email)).check(matches(withHint("Email"))) + } + + @Test + fun check_reset_password() { + onView(withId(R.id.text_email)).perform( + typeText(EMAIL), closeSoftKeyboard() + ) + onView(withId(R.id.button_reset_password)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.image_on_boarding)).check(matches(isDisplayed())) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/server/ui/ServerFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/server/ui/ServerFragmentTest.kt new file mode 100644 index 0000000000..43da892d20 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/server/ui/ServerFragmentTest.kt @@ -0,0 +1,51 @@ +package chat.rocket.android.authentication.server.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import testConfig.Config.Companion.SERVER +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@LargeTest +class ServerFragmentTest{ + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(ScreenViewEvent.Server.screenName, R.id.fragment_container) { + newInstance(null) + } + } + + @Test + fun check_UI_elements(){ + onView(withId(R.id.image_server)).check(matches(isDisplayed())) + onView(withId(R.id.spinner_server_protocol)).check(matches(isDisplayed())) + onView(withId(R.id.server_url_container)).check(matches(isDisplayed())) + onView(withId(R.id.button_connect)).check(matches(isDisplayed())) + onView(withId(R.id.text_sign_in_to_your_server)).check(matches(withText("Sign in to your server"))) + onView(withId(R.id.text_server_url)).check(matches(withHint("your-company.rocket.chat"))) + } + + @Test + fun fill_server_url_and_connect() { + onView(withId(R.id.text_server_url)).perform( + typeText(SERVER), closeSoftKeyboard() + ) + onView(withId(R.id.button_connect)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/signup/ui/SignupFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/signup/ui/SignupFragmentTest.kt new file mode 100644 index 0000000000..34a3afc56d --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/signup/ui/SignupFragmentTest.kt @@ -0,0 +1,64 @@ +package chat.rocket.android.authentication.signup.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import testConfig.Config.Companion.EMAIL +import testConfig.Config.Companion.NAME +import testConfig.Config.Companion.PASSWORD +import testConfig.Config.Companion.USERNAME +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@LargeTest +class SignupFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(ScreenViewEvent.SignUp.screenName, R.id.fragment_container) { + newInstance() + } + } + + @Test + fun check_UI_elements(){ + onView(withId(R.id.text_sign_up)).check(matches(ViewMatchers.withText("Sign up"))) + onView(withId(R.id.text_name)).check(matches(ViewMatchers.withHint("Name"))) + onView(withId(R.id.text_username)).check(matches(ViewMatchers.withHint("Username"))) + onView(withId(R.id.text_password)).check(matches(ViewMatchers.withHint("Password"))) + onView(withId(R.id.text_email)).check(matches(ViewMatchers.withHint("Email"))) + onView(withId(R.id.button_register)).check(matches(ViewMatchers.withText("Register"))) + } + + @Test + fun fill_details_and_signup() { + onView(withId(R.id.text_name)).perform( + typeText(NAME), closeSoftKeyboard() + ) + onView(withId(R.id.text_username)).perform( + typeText(USERNAME), closeSoftKeyboard() + ) + onView(withId(R.id.text_password)).perform( + typeText(PASSWORD), closeSoftKeyboard() + ) + onView(withId(R.id.text_email)).perform( + typeText(EMAIL), closeSoftKeyboard() + ) + onView(withId(R.id.button_register)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/authentication/twofactor/ui/TwoFAFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/authentication/twofactor/ui/TwoFAFragmentTest.kt new file mode 100644 index 0000000000..ea346f74d4 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/authentication/twofactor/ui/TwoFAFragmentTest.kt @@ -0,0 +1,52 @@ +package chat.rocket.android.authentication.twofactor.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import testConfig.Config.Companion.CODE +import testConfig.Config.Companion.PASSWORD +import testConfig.Config.Companion.USERNAME +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@LargeTest +class TwoFAFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(ScreenViewEvent.TwoFa.screenName, R.id.fragment_container) { + newInstance(USERNAME, PASSWORD) + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_two_factor_authentication)).check(matches(ViewMatchers.withText("Two-factor Authentication"))) + onView(withId(R.id.text_two_factor_authentication_code)).check(matches(isDisplayed())) + onView(withId(R.id.button_confirm)).check(matches(ViewMatchers.withText("Confirm"))) + } + + @Test + fun fill_code_and_click_confirm() { + onView(withId(R.id.text_two_factor_authentication_code)).perform( + typeText(CODE), closeSoftKeyboard() + ) + onView(withId(R.id.button_confirm)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragmentTest.kt new file mode 100644 index 0000000000..4b61583d31 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragmentTest.kt @@ -0,0 +1,136 @@ +package chat.rocket.android.chatdetails.ui + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import chat.rocket.android.util.withTextInChild +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.FAVORITE_MESSAGES +import testConfig.Config.Companion.FILES +import testConfig.Config.Companion.MEMBERS +import testConfig.Config.Companion.MENTIONS +import testConfig.Config.Companion.PINNED_MESSAGES +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL +import testConfig.Config.Companion.TEST_USER + +class ChatDetailsFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + } + } + + @Test + fun check_UI_elements() { + navigateToExistingChannelDetails() + onView(withId(R.id.title_description)).check(matches(withText(R.string.title_description))) + onView(withId(R.id.content_description)).check(matches(isDisplayed())) + onView(withId(R.id.title_topic)).check(matches(withText(R.string.title_topic))) + onView(withId(R.id.content_topic)).check(matches(isDisplayed())) + onView(withId(R.id.title_announcement)).check(matches(withText(R.string.title_announcement))) + onView(withId(R.id.content_announcement)).check(matches(isDisplayed())) + } + + @Test + fun check_UI_elements_of_option_list_in_channel() { + navigateToExistingChannelDetails() + onView(withId(R.id.options)).perform( + RecyclerViewActions.actionOnItemAtPosition(0, withTextInChild(R.id.name, FILES)) + ).perform( + RecyclerViewActions.actionOnItemAtPosition(1, withTextInChild(R.id.name, MENTIONS)) + ).perform( + RecyclerViewActions.actionOnItemAtPosition(2, withTextInChild(R.id.name, MEMBERS)) + ).perform( + RecyclerViewActions.actionOnItemAtPosition(3, withTextInChild(R.id.name, FAVORITE_MESSAGES)) + ).perform( + RecyclerViewActions.actionOnItemAtPosition(4, withTextInChild(R.id.name, PINNED_MESSAGES)) + ) + } + + @Test + fun check_UI_elements_of_option_list_in_direct_messages() { + navigateToExistingDMDetails() + onView(withId(R.id.options)).perform( + RecyclerViewActions.actionOnItemAtPosition(0, withTextInChild(R.id.name, FILES)) + ).perform( + RecyclerViewActions.actionOnItemAtPosition(1, withTextInChild(R.id.name, FAVORITE_MESSAGES)) + ).perform( + RecyclerViewActions.actionOnItemAtPosition(2, withTextInChild(R.id.name, PINNED_MESSAGES)) + ) + } + + @Test + fun files_fragment_should_open() { + navigateToExistingChannelDetails() + onView(withText(FILES)).perform(click()) + onView(withId(R.id.files_layout)).check(matches(isDisplayed())) + } + + @Test + fun members_fragment_should_open() { + navigateToExistingChannelDetails() + onView(withText(MEMBERS)).perform(click()) + onView(withId(R.id.members_layout)).check(matches(isDisplayed())) + } + + @Test + fun mentions_fragment_should_open() { + navigateToExistingChannelDetails() + onView(withText(MENTIONS)).perform(click()) + onView(withId(R.id.mentions_layout)).check(matches(isDisplayed())) + } + + @Test + fun favourite_messages_fragment_should_open() { + navigateToExistingChannelDetails() + onView(withText(FAVORITE_MESSAGES)).perform(click()) + onView(withId(R.id.favourite_message_layout)).check(matches(isDisplayed())) + } + + @Test + fun pinned_messages_fragment_should_open() { + navigateToExistingChannelDetails() + onView(withText(PINNED_MESSAGES)).perform(click()) + onView(withId(R.id.pinned_messages_layout)).check(matches(isDisplayed())) + } + + private fun navigateToExistingDMDetails() { + Thread.sleep(5000) + onView(withText(TEST_USER)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } + + private fun navigateToExistingChannelDetails() { + Thread.sleep(5000) + onView(withText(TEST_CHANNEL)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/chatinformation/ui/MessageInfoFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/chatinformation/ui/MessageInfoFragmentTest.kt new file mode 100644 index 0000000000..1c84d4322b --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/chatinformation/ui/MessageInfoFragmentTest.kt @@ -0,0 +1,84 @@ +package chat.rocket.android.chatinformation.ui + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion.Companion.withItemCount +import chat.rocket.android.util.ScrollToTop +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.CoreMatchers.equalTo +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config +import testConfig.Config.Companion.TEST_USER2 + + +class MessageInfoFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(Config.SERVER_URL) + } + loginUserToTheApp() + navigateToTestUser() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + navigateToTestUser() + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_toolbar_title)).check(matches(isDisplayed())) + onView(withId(R.id.root_layout)).check(matches(isDisplayed())) + } + + @Test + fun receipt_list_is_displayed() { + onView(withId(R.id.recycler_view)).perform(ScrollToTop()) + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, click() + ) + ) + onView(withText(R.string.action_info)).perform(click()) + Thread.sleep(3000) + onView(withId(R.id.receipt_list)).check(withItemCount(equalTo(0))) + } + + @Test + fun check_toolbar_title() { + onView(withId(R.id.recycler_view)).perform(ScrollToTop()) + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, click() + ) + ) + onView(withText(R.string.action_info)).check(matches(isDisplayed())) + .perform(click()) + onView(withId(R.id.text_toolbar_title)).check(matches(withText(R.string.message_information_title))) + } + + private fun navigateToTestUser() { + onView(withText(TEST_USER2)).perform(click()) + Thread.sleep(2000) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/chatroom/ui/ChatRoomFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/chatroom/ui/ChatRoomFragmentTest.kt index 25689d1956..6e1a181c44 100644 --- a/app/src/androidTest/java/chat/rocket/android/chatroom/ui/ChatRoomFragmentTest.kt +++ b/app/src/androidTest/java/chat/rocket/android/chatroom/ui/ChatRoomFragmentTest.kt @@ -1,67 +1,189 @@ package chat.rocket.android.chatroom.ui -import android.content.Intent -import androidx.test.espresso.intent.rule.IntentsTestRule +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.ScrollToTop +import chat.rocket.android.util.ToastMatcher.Companion.isToast +import chat.rocket.android.util.clickChildViewWithId +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.junit.Before import org.junit.Rule import org.junit.Test -import android.app.Activity -import android.app.Instrumentation.ActivityResult -import androidx.test.InstrumentationRegistry -import androidx.test.espresso.intent.Intents.intended -import androidx.test.espresso.intent.Intents.intending -import androidx.test.espresso.intent.matcher.IntentMatchers.* -import org.hamcrest.Matchers.allOf -import org.hamcrest.Matchers.not -import org.junit.Before +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL2 +import testConfig.Config.Companion.TEST_MESSAGE +import testConfig.Config.Companion.TEST_USER +import testConfig.Config.Companion.TEST_USER2 @LargeTest class ChatRoomFragmentTest { @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + @Rule - val activityRule = IntentsTestRule(ChatRoomActivity::class.java, false, false) + fun rule() = activityRule @Before - fun stubAllExternalIntents() { - val activityIntent = InstrumentationRegistry.getTargetContext() - .chatRoomIntent("id", "name", "type", false, 0L) - activityRule.launchActivity(activityIntent) - intending(not(isInternal())).respondWith(ActivityResult(Activity.RESULT_OK, null)) + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + } + } + + @Test + fun check_UI_elements_when_messages_are_present() { + navigateToExistingChannel() + onView(withId(R.id.message_list_container)).check(matches(isDisplayed())) + onView(withId(R.id.layout_message_list)).check(matches(isDisplayed())) + onView(withId(R.id.layout_message_composer)).check(matches(isDisplayed())) + } + + @Test + fun check_UI_elements_when_no_messages_is_present() { + navigateToExistingUser1() + onView(withId(R.id.layout_message_list)).check(matches(isDisplayed())) + onView(withId(R.id.message_list_container)).check(matches(isDisplayed())) + onView(withId(R.id.layout_message_composer)).check(matches(isDisplayed())) + onView(withId(R.id.image_chat_icon)).check(matches(isDisplayed())) + onView(withId(R.id.text_chat_title)).check(matches(withText(R.string.msg_no_chat_title))) + onView(withId(R.id.text_chat_description)).check(matches(withText(R.string.msg_no_chat_description))) + } + + @Test + fun check_UI_elements_of_message_composer() { + navigateToExistingChannel() + onView(withId(R.id.button_add_reaction_or_show_keyboard)).check(matches(isDisplayed())) + onView(withId(R.id.text_message)).check(matches(isDisplayed())) + onView(withId(R.id.button_show_attachment_options)).check(matches(isDisplayed())) + } + + @Test + fun check_UI_elements_of_message_item() { + navigateToExistingUser2() + onView(withId(R.id.message_list_container)).check(matches(isDisplayed())) + onView(withId(R.id.image_avatar)).check(matches(isDisplayed())) + onView(withId(R.id.text_sender)).check(matches(isDisplayed())) + onView(withId(R.id.text_message_time)).check(matches(isDisplayed())) + onView(withId(R.id.text_content)).check(matches(isDisplayed())) + onView(withId(R.id.text_content)).check(matches(isDisplayed())) + } + + @Test + fun show_attachment_options() { + navigateToExistingChannel() + onView(withId(R.id.button_show_attachment_options)).perform(click()) + onView(withId(R.id.button_take_a_photo)).check(matches(isDisplayed())) + onView(withId(R.id.button_attach_a_file)).check(matches(isDisplayed())) + onView(withId(R.id.button_drawing)).check(matches(isDisplayed())) + onView(withId(R.id.text_message)).check(matches(isDisplayed())) + } + + @Test + fun send_text_message() { + navigateToExistingChannel() + onView(withId(R.id.text_message)).check(matches(withHint(R.string.msg_message))) + .perform( + typeText(TEST_MESSAGE), closeSoftKeyboard() + ) + onView(withId(R.id.button_send)).check(matches(isDisplayed())) + .perform(click()) + onView(withId(R.id.text_message)).perform(clearText()) } @Test - fun showFileSelection_nonNullFiltersAreApplied() { - val fragment = - activityRule.activity.supportFragmentManager.findFragmentByTag("ChatRoomFragment") as ChatRoomFragment - - val filters = arrayOf("image/*") - fragment.showFileSelection(filters) - - intended( - allOf( - hasAction(Intent.ACTION_GET_CONTENT), - hasType("*/*"), - hasCategories(setOf(Intent.CATEGORY_OPENABLE)), - hasExtra(Intent.EXTRA_MIME_TYPES, filters) + fun check_message_action_bottom_sheet() { + navigateToExistingUser2() + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, click() ) ) + onView(withText(R.string.action_msg_add_reaction)).check(matches(isDisplayed())) + onView(withText(R.string.action_msg_reply)).check(matches(isDisplayed())) + onView(withText(R.string.action_msg_quote)).check(matches(isDisplayed())) + onView(withText(R.string.action_msg_permalink)).check(matches(isDisplayed())) + onView(withText(R.string.action_msg_copy)).check(matches(isDisplayed())) + onView(withText(R.string.action_msg_edit)).check(matches(isDisplayed())) + onView(withText(R.string.action_info)).check(matches(isDisplayed())) } @Test - fun showFileSelection_nullFiltersAreNotApplied() { - val fragment = - activityRule.activity.supportFragmentManager.findFragmentByTag("ChatRoomFragment") as ChatRoomFragment - - fragment.showFileSelection(null) - - intended( - allOf( - hasAction(Intent.ACTION_GET_CONTENT), - hasType("*/*"), - hasCategories(setOf(Intent.CATEGORY_OPENABLE)), - not(hasExtraWithKey(Intent.EXTRA_MIME_TYPES)) + fun emoji_picker_popup_should_display() { + navigateToExistingUser2() + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, click() ) ) + onView(withText(R.string.action_msg_add_reaction)).perform(click()) + onView(withId(R.id.picker_container)).check(matches(isDisplayed())) + } + + @Test + fun copy_the_message() { + navigateToExistingUser2() + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, click() + ) + ) + onView(withText(R.string.action_msg_copy)).perform(click()) + onView(withText(R.string.msg_message_copied)).inRoot(isToast()).check(matches(isDisplayed())) + } + + @Test + fun copy_the_permalink() { + navigateToExistingUser2() + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, click() + ) + ) + onView(withText(R.string.action_msg_permalink)).perform(click()) + onView(withText(R.string.msg_permalink_copied)).inRoot(isToast()).check(matches(isDisplayed())) + } + + @Test + fun clicking_user_avatar_should_open_his_details(){ + navigateToExistingUser2() + onView(withId(R.id.recycler_view)).perform(ScrollToTop()) + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, clickChildViewWithId(R.id.image_avatar) + ) + ) + onView(withId(R.id.user_details_layout)).check(matches(isDisplayed())) + } + + private fun navigateToExistingChannel() { + onView(withText(TEST_CHANNEL2)).perform(click()) + Thread.sleep(2000) + } + + private fun navigateToExistingUser1() { + onView(withText(TEST_USER)).perform(click()) + Thread.sleep(2000) + } + + private fun navigateToExistingUser2() { + onView(withText(TEST_USER2)).perform(click()) + Thread.sleep(2000) } } \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragmentTest.kt new file mode 100644 index 0000000000..a58989ccd8 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragmentTest.kt @@ -0,0 +1,64 @@ +package chat.rocket.android.chatrooms.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import chat.rocket.android.util.withIndex +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.ORG_NAME +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL + +class ChatRoomsFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.recycler_view)).check(matches(isDisplayed())) + onView(withIndex(withId(R.id.image_avatar), 0)).check(matches(isDisplayed())) + onView(withIndex(withId(R.id.image_chat_icon), 0)).check(matches(isDisplayed())) + onView(withIndex(withId(R.id.text_last_message), 0)).check(matches(isDisplayed())) + onView(withIndex(withId(R.id.text_timestamp), 0)).check(matches(isDisplayed())) + onView(withId(R.id.text_sort_by)).check(matches(isDisplayed())) + } + + @Test + fun clicking_channel_should_open_chatroom() { + onView(withText(TEST_CHANNEL)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).check(matches(withText(TEST_CHANNEL))) + onView(withId(R.id.message_list_container)).check(matches(isDisplayed())) + } + + @Test + fun org_name_is_displayed() { + onView(withText(ORG_NAME)).check(matches(isDisplayed())) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/createchannel/ui/CreateChannelFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/createchannel/ui/CreateChannelFragmentTest.kt new file mode 100644 index 0000000000..a29a73927c --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/createchannel/ui/CreateChannelFragmentTest.kt @@ -0,0 +1,70 @@ +package chat.rocket.android.createchannel.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.loginUserToTheApp +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.SERVER_URL + + +class CreateChannelFragmentTest { + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + onView(withId(R.id.action_new_channel)).perform(click()) + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + onView(withId(R.id.action_new_channel)).perform(click()) + } + } + + @Test + fun check_UI_element() { + onView(withId(R.id.text_channel_type)).check(matches(isDisplayed())) + onView(withId(R.id.text_channel_type_description)).check(matches(isDisplayed())) + onView(withId(R.id.switch_channel_type)).check(matches(isDisplayed())) + onView(withId(R.id.text_read_only)).check(matches(isDisplayed())) + onView(withId(R.id.text_read_only_description)).check(matches(isDisplayed())) + onView(withId(R.id.switch_read_only)).check(matches(isDisplayed())) + onView(withId(R.id.image_channel_icon)).check(matches(isDisplayed())) + onView(withId(R.id.text_channel_name)).check(matches(isDisplayed())) + onView(withId(R.id.image_invite_member)).check(matches(isDisplayed())) + onView(withId(R.id.text_invite_members)).check(matches(isDisplayed())) + } + + @Test + fun channel_should_be_public() { + onView(withId(R.id.text_channel_type)).check(matches(withText("Public"))) + onView(withId(R.id.text_channel_type_description)).check(matches(withText(R.string.msg_public_channel_description))) + } + + @Test + fun channel_description_should_change_on_making_channel_private() { + onView(withId(R.id.switch_channel_type)).perform(click()) + Thread.sleep(1000) + onView(withId(R.id.text_channel_type)).check(matches(withText("Private"))) + onView(withId(R.id.text_channel_type_description)).check(matches(withText(R.string.msg_private_channel_description))) + Thread.sleep(1000) + onView(withId(R.id.switch_channel_type)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/directory/ui/DirectoryFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/directory/ui/DirectoryFragmentTest.kt new file mode 100644 index 0000000000..35824cdb72 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/directory/ui/DirectoryFragmentTest.kt @@ -0,0 +1,136 @@ +package chat.rocket.android.directory.ui + +import android.widget.AutoCompleteTextView +import androidx.test.espresso.Espresso +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion.Companion.withItemCount +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.greaterThan +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.CHANNELS +import testConfig.Config.Companion.DIRECTORY +import testConfig.Config.Companion.NON_EXISTING_CHANNEL +import testConfig.Config.Companion.NON_EXISTING_USER +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL +import testConfig.Config.Companion.TEST_USER +import testConfig.Config.Companion.USERS + +class DirectoryFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + navigateToDirectory() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + navigateToDirectory() + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_sort_by)).check(matches(isDisplayed())) + onView(withId(R.id.layout_app_bar)).check(matches(isDisplayed())) + onView(withText(CHANNELS)).check(matches(isDisplayed())) + } + + @Test + fun channels_should_be_greater_than_zero() { + Thread.sleep(5000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + } + + @Test + fun users_should_be_greater_than_zero() { + onView(withId(R.id.text_sort_by)).perform(click()) + onView(withText(USERS)).perform(click()) + Espresso.pressBack() + Thread.sleep(8000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + onView(withId(R.id.text_sort_by)).perform(click()) + onView(withText(CHANNELS)).perform(click()) + Espresso.pressBack() + } + + @Test + fun search_an_existing_channel() { + onView(withId(R.id.action_search)).perform(click()) + onView(isAssignableFrom(AutoCompleteTextView::class.java)).perform( + clearText(), + typeText(TEST_CHANNEL), + closeSoftKeyboard() + ) + Thread.sleep(8000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + } + + @Test + fun search_a_non_existing_channel() { + onView(withId(R.id.action_search)).perform(click()) + onView(isAssignableFrom(AutoCompleteTextView::class.java)).perform( + clearText(), + typeText(NON_EXISTING_CHANNEL), + closeSoftKeyboard() + ) + Thread.sleep(8000) + onView(withId(R.id.recycler_view)).check(withItemCount(equalTo(0))) + } + + @Test + fun search_an_existing_user() { + onView(withId(R.id.text_sort_by)).perform(click()) + onView(withText(USERS)).perform(click()) + Espresso.pressBack() + onView(withId(R.id.action_search)).perform(click()) + onView(isAssignableFrom(AutoCompleteTextView::class.java)).perform( + clearText(), + typeText(TEST_USER), + closeSoftKeyboard() + ) + Espresso.pressBack() + Thread.sleep(5000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + } + + @Test + fun search_a_non_existing_user() { + onView(withId(R.id.action_search)).perform(click()) + Thread.sleep(3000) + onView(isAssignableFrom(AutoCompleteTextView::class.java)).perform( + clearText(), + typeText(NON_EXISTING_USER), + closeSoftKeyboard() + ) + Espresso.pressBack() + Thread.sleep(3000) + onView(withId(R.id.recycler_view)).check(withItemCount(equalTo(0))) + } + + private fun navigateToDirectory() { + onView(withId(R.id.action_search)).perform(click()) + onView(withText(DIRECTORY)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/favoritemessages/ui/FavoriteMessagesFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/favoritemessages/ui/FavoriteMessagesFragmentTest.kt new file mode 100644 index 0000000000..05f1028241 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/favoritemessages/ui/FavoriteMessagesFragmentTest.kt @@ -0,0 +1,74 @@ +package chat.rocket.android.favoritemessages.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion.Companion.withItemCount +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.greaterThan +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.FAVORITE_MESSAGES +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL +import testConfig.Config.Companion.TEST_CHANNEL2 + + +class FavoriteMessagesFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + } catch (e: NoMatchingViewException) { + } + } + + @Test + fun messages_should_be_greater_than_zero(){ + navigateToGeneralChannelDetails() + onView(withText(FAVORITE_MESSAGES)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + } + + @Test + fun messages_should_be_zero(){ + navigateToSandboxChannelDetails() + onView(withText(FAVORITE_MESSAGES)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(equalTo(0))) + } + + private fun navigateToSandboxChannelDetails() { + Thread.sleep(5000) + onView(withText(TEST_CHANNEL2)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } + + private fun navigateToGeneralChannelDetails() { + Thread.sleep(5000) + onView(withText(TEST_CHANNEL)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/files/ui/FilesFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/files/ui/FilesFragmentTest.kt new file mode 100644 index 0000000000..4ad25f4f5c --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/files/ui/FilesFragmentTest.kt @@ -0,0 +1,86 @@ +package chat.rocket.android.files.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion.Companion.withItemCount +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.Matchers.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.FILES +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL +import testConfig.Config.Companion.TEST_USER + +class FilesFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + } catch (e: NoMatchingViewException) { + } + } + + @Test + fun check_toolbar_is_displayed() { + navigateToGeneralChannelDetails() + onView(withText(FILES)).perform(click()) + Thread.sleep(5000) + onView(withId(R.id.text_toolbar_title)).check(matches(isDisplayed())) + } + + @Test + fun no_of_files_should_be_zero() { + navigateToDummyUserChannelDetails() + onView(withText(FILES)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(equalTo(0))) + onView(withId(R.id.image_file)).check(matches(isDisplayed())) + onView(withId(R.id.text_no_file)).check(matches(isDisplayed())) + onView(withId(R.id.text_all_files_appear_here)).check(matches(isDisplayed())) + } + + @Test + fun no_of_files_should_be_greater_than_zero() { + navigateToGeneralChannelDetails() + onView(withText(FILES)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + onView(withId(R.id.image_file)).check(matches(not(isDisplayed()))) + onView(withId(R.id.text_no_file)).check(matches(not(isDisplayed()))) + onView(withId(R.id.text_all_files_appear_here)).check(matches(not(isDisplayed()))) + } + + private fun navigateToGeneralChannelDetails() { + Thread.sleep(5000) + onView(withText(TEST_CHANNEL)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } + + private fun navigateToDummyUserChannelDetails() { + Thread.sleep(5000) + onView(withText(TEST_USER)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/inviteusers/ui/InviteUsersFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/inviteusers/ui/InviteUsersFragmentTest.kt new file mode 100644 index 0000000000..487574dd81 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/inviteusers/ui/InviteUsersFragmentTest.kt @@ -0,0 +1,88 @@ +package chat.rocket.android.inviteusers.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.greaterThan +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.MEMBERS +import testConfig.Config.Companion.NON_EXISTING_USER +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL3 +import testConfig.Config.Companion.TEST_USER2 + + +class InviteUsersFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + navigateToInviteUser() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + navigateToInviteUser() + } + } + + private fun navigateToInviteUser() { + onView(withText(TEST_CHANNEL3)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + onView(withText(MEMBERS)).perform(click()) + Thread.sleep(3000) + onView(withId(R.id.button_invite_user)).perform(click()) + } + + @Test + fun check_UI_element() { + onView(withId(R.id.text_invite_users)).check(matches(withHint(R.string.msg_invite_members))) + onView(withId(R.id.recycler_view)).check(matches(isDisplayed())) + onView(withId(R.id.button_invite_user)).check(matches(isDisplayed())) + } + + @Test + fun search_an_existing_user() { + onView(withId(R.id.text_invite_users)).perform( + typeText(TEST_USER2), closeSoftKeyboard() + ) + Thread.sleep(2000) + onView(withId(R.id.recycler_view)).check( + RecyclerViewItemCountAssertion.withItemCount(greaterThan(0)) + ) + onView(withId(R.id.text_member)).check(matches(withText(TEST_USER2))) + } + + @Test + fun search_an_non_existing_user() { + onView(withId(R.id.text_invite_users)).perform( + typeText(NON_EXISTING_USER), closeSoftKeyboard() + ) + Thread.sleep(2000) + onView(withId(R.id.recycler_view)).check( + RecyclerViewItemCountAssertion.withItemCount(equalTo(0)) + ) + onView(withId(R.id.text_member_not_found)).check(matches(isDisplayed())) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/members/ui/MembersFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/members/ui/MembersFragmentTest.kt new file mode 100644 index 0000000000..87f9cee444 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/members/ui/MembersFragmentTest.kt @@ -0,0 +1,58 @@ +package chat.rocket.android.members.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion.Companion.withItemCount +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.Matchers.greaterThan +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.MEMBERS +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL + + +class MembersFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + navigateToChannelDetails() + } catch (e: NoMatchingViewException) { + navigateToChannelDetails() + } + } + + @Test + fun members_should_be_greater_than_zero(){ + onView(withText(MEMBERS)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + } + + private fun navigateToChannelDetails() { + Thread.sleep(3000) + onView(withText(TEST_CHANNEL)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/mentions/ui/MentionsFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/mentions/ui/MentionsFragmentTest.kt new file mode 100644 index 0000000000..0c102f1fc5 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/mentions/ui/MentionsFragmentTest.kt @@ -0,0 +1,74 @@ +package chat.rocket.android.mentions.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion.Companion.withItemCount +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.greaterThan +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.MENTIONS +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.TEST_CHANNEL +import testConfig.Config.Companion.TEST_CHANNEL2 + + +class MentionsFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + } catch (e: NoMatchingViewException) { + } + } + + @Test + fun mentions_should_be_greater_than_zero(){ + navigateToSandboxChannelDetails() + onView(withText(MENTIONS)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(greaterThan(0))) + } + + @Test + fun mentions_should_be_zero(){ + navigateToGeneralChannelDetails() + onView(withText(MENTIONS)).perform(click()) + Thread.sleep(6000) + onView(withId(R.id.recycler_view)).check(withItemCount(equalTo(0))) + } + + private fun navigateToSandboxChannelDetails() { + Thread.sleep(3000) + onView(withText(TEST_CHANNEL2)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } + + private fun navigateToGeneralChannelDetails() { + Thread.sleep(3000) + onView(withText(TEST_CHANNEL)).perform(click()) + Thread.sleep(2000) + onView(withId(R.id.text_toolbar_title)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/profile/ui/ProfileFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/profile/ui/ProfileFragmentTest.kt new file mode 100644 index 0000000000..676bd2388b --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/profile/ui/ProfileFragmentTest.kt @@ -0,0 +1,117 @@ +package chat.rocket.android.profile.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.loginUserToTheApp +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.AWAY +import testConfig.Config.Companion.BUSY +import testConfig.Config.Companion.CHANGE_STATUS +import testConfig.Config.Companion.EMAIL +import testConfig.Config.Companion.INVISIBLE +import testConfig.Config.Companion.NAME +import testConfig.Config.Companion.ONLINE +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.USERNAME + +@LargeTest +class ProfileFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + navigateToProfileFragment() + } catch (e: NoMatchingViewException) { + Thread.sleep(4000) + navigateToProfileFragment() + } + } + + @Test + fun check_UI_element() { + onView(withId(R.id.layout_avatar_profile)).check(matches(isDisplayed())) + onView(withId(R.id.text_status)).check(matches(isDisplayed())) + onView(withId(R.id.text_name)).check(matches(isDisplayed())) + onView(withId(R.id.text_email)).check(matches(isDisplayed())) + onView(withId(R.id.text_username)).check(matches(isDisplayed())) + } + + @Test + fun check_name_of_logged_in_user() { + onView(withId(R.id.text_name)).check(matches(withText(NAME))) + onView(withId(R.id.text_name)).check(matches(withHint("Please enter your name…"))) + } + + @Test + fun check_username_of_logged_in_user() { + onView(withId(R.id.text_username)).check(matches(withText(USERNAME))) + onView(withId(R.id.text_username)).check(matches(withHint("Please enter your username"))) + } + + @Test + fun check_email_of_logged_in_user() { + onView(withId(R.id.text_email)).check(matches(withText(EMAIL))) + onView(withId(R.id.text_email)).check(matches(withHint("Please enter your email address"))) + } + + @Test + fun user_status_should_be_online() { + onView(withId(R.id.text_status)).perform(click()) + onView(withText(ONLINE)).perform(click()) + onView(withText(CHANGE_STATUS)).perform(click()) + onView(withId(R.id.text_status)).check(matches(withText("Status: Online"))) + } + + @Test + fun user_status_should_be_away() { + onView(withId(R.id.text_status)).perform(click()) + onView(withText(AWAY)).perform(click()) + onView(withText(CHANGE_STATUS)).perform(click()) + onView(withId(R.id.text_status)).check(matches(withText("Status: Away"))) + } + + @Test + fun user_status_should_be_busy() { + onView(withId(R.id.text_status)).perform(click()) + onView(withText(BUSY)).perform(click()) + onView(withText(CHANGE_STATUS)).perform(click()) + onView(withId(R.id.text_status)).check(matches(withText("Status: Busy"))) + } + + @Test + fun user_status_should_be_Invisible() { + onView(withId(R.id.text_status)).perform(click()) + onView(withText(INVISIBLE)).perform(click()) + onView(withText(CHANGE_STATUS)).perform(click()) + onView(withId(R.id.text_status)).check(matches(withText("Status: Offline"))) + } + + private fun navigateToProfileFragment() { + onView(withId(R.id.toolbar)).check(matches(isDisplayed())) + onView(withContentDescription(R.string.abc_action_bar_up_description)).perform(click()) + Thread.sleep(1000) + onView(withId(R.id.image_avatar)).perform(click()) + Thread.sleep(2000) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/servers/ui/ServersBottomSheetFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/servers/ui/ServersBottomSheetFragmentTest.kt new file mode 100644 index 0000000000..849f1d04f6 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/servers/ui/ServersBottomSheetFragmentTest.kt @@ -0,0 +1,59 @@ +package chat.rocket.android.servers.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion +import chat.rocket.android.util.loginUserToTheApp +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.hamcrest.Matchers +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.ORG_NAME +import testConfig.Config.Companion.SERVER_URL + +class ServersBottomSheetFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + onView(withText(ORG_NAME)).perform(click()) + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + onView(withText(ORG_NAME)).perform(click()) + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_server)).check(matches(withText("Server"))) + onView(withId(R.id.view_divider)).check(matches(isDisplayed())) + onView(withId(R.id.recycler_view)).check(matches(isDisplayed())) + } + + @Test + fun no_of_available_server_should_be_greater_than_zero() { + onView(withId(R.id.recycler_view)).check( + RecyclerViewItemCountAssertion.withItemCount( + Matchers.greaterThan(0) + ) + ) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/settings/password/ui/PasswordFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/settings/password/ui/PasswordFragmentTest.kt new file mode 100644 index 0000000000..79278d532e --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/settings/password/ui/PasswordFragmentTest.kt @@ -0,0 +1,50 @@ +package chat.rocket.android.settings.password.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.settings.password.ui.PasswordFragment.Companion.newInstance +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.PASSWORD + + +class PasswordFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(PasswordActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + rule().activity.addFragmentBackStack(TAG_PASSWORD_FRAGMENT, R.id.fragment_container) { + newInstance() + } + Thread.sleep(2000) + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_new_password)).check(matches(isDisplayed())) + onView(withId(R.id.text_confirm_password)).check(matches(isDisplayed())) + } + + @Test + fun change_password() { + onView(withId(R.id.text_new_password)).perform( + typeText(PASSWORD), closeSoftKeyboard() + ) + onView(withId(R.id.text_confirm_password)).perform( + typeText(PASSWORD), closeSoftKeyboard() + ) + onView(withId(R.id.action_password)).perform(click()) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/settings/ui/SettingFragmentIntentTest.kt b/app/src/androidTest/java/chat/rocket/android/settings/ui/SettingFragmentIntentTest.kt new file mode 100644 index 0000000000..74be4e8c57 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/settings/ui/SettingFragmentIntentTest.kt @@ -0,0 +1,88 @@ +package chat.rocket.android.settings.ui + +import android.content.Intent +import android.net.Uri +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.intent.Intents +import androidx.test.espresso.intent.Intents.intended +import androidx.test.espresso.intent.matcher.IntentMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import androidx.test.uiautomator.UiDevice +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.hamcrest.CoreMatchers.allOf +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.SERVER_URL + +@Ignore("Run Separately") +@LargeTest +class SettingsFragmentIntentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + navigateToSettings() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + navigateToSettings() + } + } + + @Test + fun check_review_the_app() { + Intents.init() + val mDevice: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + onView(withId(R.id.text_review_this_app)).perform(click()) + intended(allOf( + hasAction(Intent.ACTION_VIEW), + hasData(Uri.parse("market://details?id=chat.rocket.android")) + )) + Thread.sleep(5000) + mDevice.pressBack() + mDevice.pressBack() + Intents.release() + } + + @Test + fun check_contact_us_button() { + Intents.init() + val mDevice: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + onView(withId(R.id.text_contact_us)).perform(click()) + intended(allOf( + hasAction(Intent.ACTION_CHOOSER), + hasExtra(Intent.EXTRA_TITLE, "Send email") + )) + Thread.sleep(5000) + mDevice.pressBack() + mDevice.pressBack() + Intents.release() + } + + private fun navigateToSettings() { + onView(withId(R.id.toolbar)).check(matches(isDisplayed())) + onView(withContentDescription(R.string.abc_action_bar_up_description)).perform(click()) + Thread.sleep(3000) + } +} diff --git a/app/src/androidTest/java/chat/rocket/android/settings/ui/SettingsFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/settings/ui/SettingsFragmentTest.kt new file mode 100644 index 0000000000..3e2bec8730 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/settings/ui/SettingsFragmentTest.kt @@ -0,0 +1,119 @@ +package chat.rocket.android.settings.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.swipeDown +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.APP_VERSION +import testConfig.Config.Companion.SERVER_URL +import testConfig.Config.Companion.USERNAME + +@Ignore("Run Separately") +@LargeTest +class SettingsFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + navigateToSettings() + } catch (e: NoMatchingViewException) { + Thread.sleep(3000) + navigateToSettings() + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_display_name)).check(matches(isDisplayed())) + onView(withId(R.id.text_status)).check(matches(isDisplayed())) + onView(withId(R.id.image_avatar)).check(matches(isDisplayed())) + onView(withId(R.id.text_contact_us)).check(matches(isDisplayed())) + onView(withId(R.id.text_language)).check(matches(isDisplayed())) + onView(withId(R.id.text_review_this_app)).check(matches(isDisplayed())) + onView(withId(R.id.text_share_this_app)).check(matches(isDisplayed())) + onView(withId(R.id.text_license)).check(matches(isDisplayed())) + onView(withId(R.id.text_app_version)).check(matches(isDisplayed())) + onView(withId(R.id.text_server_version)).check(matches(isDisplayed())) + onView(withId(R.id.text_send_crash_report)).check(matches(isDisplayed())) + onView(withId(R.id.text_send_crash_report_description)).check(matches(isDisplayed())) + onView(withId(R.id.text_logout)).check(matches(isDisplayed())) + onView(withId(R.id.text_delete_account)).check(matches(isDisplayed())) + } + + @Test + fun check_username() { + onView(withId(R.id.text_display_name)).check(matches(withText(USERNAME))) + } + + @Test + fun clicking_user_should_open_his_profile() { + onView(withId(R.id.text_display_name)).perform(click()) + onView(withId(R.id.profile_container)).check(matches(isDisplayed())) + } + + @Test + fun check_license() { + onView(withId(R.id.text_license)).perform(click()) + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } + + @Test + fun check_version_of_app() { + onView(withId(R.id.text_app_version)).check(matches(withText(APP_VERSION))) + } + + @Test + fun change_language_to_german_then_reset_to_english() { + onView(withId(R.id.text_language)).perform(click()) + onView(withText("German")).perform(click()) + Thread.sleep(2000) + onView(withContentDescription(R.string.abc_action_bar_up_description)).perform(click()) + Thread.sleep(3000) + onView(withText("Sprache")).check(matches(isDisplayed())).perform(click()) + onView(withText("Deutsch")).perform(swipeDown()).perform(swipeDown()).perform(swipeDown()).perform(swipeDown()) + onView(withText("Englisch")).check(matches(isDisplayed())).perform(click()) + } + + @Test + fun logout_dialog_should_be_displayed() { + onView(withId(R.id.text_logout)).perform(click()) + onView(withText(R.string.title_are_you_sure)) + onView(withText("Cancel")).perform(click()) + } + + @Test + fun delete_account_dialog_box_should_be_displayed() { + onView(withId(R.id.text_delete_account)).perform(click()) + onView(withText(R.string.title_are_you_sure)) + onView(withText("Cancel")).perform(click()) + } + + private fun navigateToSettings() { + onView(withId(R.id.toolbar)).check(matches(isDisplayed())) + onView(withContentDescription(R.string.abc_action_bar_up_description)).perform(click()) + Thread.sleep(3000) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/sortingandgrouping/ui/SortingAndGroupingBottomSheetFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/sortingandgrouping/ui/SortingAndGroupingBottomSheetFragmentTest.kt new file mode 100644 index 0000000000..c3738dc28d --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/sortingandgrouping/ui/SortingAndGroupingBottomSheetFragmentTest.kt @@ -0,0 +1,101 @@ +package chat.rocket.android.sortingandgrouping.ui + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.RecyclerViewItemCountAssertion +import chat.rocket.android.util.clickChildViewWithId +import chat.rocket.android.util.loginUserToTheApp +import chat.rocket.android.util.withTextInChild +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.hamcrest.Matchers.greaterThan +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.CHANNELS +import testConfig.Config.Companion.DIRECT_MESSAGES +import testConfig.Config.Companion.SERVER_URL + +class SortingAndGroupingBottomSheetFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(SERVER_URL) + } + loginUserToTheApp() + onView(withId(R.id.text_sort_by)).perform(click()) + } catch (e: NoMatchingViewException) { + onView(withId(R.id.text_sort_by)).perform(click()) + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.text_sort_by)).check(matches(isDisplayed())) + onView(withId(R.id.text_name)).check(matches(isDisplayed())) + onView(withId(R.id.text_activity)).check(matches(isDisplayed())) + onView(withId(R.id.view_divider)).check(matches(isDisplayed())) + onView(withId(R.id.text_unread_on_top)).check(matches(isDisplayed())) + onView(withId(R.id.text_group_by_type)).check(matches(isDisplayed())) + onView(withId(R.id.text_group_by_favorites)).check(matches(isDisplayed())) + } + + @Test + fun sort_by_name() { + onView(withId(R.id.text_name)).perform(click()) + Espresso.pressBack() + onView(withId(R.id.recycler_view)).check( + RecyclerViewItemCountAssertion.withItemCount(greaterThan(0)) + ) + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, withTextInChild(R.id.text_chat_name, "c239dk") + ) + ) + } + + @Test + fun sort_by_activity() { + onView(withId(R.id.text_activity)).perform(click()) + Espresso.pressBack() + onView(withId(R.id.recycler_view)).check( + RecyclerViewItemCountAssertion.withItemCount(greaterThan(0)) + ) + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, clickChildViewWithId(R.id.text_chat_name) + ) + ) + } + + @Test + fun group_by_type() { + onView(withId(R.id.text_group_by_type)).perform(click()) + Espresso.pressBack() + onView(withId(R.id.recycler_view)).check( + RecyclerViewItemCountAssertion.withItemCount(greaterThan(0)) + ) + onView(withText(CHANNELS)).check(matches(isDisplayed())) + onView(withText(DIRECT_MESSAGES)).check(matches(isDisplayed())) + onView(withId(R.id.text_sort_by)).perform(click()) + onView(withId(R.id.text_group_by_type)).perform(click()) + Espresso.pressBack() + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/userdetails/ui/UserDetailsFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/userdetails/ui/UserDetailsFragmentTest.kt new file mode 100644 index 0000000000..c36b5dca8c --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/userdetails/ui/UserDetailsFragmentTest.kt @@ -0,0 +1,76 @@ +package chat.rocket.android.userdetails.ui + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.analytics.event.ScreenViewEvent +import chat.rocket.android.authentication.ui.AuthenticationActivity +import chat.rocket.android.util.clickChildViewWithId +import chat.rocket.android.util.extensions.addFragmentBackStack +import chat.rocket.android.util.loginUserToTheApp +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config +import testConfig.Config.Companion.TEST_USER2 + +class UserDetailsFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + try { + rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) { + chat.rocket.android.authentication.login.ui.newInstance(Config.SERVER_URL) + } + loginUserToTheApp() + navigateToUserDetail() + } catch (e: NoMatchingViewException) { + Thread.sleep(5000) + navigateToUserDetail() + } + } + + @Test + fun check_UI_elements() { + onView(withId(R.id.image_avatar)).check(matches(isDisplayed())) + onView(withId(R.id.image_blur)).check(matches(isDisplayed())) + onView(withId(R.id.image_arrow_back)).check(matches(isDisplayed())) + onView(withId(R.id.text_message)).check(matches(withText("Message"))) + onView(withId(R.id.text_video_call)).check(matches(withText("Video call"))) + onView(withId(R.id.text_title_status)).check(matches(withText("Status"))) + onView(withId(R.id.text_title_timezone)).check(matches(withText("Timezone"))) + onView(withId(R.id.text_description_timezone)).check(matches(isDisplayed())) + onView(withId(R.id.button_remove_user)).check(matches(isDisplayed())) + } + + @Test + fun click_back_and_move_to_chatList() { + Espresso.pressBack() + onView(withId(R.id.message_list_container)).check(matches(isDisplayed())) + } + + private fun navigateToUserDetail() { + onView(withText(TEST_USER2)).perform(click()) + Thread.sleep(5000) + onView(withId(R.id.recycler_view)).perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, + clickChildViewWithId(R.id.image_avatar) + ) + ) + Thread.sleep(4000) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/util/utils.kt b/app/src/androidTest/java/chat/rocket/android/util/utils.kt new file mode 100644 index 0000000000..b54233ca36 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/util/utils.kt @@ -0,0 +1,206 @@ +package chat.rocket.android.util + +import android.view.View +import android.view.WindowManager +import android.widget.EditText +import android.widget.TextView +import androidx.appcompat.widget.Toolbar +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Root +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.ViewAssertion +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.matcher.BoundedMatcher +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import chat.rocket.android.R +import org.hamcrest.CoreMatchers.allOf +import org.hamcrest.Description +import org.hamcrest.Matcher +import org.hamcrest.MatcherAssert +import org.hamcrest.TypeSafeMatcher +import testConfig.Config.Companion.PASSWORD +import testConfig.Config.Companion.USERNAME + + +fun withHint(expectedHint: String): Matcher { + return object : TypeSafeMatcher() { + + override fun matchesSafely(view: View): Boolean { + if (view !is EditText) { + return false + } + + val hint = view.hint.toString() + return expectedHint == hint + } + + override fun describeTo(description: Description) {} + } +} + +fun withToolbarTitle(textMatcher: Matcher): Matcher { + return object : BoundedMatcher(Toolbar::class.java) { + public override fun matchesSafely(toolbar: Toolbar): Boolean { + return textMatcher.matches(toolbar.title) + } + + override fun describeTo(description: Description) { + description.appendText("with toolbar title: ") + textMatcher.describeTo(description) + } + } +} + +fun clickChildViewWithId(id: Int): ViewAction { + return object : ViewAction { + override fun getConstraints(): Matcher? { + return null + } + + override fun getDescription(): String { + return "" + } + + override fun perform(uiController: UiController, view: View) { + val v = view.findViewById(id) + v.performClick() + } + } +} + +//Matches an element with id as a childView +fun withTextInChild(id: Int, text: String): ViewAction { + return object : ViewAction { + override fun getConstraints(): Matcher { + return allOf( + isAssignableFrom(EditText::class.java), + isAssignableFrom(TextView::class.java) + ) + } + + override fun getDescription(): String { + return "" + } + + override fun perform(uiController: UiController, view: View) { + val v = view.findViewById(id) + v?.text = text + } + } +} + +//Matches an element with an id at a particular index +fun withIndex(matcher: Matcher, index: Int): Matcher { + return object : TypeSafeMatcher() { + var currentIndex = 0 + + override fun describeTo(description: Description) { + description.appendText("with index: ") + description.appendValue(index) + matcher.describeTo(description) + } + + public override fun matchesSafely(view: View): Boolean { + return matcher.matches(view) && currentIndex++ == index + } + } +} + +class ScrollToBottom : ViewAction { + override fun getDescription(): String { + return "scroll RecyclerView to bottom" + } + + override fun getConstraints(): Matcher { + return allOf(isAssignableFrom(RecyclerView::class.java), isDisplayed()) + } + + override fun perform(uiController: UiController?, view: View?) { + val recyclerView = view as RecyclerView + val itemCount = recyclerView.adapter?.itemCount + val position = itemCount?.minus(1) ?: 0 + recyclerView.scrollToPosition(position) + uiController?.loopMainThreadUntilIdle() + } +} + +class ScrollToTop : ViewAction { + override fun getDescription(): String { + return "scroll RecyclerView to bottom" + } + + override fun getConstraints(): Matcher { + return allOf(isAssignableFrom(RecyclerView::class.java), isDisplayed()) + } + + override fun perform(uiController: UiController?, view: View?) { + val recyclerView = view as RecyclerView + recyclerView.scrollToPosition(0) + uiController?.loopMainThreadUntilIdle() + } +} + +fun loginUserToTheApp() { + onView(ViewMatchers.withId(R.id.text_username_or_email)).perform( + ViewActions.typeText(USERNAME), + closeSoftKeyboard() + ) + onView(ViewMatchers.withId(R.id.text_password)) + .perform(ViewActions.typeText(PASSWORD), closeSoftKeyboard()) + onView(ViewMatchers.withId(R.id.button_log_in)).perform(click()) + Thread.sleep(12000) +} + +class RecyclerViewItemCountAssertion private constructor(private val matcher: Matcher) : + ViewAssertion { + + override fun check(view: View, noViewFoundException: NoMatchingViewException?) { + if (noViewFoundException != null) { + throw noViewFoundException + } + val recyclerView = view as RecyclerView + val adapter = recyclerView.adapter + MatcherAssert.assertThat(adapter!!.itemCount, matcher) + } + + companion object { + + fun withItemCount(matcher: Matcher): RecyclerViewItemCountAssertion { + return RecyclerViewItemCountAssertion(matcher) + } + } +} + +class ToastMatcher : TypeSafeMatcher() { + + override fun describeTo(description: Description) { + description.appendText("is toast") + } + + public override fun matchesSafely(root: Root): Boolean { + val type = root.windowLayoutParams.get().type + if (type == WindowManager.LayoutParams.TYPE_TOAST) { + val windowToken = root.decorView.windowToken + val appToken = root.decorView.applicationWindowToken + if (windowToken === appToken) { + // windowToken == appToken means this window isn't contained by any other windows. + // if it was a window for an activity, it would have TYPE_BASE_APPLICATION. + return true + } + } + return false + } + + companion object { + fun isToast(): Matcher { + return ToastMatcher() + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragmentTest.kt b/app/src/androidTest/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragmentTest.kt new file mode 100644 index 0000000000..b6b06fd143 --- /dev/null +++ b/app/src/androidTest/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragmentTest.kt @@ -0,0 +1,37 @@ +package chat.rocket.android.webview.adminpanel.ui + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.rule.ActivityTestRule +import chat.rocket.android.R +import chat.rocket.android.main.ui.MainActivity +import chat.rocket.android.util.extensions.addFragmentBackStack +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import testConfig.Config.Companion.ADMIN_PANEL_URL +import testConfig.Config.Companion.USER_TOKEN + +class AdminPanelWebViewFragmentTest { + + @JvmField + var activityRule = ActivityTestRule(MainActivity::class.java, true, true) + + @Rule + fun rule() = activityRule + + @Before + fun setUp() { + Thread.sleep(3000) + rule().activity.addFragmentBackStack(TAG_ADMIN_PANEL_WEB_VIEW_FRAGMENT, R.id.fragment_container) { + newInstance(ADMIN_PANEL_URL, USER_TOKEN) + } + } + + @Test + fun check_webview_is_opened() { + onView(withId(R.id.web_view)).check(matches(isDisplayed())) + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt index 3d2c8ecdf8..5970e1e3ca 100644 --- a/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt @@ -34,8 +34,10 @@ import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.loginWithEmail import chat.rocket.core.internal.rest.loginWithLdap import chat.rocket.core.internal.rest.me +import testConfig.Config.Companion.DEFAULT_TEST_URL import javax.inject.Inject + class LoginPresenter @Inject constructor( private val view: LoginView, private val strategy: CancelStrategy, @@ -50,7 +52,7 @@ class LoginPresenter @Inject constructor( val serverInteractor: GetConnectingServerInteractor ) { // TODO - we should validate the current server when opening the app, and have a nonnull get() - private var currentServer = serverInteractor.get()!! + private var currentServer = serverInteractor.get() ?: DEFAULT_TEST_URL private val token = tokenRepository.get(currentServer) private lateinit var client: RocketChatClient private lateinit var settings: PublicSettings diff --git a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt index 06d4e6fcb4..8115dc87c9 100644 --- a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt @@ -33,6 +33,7 @@ import chat.rocket.core.internal.rest.loginWithOauth import chat.rocket.core.internal.rest.loginWithSaml import chat.rocket.core.internal.rest.me import kotlinx.coroutines.delay +import testConfig.Config.Companion.DEFAULT_TEST_URL import javax.inject.Inject private const val TYPE_LOGIN_OAUTH = 1 @@ -54,7 +55,7 @@ class LoginOptionsPresenter @Inject constructor( serverInteractor: GetConnectingServerInteractor ) { // TODO - we should validate the current server when opening the app, and have a nonnull get() - private var currentServer = serverInteractor.get()!! + private var currentServer = serverInteractor.get() ?: DEFAULT_TEST_URL private val token = tokenRepository.get(currentServer) private lateinit var client: RocketChatClient private lateinit var settings: PublicSettings diff --git a/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt b/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt index a39790f5c6..842f79915d 100644 --- a/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt @@ -24,6 +24,7 @@ import chat.rocket.common.model.Token import chat.rocket.common.util.ifNull import chat.rocket.core.RocketChatClient import chat.rocket.core.internal.rest.updateOwnBasicInformation +import testConfig.Config.Companion.DEFAULT_TEST_URL import javax.inject.Inject class RegisterUsernamePresenter @Inject constructor( @@ -38,7 +39,7 @@ class RegisterUsernamePresenter @Inject constructor( val factory: RocketChatClientFactory, val settingsInteractor: GetSettingsInteractor ) { - private val currentServer = serverInteractor.get()!! + private val currentServer = serverInteractor.get()?: DEFAULT_TEST_URL private val client: RocketChatClient = factory.get(currentServer) private var settings: PublicSettings = settingsInteractor.get(currentServer) private val token = tokenRepository.get(currentServer) @@ -74,7 +75,7 @@ class RegisterUsernamePresenter @Inject constructor( } } - private fun saveAccount(username: String) { + fun saveAccount(username: String) { val icon = settings.favicon()?.let { currentServer.serverLogoUrl(it) } diff --git a/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt index c129db9f49..d08eb3b90f 100644 --- a/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt @@ -11,6 +11,7 @@ import chat.rocket.common.RocketChatInvalidResponseException import chat.rocket.common.util.ifNull import chat.rocket.core.RocketChatClient import chat.rocket.core.internal.rest.forgotPassword +import testConfig.Config.Companion.DEFAULT_TEST_URL import javax.inject.Inject class ResetPasswordPresenter @Inject constructor( @@ -20,7 +21,7 @@ class ResetPasswordPresenter @Inject constructor( factory: RocketChatClientFactory, serverInteractor: GetConnectingServerInteractor ) { - private val currentServer = serverInteractor.get()!! + private val currentServer = serverInteractor.get()?: DEFAULT_TEST_URL private val client: RocketChatClient = factory.get(currentServer) fun resetPassword(email: String) { diff --git a/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt index 3c0d9014e1..50cfa8e5e6 100644 --- a/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt @@ -28,6 +28,7 @@ import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.signup import chat.rocket.core.model.Myself +import testConfig.Config.Companion.DEFAULT_TEST_URL import javax.inject.Inject class SignupPresenter @Inject constructor( @@ -43,7 +44,7 @@ class SignupPresenter @Inject constructor( tokenRepository: TokenRepository, settingsInteractor: GetSettingsInteractor ) { - private val currentServer = serverInteractor.get()!! + private val currentServer = serverInteractor.get() ?: DEFAULT_TEST_URL private var settings: PublicSettings = settingsInteractor.get(currentServer) private val token = tokenRepository.get(currentServer) diff --git a/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt index 107f12eb03..71d8812c41 100644 --- a/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt @@ -28,6 +28,7 @@ import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.loginWithEmail import chat.rocket.core.internal.rest.me import chat.rocket.core.model.Myself +import testConfig.Config.Companion.DEFAULT_TEST_URL import javax.inject.Inject class TwoFAPresenter @Inject constructor( @@ -43,7 +44,7 @@ class TwoFAPresenter @Inject constructor( val serverInteractor: GetConnectingServerInteractor, val settingsInteractor: GetSettingsInteractor ) { - private val currentServer = serverInteractor.get()!! + private val currentServer = serverInteractor.get()?: DEFAULT_TEST_URL private var settings: PublicSettings = settingsInteractor.get(currentServer) private val token = tokenRepository.get(currentServer) diff --git a/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt b/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt index 315ef9a1a5..ae85b7bb9d 100644 --- a/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt +++ b/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt @@ -233,7 +233,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { handler.removeCallbacks { dismissConnectionState } text_connection_status.text = when (state) { is State.Connected -> { - handler.postDelayed({ dismissConnectionState }, 2000) + handler.postDelayed({ dismissConnectionState }, 1000) getString(R.string.status_connected) } is State.Disconnected -> getString(R.string.status_disconnected) diff --git a/app/src/main/java/chat/rocket/android/files/ui/FilesFragment.kt b/app/src/main/java/chat/rocket/android/files/ui/FilesFragment.kt index 4dd06e7494..79647009f3 100644 --- a/app/src/main/java/chat/rocket/android/files/ui/FilesFragment.kt +++ b/app/src/main/java/chat/rocket/android/files/ui/FilesFragment.kt @@ -104,7 +104,7 @@ class FilesFragment : Fragment(), FilesView { override fun openImage(url: String, name: String) { ui { - ImageHelper.openImage(root_layout.context, url, name) + ImageHelper.openImage(files_layout.context, url, name) } } diff --git a/app/src/main/java/chat/rocket/android/util/extensions/Ui.kt b/app/src/main/java/chat/rocket/android/util/extensions/Ui.kt index 6f60a628fb..8abbd7683b 100644 --- a/app/src/main/java/chat/rocket/android/util/extensions/Ui.kt +++ b/app/src/main/java/chat/rocket/android/util/extensions/Ui.kt @@ -74,7 +74,7 @@ fun AppCompatActivity.addFragmentBackStack( ) .replace(layoutId, fragment, tag) .addToBackStack(tag) - .commit() + .commitAllowingStateLoss() } fun AppCompatActivity.toPreviousView() { diff --git a/app/src/main/java/testConfig/Config.kt b/app/src/main/java/testConfig/Config.kt new file mode 100644 index 0000000000..59cfda2c37 --- /dev/null +++ b/app/src/main/java/testConfig/Config.kt @@ -0,0 +1,71 @@ +package testConfig + +import chat.rocket.android.BuildConfig + +class Config { + companion object { + const val ORG_NAME: String = "Rocket.Chat" + const val SERVER: String = "open.rocket.chat" + const val SERVER_URL: String = "serverUrl" + + //Organisation using RC forks should create a user with below details before running tests + const val USERNAME: String = "user121" + const val PASSWORD: String = "123456" + const val NAME: String = "user121" + const val EMAIL: String = "qasdf@gmail.com" + + //Existing User + const val TEST_USER: String ="dfcxc" + const val TEST_USER2: String ="govind.dixit" + + const val NON_EXISTING_USER: String = "**33##&&" + + //Existing Channel + // Other organisation have to create channels before testing + const val TEST_CHANNEL: String ="general" + const val TEST_CHANNEL2: String ="sandbox" + const val TEST_CHANNEL3: String ="dfcxc" + + const val NON_EXISTING_CHANNEL: String = "**33##&&" + + const val CODE = "1234" + const val USER_ID = "user_id" + const val AUTH_TOKEN = "auth_token" + const val USER_TOKEN = "user_token" + + const val CURRENT_SERVER: String = "https://$SERVER" + const val COMMUNTIY_SERVER: String = CURRENT_SERVER + const val DEFAULT_TEST_URL: String = CURRENT_SERVER + const val USER_NAME: String = "userName" + const val AVATAR_URL: String = "serverUrl/avatar/userName?format=jpeg&rc_uid=null&rc_token=null" + const val USER_AVATAR: String = "$CURRENT_SERVER/avatar/userName?format=jpeg&rc_uid=null&rc_token=null" + const val UPDATED_AVATAR: String = "$CURRENT_SERVER/avatar/$USERNAME?format=jpeg&rc_uid=null&rc_token=null" + const val TERMS_OF_SERVICE: String = "Terms of Service" + const val PRIVACY_POLICY: String = "Privacy Policy" + const val TERMS_OF_SERVICE_URL: String = "$CURRENT_SERVER/terms-of-service" + const val PRIVACY_POLICY_URL: String = "$CURRENT_SERVER/privacy-policy" + const val ADMIN_PANEL_URL = "$CURRENT_SERVER/admin/info?layout=embedded" + const val LICENSE_URL = "https://github.com/RocketChat/Rocket.Chat.Android/blob/develop/LICENSE" + const val LICENSE = "LICENSE" + const val CHANGE_STATUS: String = "CHANGE STATUS" + const val ONLINE: String = "Online" + const val BUSY: String = "Busy" + const val AWAY: String = "Away" + const val INVISIBLE: String = "Invisible" + const val MEMBERS: String = "Members" + const val CHANNELS: String = "Channels" + const val DIRECT_MESSAGES: String = "Direct Messages" + const val FILES: String = "Files" + const val USERS: String = "Users" + const val DIRECTORY: String = "Directory" + const val VERSION_NAME: String = BuildConfig.VERSION_NAME + const val VERSION_CODE: Int = BuildConfig.VERSION_CODE + const val APP_VERSION: String = "Version: $VERSION_NAME ($VERSION_CODE)" + const val FAVORITE_MESSAGES: String = "Favorite Messages" + const val PINNED_MESSAGES: String = "Pinned Messages" + const val MENTIONS: String = "Mentions" + const val CHAT_ROOM_ID: String = "abcd1234ABCD" + const val CHAT_ROOM_TYPE: String = "Public" + const val TEST_MESSAGE: String = "This is a test message" + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_authentication_on_boarding.xml b/app/src/main/res/layout/fragment_authentication_on_boarding.xml index 4cf9ab4697..27bcd336e6 100644 --- a/app/src/main/res/layout/fragment_authentication_on_boarding.xml +++ b/app/src/main/res/layout/fragment_authentication_on_boarding.xml @@ -63,6 +63,7 @@ tools:ignore="ContentDescription" /> diff --git a/app/src/main/res/layout/fragment_files.xml b/app/src/main/res/layout/fragment_files.xml index 1991c4707c..42b0d5d84e 100644 --- a/app/src/main/res/layout/fragment_files.xml +++ b/app/src/main/res/layout/fragment_files.xml @@ -2,7 +2,7 @@ diff --git a/app/src/main/res/layout/fragment_members.xml b/app/src/main/res/layout/fragment_members.xml index 2176f23d05..588a400889 100644 --- a/app/src/main/res/layout/fragment_members.xml +++ b/app/src/main/res/layout/fragment_members.xml @@ -2,6 +2,7 @@ diff --git a/app/src/main/res/layout/fragment_mentions.xml b/app/src/main/res/layout/fragment_mentions.xml index f0fcc461df..a08fb7b516 100644 --- a/app/src/main/res/layout/fragment_mentions.xml +++ b/app/src/main/res/layout/fragment_mentions.xml @@ -2,6 +2,7 @@ diff --git a/app/src/main/res/layout/fragment_pinned_messages.xml b/app/src/main/res/layout/fragment_pinned_messages.xml index f0baaae819..9cfad13784 100644 --- a/app/src/main/res/layout/fragment_pinned_messages.xml +++ b/app/src/main/res/layout/fragment_pinned_messages.xml @@ -2,6 +2,7 @@ diff --git a/app/src/main/res/layout/fragment_user_details.xml b/app/src/main/res/layout/fragment_user_details.xml index 3363303d7d..8961c06daf 100644 --- a/app/src/main/res/layout/fragment_user_details.xml +++ b/app/src/main/res/layout/fragment_user_details.xml @@ -9,6 +9,7 @@ diff --git a/app/src/test/java/chat/rocket/android/authentication/login/presentation/LoginPresenterTest.kt b/app/src/test/java/chat/rocket/android/authentication/login/presentation/LoginPresenterTest.kt new file mode 100644 index 0000000000..d9f7c35548 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/authentication/login/presentation/LoginPresenterTest.kt @@ -0,0 +1,85 @@ +package chat.rocket.android.authentication.login.presentation + +import chat.rocket.android.analytics.AnalyticsManager +import chat.rocket.android.authentication.presentation.AuthenticationNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.infrastructure.LocalRepository +import chat.rocket.android.server.domain.* +import chat.rocket.android.server.domain.model.Account +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import chat.rocket.common.model.Token +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER +import testConfig.Config.Companion.UPDATED_AVATAR +import testConfig.Config.Companion.USERNAME + +class LoginPresenterTest { + + lateinit var loginPresenter: LoginPresenter + + private val view = mock(LoginView::class.java) + private val strategy = mock(CancelStrategy::class.java) + private val navigator = mock(AuthenticationNavigator::class.java) + private val tokenRepository = mock(TokenRepository::class.java) + private val localRepository = mock(LocalRepository::class.java) + private val settingsInteractor = mock(GetSettingsInteractor::class.java) + private val analyticsManager = mock(AnalyticsManager::class.java) + private val saveCurrentServer = mock(SaveCurrentServerInteractor::class.java) + private val saveAccountInteractor = mock(SaveAccountInteractor::class.java) + private val factory = mock(RocketChatClientFactory::class.java) + private val serverInteractor = mock(GetConnectingServerInteractor::class.java) + private val token = mock(Token::class.java) + + private val account = Account( + CURRENT_SERVER, CURRENT_SERVER, null, null, + USERNAME, UPDATED_AVATAR, null, null + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + loginPresenter = LoginPresenter( + view, strategy, navigator, tokenRepository, localRepository, settingsInteractor, + analyticsManager, saveCurrentServer, saveAccountInteractor, factory, serverInteractor + ) + } + + @Test + fun `check account is saved`() { + loginPresenter.setupView() + val method = loginPresenter.javaClass.getDeclaredMethod("saveAccount", String::class.java) + method.isAccessible = true + val parameters = arrayOfNulls(1) + parameters[0] = USERNAME + method.invoke(loginPresenter, *parameters) + verify(saveAccountInteractor).save(account) + } + + @Test + fun `view should not be null`() { + loginPresenter.setupView() + assertNotNull(view) + } + + @Test + fun `save token to repository`() { + loginPresenter.setupView() + val method = loginPresenter.javaClass.getDeclaredMethod("saveToken", Token::class.java) + method.isAccessible = true + val parameters = arrayOfNulls(1) + parameters[0] = token + method.invoke(loginPresenter, *parameters) + verify(tokenRepository).save(CURRENT_SERVER, token) + } + + @Test + fun `navigate to forgot password`() { + loginPresenter.forgotPassword() + verify(navigator).toForgotPassword() + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenterTest.kt b/app/src/test/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenterTest.kt new file mode 100644 index 0000000000..8c464b2a95 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenterTest.kt @@ -0,0 +1,106 @@ +package chat.rocket.android.authentication.loginoptions.presentation + +import chat.rocket.android.analytics.AnalyticsManager +import chat.rocket.android.authentication.presentation.AuthenticationNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.infrastructure.LocalRepository +import chat.rocket.android.server.domain.* +import chat.rocket.android.server.domain.model.Account +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import chat.rocket.common.model.Token +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.AUTH_TOKEN +import testConfig.Config.Companion.CURRENT_SERVER +import testConfig.Config.Companion.UPDATED_AVATAR +import testConfig.Config.Companion.USERNAME +import testConfig.Config.Companion.USER_ID + + +class LoginOptionsPresenterTest { + + private val view = Mockito.mock(LoginOptionsView::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val navigator = Mockito.mock(AuthenticationNavigator::class.java) + private val localRepository = Mockito.mock(LocalRepository::class.java) + private val settingsInteractor = Mockito.mock(GetSettingsInteractor::class.java) + private val analyticsManager = Mockito.mock(AnalyticsManager::class.java) + private val saveCurrentServerInteractor = Mockito.mock(SaveCurrentServerInteractor::class.java) + private val saveAccountInteractor = Mockito.mock(SaveAccountInteractor::class.java) + private val factory = Mockito.mock(RocketChatClientFactory::class.java) + private val serverInteractor = Mockito.mock(GetConnectingServerInteractor::class.java) + private val tokenRepository = Mockito.mock(TokenRepository::class.java) + + lateinit var loginOptionsPresenter: LoginOptionsPresenter + + private val account = Account( + CURRENT_SERVER, CURRENT_SERVER, null, null, + USERNAME, UPDATED_AVATAR, null, null + ) + + private val token = Token( + AUTH_TOKEN, USER_ID + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + loginOptionsPresenter = LoginOptionsPresenter( + view, strategy, factory, navigator, settingsInteractor, localRepository, saveCurrentServerInteractor, + saveAccountInteractor, analyticsManager, tokenRepository, serverInteractor + ) + } + + @Test + fun `navigate to create account`() { + loginOptionsPresenter.toCreateAccount() + verify(navigator).toCreateAccount() + } + + @Test + fun `navigate to login with email`() { + loginOptionsPresenter.toLoginWithEmail() + verify(navigator).toLogin(CURRENT_SERVER) + } + + @Test + fun `check account is saved`() { + val method1 = loginOptionsPresenter.javaClass.getDeclaredMethod("setupConnectionInfo", String::class.java) + method1.isAccessible = true + val parameters1 = arrayOfNulls(1) + parameters1[0] = CURRENT_SERVER + method1.invoke(loginOptionsPresenter, *parameters1) + val method = loginOptionsPresenter.javaClass.getDeclaredMethod("saveAccount", String::class.java) + method.isAccessible = true + val parameters = arrayOfNulls(1) + parameters[0] = USERNAME + method.invoke(loginOptionsPresenter, *parameters) + verify(saveAccountInteractor).save(account) + } + + @Test + fun `setup connection info`() { + val method = loginOptionsPresenter.javaClass.getDeclaredMethod("setupConnectionInfo", String::class.java) + method.isAccessible = true + val parameters = arrayOfNulls(1) + parameters[0] = CURRENT_SERVER + method.invoke(loginOptionsPresenter, *parameters) + assertEquals(parameters[0], CURRENT_SERVER) + } + + @Test + fun `check token is saved`() { + val method = loginOptionsPresenter.javaClass.getDeclaredMethod("saveToken", Token::class.java) + method.isAccessible = true + val parameters = arrayOfNulls(1) + parameters[0] = token + method.invoke(loginOptionsPresenter, *parameters) + verify(tokenRepository).save(CURRENT_SERVER, token) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenterTest.kt b/app/src/test/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenterTest.kt new file mode 100644 index 0000000000..2c3acf11df --- /dev/null +++ b/app/src/test/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenterTest.kt @@ -0,0 +1,52 @@ +package chat.rocket.android.authentication.onboarding.presentation + +import chat.rocket.android.authentication.presentation.AuthenticationNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.server.domain.GetAccountsInteractor +import chat.rocket.android.server.domain.GetSettingsInteractor +import chat.rocket.android.server.domain.RefreshSettingsInteractor +import chat.rocket.android.server.domain.SaveConnectingServerInteractor +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.COMMUNTIY_SERVER +import testConfig.Config.Companion.CURRENT_SERVER + + +class OnBoardingPresenterTest { + + lateinit var onBoardingPresenter: OnBoardingPresenter + + private val view = Mockito.mock(OnBoardingView::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val navigator = Mockito.mock(AuthenticationNavigator::class.java) + private val serverInteractor = Mockito.mock(SaveConnectingServerInteractor::class.java) + private val refreshSettingsInteractor = Mockito.mock(RefreshSettingsInteractor::class.java) + private val getAccountsInteractor = Mockito.mock(GetAccountsInteractor::class.java) + private val settingsInteractor = Mockito.mock(GetSettingsInteractor::class.java) + private val factory = Mockito.mock(RocketChatClientFactory::class.java) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + onBoardingPresenter = OnBoardingPresenter( + view, strategy, navigator, serverInteractor, refreshSettingsInteractor, + getAccountsInteractor, settingsInteractor, factory, CURRENT_SERVER + ) + } + + @Test + fun `navigate to sign in to your server`() { + onBoardingPresenter.toSignInToYourServer() + verify(navigator).toSignInToYourServer() + } + + @Test + fun `navigate to web page if new server is created`() { + onBoardingPresenter.toCreateANewServer(COMMUNTIY_SERVER) + verify(navigator).toWebPage(COMMUNTIY_SERVER) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/authentication/presentation/AuthenticationPresenterTest.kt b/app/src/test/java/chat/rocket/android/authentication/presentation/AuthenticationPresenterTest.kt new file mode 100644 index 0000000000..22c39b9c66 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/authentication/presentation/AuthenticationPresenterTest.kt @@ -0,0 +1,83 @@ +package chat.rocket.android.authentication.presentation + +import chat.rocket.android.authentication.domain.model.DeepLinkInfo +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.infrastructure.LocalRepository +import chat.rocket.android.server.domain.* +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER +import testConfig.Config.Companion.PRIVACY_POLICY +import testConfig.Config.Companion.PRIVACY_POLICY_URL +import testConfig.Config.Companion.TERMS_OF_SERVICE +import testConfig.Config.Companion.TERMS_OF_SERVICE_URL + + +class AuthenticationPresenterTest { + + private lateinit var authenticationPresenter: AuthenticationPresenter + + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val navigator = Mockito.mock(AuthenticationNavigator::class.java) + private val tokenRepository = Mockito.mock(TokenRepository::class.java) + private val localRepository = Mockito.mock(LocalRepository::class.java) + private val settingsRepository = Mockito.mock(SettingsRepository::class.java) + private val getCurrentServer = Mockito.mock(GetCurrentServerInteractor::class.java) + private val getAccountInteractor = Mockito.mock(GetAccountInteractor::class.java) + private val serverInteractor = Mockito.mock(GetConnectingServerInteractor::class.java) + + private val deepLinkInfo = DeepLinkInfo( + "www.abc.com", "UserId", "token", + "rId", "public", "abc" + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + authenticationPresenter = AuthenticationPresenter( + strategy, navigator, getCurrentServer, getAccountInteractor, settingsRepository, + localRepository, tokenRepository, serverInteractor + ) + } + + @Test + fun `navigate to tos web page`() { + authenticationPresenter.termsOfService(TERMS_OF_SERVICE) + verify(navigator).toWebPage(TERMS_OF_SERVICE_URL, TERMS_OF_SERVICE) + } + + @Test + fun `navigate to privacy policy web page`() { + authenticationPresenter.privacyPolicy(PRIVACY_POLICY) + verify(navigator).toWebPage(PRIVACY_POLICY_URL, PRIVACY_POLICY) + } + + @Test + fun `navigate to sign in to your server`() { + authenticationPresenter.toSignInToYourServer(deepLinkInfo) + verify(navigator).toSignInToYourServer(deepLinkInfo, false) + } + + @Test + fun `save deep link info`() { + authenticationPresenter.saveDeepLinkInfo(deepLinkInfo) + verify(navigator).saveDeepLinkInfo(deepLinkInfo) + } + + @Test + fun `navigate to chat list`() { + authenticationPresenter.toChatList() + verify(navigator).toChatList() + } + + @Test + fun `navigate to chat list with deeplink`() { + authenticationPresenter.toChatList(deepLinkInfo) + verify(navigator).toChatList(deepLinkInfo) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenterTest.kt b/app/src/test/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenterTest.kt new file mode 100644 index 0000000000..5c70d12a45 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenterTest.kt @@ -0,0 +1,52 @@ +package chat.rocket.android.authentication.registerusername.presentation + +import chat.rocket.android.analytics.AnalyticsManager +import chat.rocket.android.authentication.presentation.AuthenticationNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.server.domain.* +import chat.rocket.android.server.domain.model.Account +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER +import testConfig.Config.Companion.USER_AVATAR +import testConfig.Config.Companion.USER_NAME + +class RegisterUsernamePresenterTest { + + private val view = mock(RegisterUsernameView::class.java) + private val strategy = mock(CancelStrategy::class.java) + private val navigator = mock(AuthenticationNavigator::class.java) + private val tokenRepository = mock(TokenRepository::class.java) + private val settingsInteractor = mock(GetSettingsInteractor::class.java) + private val analyticsManager = mock(AnalyticsManager::class.java) + private val saveCurrentServer = mock(SaveCurrentServerInteractor::class.java) + private val saveAccountInteractor = mock(SaveAccountInteractor::class.java) + private val factory = mock(RocketChatClientFactory::class.java) + private val serverInteractor = mock(GetConnectingServerInteractor::class.java) + + private lateinit var registerUsernamePresenter: RegisterUsernamePresenter + + private val account = Account( + CURRENT_SERVER, CURRENT_SERVER, null, null, + USER_NAME, USER_AVATAR, null, null + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + registerUsernamePresenter = RegisterUsernamePresenter( + view, strategy, navigator, tokenRepository, saveAccountInteractor, analyticsManager, + saveCurrentServer, serverInteractor, factory, settingsInteractor + ) + } + + @Test + fun `save new user account`() { + registerUsernamePresenter.saveAccount(USER_NAME) + verify(saveAccountInteractor).save(account) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/authentication/signup/presentation/SignupPresenterTest.kt b/app/src/test/java/chat/rocket/android/authentication/signup/presentation/SignupPresenterTest.kt new file mode 100644 index 0000000000..c6520439ed --- /dev/null +++ b/app/src/test/java/chat/rocket/android/authentication/signup/presentation/SignupPresenterTest.kt @@ -0,0 +1,52 @@ +package chat.rocket.android.authentication.signup.presentation + +import chat.rocket.android.analytics.AnalyticsManager +import chat.rocket.android.authentication.presentation.AuthenticationNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.infrastructure.LocalRepository +import chat.rocket.android.server.domain.* +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER +import testConfig.Config.Companion.PRIVACY_POLICY_URL +import testConfig.Config.Companion.TERMS_OF_SERVICE_URL + +class SignupPresenterTest { + + private val view = mock(SignupView::class.java) + private val strategy = mock(CancelStrategy::class.java) + private val navigator = mock(AuthenticationNavigator::class.java) + private val localRepository = mock(LocalRepository::class.java) + private val settingsInteractor = mock(GetSettingsInteractor::class.java) + private val analyticsManager = mock(AnalyticsManager::class.java) + private val saveCurrentServerInteractor = mock(SaveCurrentServerInteractor::class.java) + private val saveAccountInteractor = mock(SaveAccountInteractor::class.java) + private val factory = mock(RocketChatClientFactory::class.java) + private val serverInteractor = mock(GetConnectingServerInteractor::class.java) + private val tokenRepository = mock(TokenRepository::class.java) + + lateinit var signUpPresenter: SignupPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + signUpPresenter = SignupPresenter(view, strategy, navigator, localRepository, serverInteractor, saveCurrentServerInteractor, + analyticsManager, factory, saveAccountInteractor, tokenRepository, settingsInteractor) + } + + @Test + fun `navigate to tos web page`() { + signUpPresenter.termsOfService() + verify(navigator).toWebPage(TERMS_OF_SERVICE_URL) + } + + @Test + fun `navigate to privacy policy web page`() { + signUpPresenter.privacyPolicy() + verify(navigator).toWebPage(PRIVACY_POLICY_URL) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenterTest.kt b/app/src/test/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenterTest.kt new file mode 100644 index 0000000000..6f1914bd13 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenterTest.kt @@ -0,0 +1,70 @@ +package chat.rocket.android.chatdetails.presentation + +import chat.rocket.android.chatroom.presentation.ChatRoomNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.server.domain.GetCurrentServerInteractor +import chat.rocket.android.server.infrastructure.ConnectionManagerFactory +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CHAT_ROOM_ID +import testConfig.Config.Companion.CHAT_ROOM_TYPE +import testConfig.Config.Companion.CURRENT_SERVER + +class ChatDetailsPresenterTest { + + private val view = Mockito.mock(ChatDetailsView::class.java) + private val navigator = Mockito.mock(ChatRoomNavigator::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val serverInteractor = Mockito.mock(GetCurrentServerInteractor::class.java) + private val factory = Mockito.mock(ConnectionManagerFactory::class.java) + + private lateinit var chatDetailsPresenter: ChatDetailsPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + Mockito.`when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + chatDetailsPresenter = ChatDetailsPresenter( + view, navigator, strategy, serverInteractor, factory + ) + } + + @Test + fun `naviagate to video conference`() { + chatDetailsPresenter.toVideoConference(CHAT_ROOM_ID, CHAT_ROOM_TYPE) + verify(navigator).toVideoConference(CHAT_ROOM_ID, CHAT_ROOM_TYPE) + } + + @Test + fun `naviagate to files`() { + chatDetailsPresenter.toFiles(CHAT_ROOM_ID) + verify(navigator).toFileList(CHAT_ROOM_ID) + } + + @Test + fun `naviagate to member`() { + chatDetailsPresenter.toMembers(CHAT_ROOM_ID) + verify(navigator).toMembersList(CHAT_ROOM_ID) + } + + @Test + fun `naviagate to mention`() { + chatDetailsPresenter.toMentions(CHAT_ROOM_ID) + verify(navigator).toMentions(CHAT_ROOM_ID) + } + + @Test + fun `naviagate to pinned`() { + chatDetailsPresenter.toPinned(CHAT_ROOM_ID) + verify(navigator).toPinnedMessageList(CHAT_ROOM_ID) + } + + @Test + fun `naviagate to favorites`() { + chatDetailsPresenter.toFavorites(CHAT_ROOM_ID) + verify(navigator).toFavoriteMessageList(CHAT_ROOM_ID) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenterTest.kt b/app/src/test/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenterTest.kt new file mode 100644 index 0000000000..12e8579f55 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenterTest.kt @@ -0,0 +1,73 @@ +package chat.rocket.android.chatrooms.presentation + +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.db.DatabaseManager +import chat.rocket.android.helper.UserHelper +import chat.rocket.android.infrastructure.LocalRepository +import chat.rocket.android.main.presentation.MainNavigator +import chat.rocket.android.server.domain.SettingsRepository +import chat.rocket.android.server.domain.SortingAndGroupingInteractor +import chat.rocket.android.server.domain.siteName +import chat.rocket.android.server.infrastructure.ConnectionManager +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER + +class ChatRoomsPresenterTest { + + private val view = Mockito.mock(ChatRoomsView::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val navigator = Mockito.mock(MainNavigator::class.java) + private val sortingAndGroupingInteractor = + Mockito.mock(SortingAndGroupingInteractor::class.java) + private val dbManager = Mockito.mock(DatabaseManager::class.java) + private val manager = Mockito.mock(ConnectionManager::class.java) + private val localRepository = Mockito.mock(LocalRepository::class.java) + private val userHelper = Mockito.mock(UserHelper::class.java) + private val settingsRepository = Mockito.mock(SettingsRepository::class.java) + + lateinit var chatRoomsPresenter: ChatRoomsPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + chatRoomsPresenter = ChatRoomsPresenter( + view, strategy, navigator, CURRENT_SERVER, sortingAndGroupingInteractor, dbManager, + manager, localRepository, userHelper, settingsRepository + ) + } + + @Test + fun `navigate to create channel`() { + chatRoomsPresenter.toCreateChannel() + verify(navigator).toCreateChannel() + } + + @Test + fun `navigate to setting`() { + chatRoomsPresenter.toSettings() + verify(navigator).toSettings() + } + + @Test + fun `navigate to directory`() { + chatRoomsPresenter.toDirectory() + verify(navigator).toDirectory() + } + + @Test + fun `get current server name`() { + chatRoomsPresenter.getCurrentServerName() + val settings = CURRENT_SERVER.let { settingsRepository.get(it) } + verify(view).setupToolbar(settings.siteName() ?: CURRENT_SERVER) + } + + @Test + fun `sorting and grouping preferences`() { + chatRoomsPresenter.getSortingAndGroupingPreferences() + verify(view).setupSortingAndGrouping(false, false, false, false) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenterTest.kt b/app/src/test/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenterTest.kt new file mode 100644 index 0000000000..ee9c0b0074 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenterTest.kt @@ -0,0 +1,39 @@ +package chat.rocket.android.createchannel.presentation + +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.main.presentation.MainNavigator +import chat.rocket.android.members.uimodel.MemberUiModelMapper +import chat.rocket.android.server.domain.GetCurrentServerInteractor +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER + +class CreateChannelPresenterTest { + + private val view = mock(CreateChannelView::class.java) + private val strategy = mock(CancelStrategy::class.java) + private val mapper = mock(MemberUiModelMapper::class.java) + private val navigator = mock(MainNavigator::class.java) + private val serverInteractor = mock(GetCurrentServerInteractor::class.java) + private val factory = mock(RocketChatClientFactory::class.java) + + private lateinit var createChannelPresenter: CreateChannelPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + createChannelPresenter = CreateChannelPresenter( + view, strategy, mapper, navigator, serverInteractor, factory + ) + } + + @Test + fun `navigate to chat list`() { + createChannelPresenter.toChatList() + verify(navigator).toChatList() + } +} diff --git a/app/src/test/java/chat/rocket/android/main/presentation/MainPresenterTest.kt b/app/src/test/java/chat/rocket/android/main/presentation/MainPresenterTest.kt new file mode 100644 index 0000000000..753f07bf06 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/main/presentation/MainPresenterTest.kt @@ -0,0 +1,74 @@ +package chat.rocket.android.main.presentation + +import chat.rocket.android.core.behaviours.AppLanguageView +import chat.rocket.android.helper.UserHelper +import chat.rocket.android.push.GroupedPush +import chat.rocket.android.server.domain.* +import chat.rocket.android.server.infrastructure.ConnectionManagerFactory +import junit.framework.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CHAT_ROOM_ID +import testConfig.Config.Companion.CURRENT_SERVER + +class MainPresenterTest { + private val mainNavigator = Mockito.mock(MainNavigator::class.java) + private val appLanguageView = Mockito.mock(AppLanguageView::class.java) + private val refreshSettingsInteractor = Mockito.mock(RefreshSettingsInteractor::class.java) + private val refreshPermissionsInteractor = + Mockito.mock(RefreshPermissionsInteractor::class.java) + private val connectionManagerFactory = Mockito.mock(ConnectionManagerFactory::class.java) + private val getLanguageInteractor = Mockito.mock(GetCurrentLanguageInteractor::class.java) + private val groupedPush = Mockito.mock(GroupedPush::class.java) + private val tokenRepository = Mockito.mock(TokenRepository::class.java) + private val getSettingsInteractor = Mockito.mock(GetSettingsInteractor::class.java) + private val userHelper = Mockito.mock(UserHelper::class.java) + private val saveAccountInteractor = Mockito.mock(SaveAccountInteractor::class.java) + private val removeAccountInteractor = Mockito.mock(RemoveAccountInteractor::class.java) + + lateinit var mainPresenter: MainPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + mainPresenter = MainPresenter( + CURRENT_SERVER, mainNavigator, appLanguageView, refreshSettingsInteractor, + refreshPermissionsInteractor, getSettingsInteractor, connectionManagerFactory, + getLanguageInteractor, groupedPush, tokenRepository, userHelper, saveAccountInteractor, + removeAccountInteractor + ) + } + + @Test + fun connect() { + mainPresenter.connect() + verify(refreshSettingsInteractor).refreshAsync(CURRENT_SERVER) + verify(refreshPermissionsInteractor).refreshAsync(CURRENT_SERVER) + verify(connectionManagerFactory).create(CURRENT_SERVER)?.connect() + } + + @Test + fun `navigate to chatlist`() { + mainPresenter.showChatList(CHAT_ROOM_ID, null) + verify(mainNavigator).toChatList(CHAT_ROOM_ID, null) + } + + @Test + fun `update app language`() { + `when`(getLanguageInteractor.getLanguage()).thenReturn("hi") + `when`(getLanguageInteractor.getCountry()).thenReturn("rIN") + mainPresenter.getAppLanguage() + verify(getLanguageInteractor).getLanguage() + verify(appLanguageView).updateLanguage("hi", "rIN") + } + + @Test + fun `clear chatroom notifications`() { + val result = mainPresenter.clearNotificationsForChatRoom(null) + assertEquals(result, Unit) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/members/presentation/MembersPresenterTest.kt b/app/src/test/java/chat/rocket/android/members/presentation/MembersPresenterTest.kt new file mode 100644 index 0000000000..87719fdde0 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/members/presentation/MembersPresenterTest.kt @@ -0,0 +1,53 @@ +package chat.rocket.android.members.presentation + +import chat.rocket.android.chatroom.presentation.ChatRoomNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.db.DatabaseManager +import chat.rocket.android.helper.UserHelper +import chat.rocket.android.members.uimodel.MemberUiModelMapper +import chat.rocket.android.server.domain.PermissionsInteractor +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import junit.framework.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CHAT_ROOM_ID +import testConfig.Config.Companion.CURRENT_SERVER + +class MembersPresenterTest { + + private val view = Mockito.mock(MembersView::class.java) + private val navigator = Mockito.mock(ChatRoomNavigator::class.java) + private val dbManager = Mockito.mock(DatabaseManager::class.java) + private val permissionsInteractor = Mockito.mock(PermissionsInteractor::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val mapper = Mockito.mock(MemberUiModelMapper::class.java) + private val userHelper = Mockito.mock(UserHelper::class.java) + private val factory = Mockito.mock(RocketChatClientFactory::class.java) + + private lateinit var membersPresenter: MembersPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + Mockito.`when`(strategy.isTest).thenReturn(true) + membersPresenter = MembersPresenter( + view, navigator, dbManager, permissionsInteractor, + CURRENT_SERVER, strategy, mapper, factory, userHelper + ) + } + + @Test + fun `load chat room members`() { + val result = membersPresenter.loadChatRoomsMembers(CHAT_ROOM_ID) + assertEquals(result, Unit) + } + + @Test + fun `navigate to invite user`() { + membersPresenter.toInviteUsers(CHAT_ROOM_ID) + verify(navigator).toInviteUsers(CHAT_ROOM_ID) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/servers/presentation/ServersPresenterTest.kt b/app/src/test/java/chat/rocket/android/servers/presentation/ServersPresenterTest.kt new file mode 100644 index 0000000000..6675858878 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/servers/presentation/ServersPresenterTest.kt @@ -0,0 +1,47 @@ +package chat.rocket.android.servers.presentation + +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.main.presentation.MainNavigator +import chat.rocket.android.server.domain.GetAccountsInteractor +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER + +class ServersPresenterTest { + + private val view = Mockito.mock(ServersView::class.java) + private val navigator = Mockito.mock(MainNavigator::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val getAccountsInteractor = Mockito.mock(GetAccountsInteractor::class.java) + + lateinit var serversPresenter: ServersPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + serversPresenter = ServersPresenter( + view, navigator, strategy, getAccountsInteractor, CURRENT_SERVER + ) + } + + @Test + fun `navigate to server screen if new server is added`() { + serversPresenter.addNewServer() + verify(navigator).toServerScreen() + } + + @Test + fun `hide server view if serverUrl equal curentServer`() { + serversPresenter.changeServer(CURRENT_SERVER) + verify(view).hideServerView() + } + + @Test + fun `switch Or add new server if serverUrl not equal curentServer`() { + serversPresenter.changeServer("") + verify(navigator).switchOrAddNewServer("") + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/settings/presentation/SettingsPresenterTest.kt b/app/src/test/java/chat/rocket/android/settings/presentation/SettingsPresenterTest.kt new file mode 100644 index 0000000000..fe2732950b --- /dev/null +++ b/app/src/test/java/chat/rocket/android/settings/presentation/SettingsPresenterTest.kt @@ -0,0 +1,107 @@ +package chat.rocket.android.settings.presentation + +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.db.DatabaseManagerFactory +import chat.rocket.android.dynamiclinks.DynamicLinksForFirebase +import chat.rocket.android.helper.UserHelper +import chat.rocket.android.main.presentation.MainNavigator +import chat.rocket.android.server.domain.* +import chat.rocket.android.server.infrastructure.ConnectionManagerFactory +import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.ADMIN_PANEL_URL +import testConfig.Config.Companion.CURRENT_SERVER +import testConfig.Config.Companion.LICENSE +import testConfig.Config.Companion.LICENSE_URL + +class SettingsPresenterTest { + + private val view = Mockito.mock(SettingsView::class.java) + private val strategy = Mockito.mock(CancelStrategy::class.java) + private val navigator = Mockito.mock(MainNavigator::class.java) + private val userHelper = Mockito.mock(UserHelper::class.java) + private val analyticsTrackingInteractor = Mockito.mock(AnalyticsTrackingInteractor::class.java) + private val tokenRepository = Mockito.mock(TokenRepository::class.java) + private val permissions = Mockito.mock(PermissionsInteractor::class.java) + private val rocketChatClientFactory = Mockito.mock(RocketChatClientFactory::class.java) + private val dynamicLinksManager = Mockito.mock(DynamicLinksForFirebase::class.java) + private val saveLanguageInteractor = Mockito.mock(SaveCurrentLanguageInteractor::class.java) + private val getCurrentServerInteractor = Mockito.mock(GetCurrentServerInteractor::class.java) + private val removeAccountInteractor = Mockito.mock(RemoveAccountInteractor::class.java) + private val databaseManagerFactory = Mockito.mock(DatabaseManagerFactory::class.java) + private val connectionManagerFactory = Mockito.mock(ConnectionManagerFactory::class.java) + private val serverInteractor = Mockito.mock(GetConnectingServerInteractor::class.java) + lateinit var settingsPresenter: SettingsPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + Mockito.`when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + Mockito.`when`(strategy.isTest).thenReturn(true) + settingsPresenter = SettingsPresenter( + view, strategy, navigator, CURRENT_SERVER, userHelper, analyticsTrackingInteractor, + tokenRepository, permissions, rocketChatClientFactory, dynamicLinksManager, saveLanguageInteractor, + getCurrentServerInteractor, removeAccountInteractor, databaseManagerFactory, connectionManagerFactory + ) + } + + @Test + fun setupView() { + val result = settingsPresenter.setupView() + assertEquals(result, Unit) + } + + @Test + fun TrackingShouldBeEnable() { + settingsPresenter.enableAnalyticsTracking(true) + verify(analyticsTrackingInteractor).save(true) + } + + @Test + fun TrackingShouldBeDisable() { + settingsPresenter.enableAnalyticsTracking(false) + verify(analyticsTrackingInteractor).save(false) + } + + @Test + fun saveLocaleWithCountry() { + settingsPresenter.saveLocale("hi", "rIN") + verify(saveLanguageInteractor).save("hi", "rIN") + } + + @Test + fun saveLocaleWithNoCountry() { + settingsPresenter.saveLocale("hi", null) + verify(saveLanguageInteractor).save("hi", null) + } + + @Test + fun navigateToProfile() { + settingsPresenter.toProfile() + verify(navigator).toProfile() + } + + @Test + fun navigateToAdmin() { + settingsPresenter.toAdmin() + val a = tokenRepository.get(CURRENT_SERVER) + a?.authToken?.let { verify(navigator).toAdminPanel(ADMIN_PANEL_URL, it) } + } + + @Test + fun navigateToLicense() { + settingsPresenter.toLicense(LICENSE_URL, LICENSE) + verify(navigator).toLicense(LICENSE_URL, LICENSE) + } + + @Test + fun activityShouldBeRecreated() { + settingsPresenter.recreateActivity() + verify(navigator).recreateActivity() + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingPresenterTest.kt b/app/src/test/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingPresenterTest.kt new file mode 100644 index 0000000000..386ce36869 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingPresenterTest.kt @@ -0,0 +1,43 @@ +package chat.rocket.android.sortingandgrouping.presentation + +import chat.rocket.android.server.domain.SortingAndGroupingInteractor +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.CURRENT_SERVER + +class SortingAndGroupingPresenterTest { + + private val view = Mockito.mock(SortingAndGroupingView::class.java) + private val sortingAndGroupingInteractor = + Mockito.mock(SortingAndGroupingInteractor::class.java) + + lateinit var sortingAndGroupingPresenter: SortingAndGroupingPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + sortingAndGroupingPresenter = SortingAndGroupingPresenter( + view, sortingAndGroupingInteractor, CURRENT_SERVER + ) + } + + @Test + fun `get sorting and grouping preferences`() { + sortingAndGroupingPresenter.getSortingAndGroupingPreferences() + verify(view).showSortingAndGroupingPreferences( + sortingAndGroupingInteractor.getSortByName(CURRENT_SERVER), + sortingAndGroupingInteractor.getUnreadOnTop(CURRENT_SERVER), + sortingAndGroupingInteractor.getGroupByType(CURRENT_SERVER), + sortingAndGroupingInteractor.getGroupByFavorites(CURRENT_SERVER) + ) + } + + @Test + fun `save sorting and grouping preferences`() { + sortingAndGroupingPresenter.saveSortingAndGroupingPreferences(true, false, false, false) + verify(sortingAndGroupingInteractor).save(CURRENT_SERVER, true, false, false, false) + } +} \ No newline at end of file diff --git a/app/src/test/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenterTest.kt b/app/src/test/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenterTest.kt new file mode 100644 index 0000000000..3e0200cb12 --- /dev/null +++ b/app/src/test/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenterTest.kt @@ -0,0 +1,49 @@ +package chat.rocket.android.userdetails.presentation + +import chat.rocket.android.chatroom.presentation.ChatRoomNavigator +import chat.rocket.android.core.lifecycle.CancelStrategy +import chat.rocket.android.db.DatabaseManager +import chat.rocket.android.server.domain.CurrentServerRepository +import chat.rocket.android.server.domain.GetSettingsInteractor +import chat.rocket.android.server.domain.PermissionsInteractor +import chat.rocket.android.server.domain.TokenRepository +import chat.rocket.android.server.infrastructure.ConnectionManagerFactory +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import testConfig.Config.Companion.AVATAR_URL +import testConfig.Config.Companion.CURRENT_SERVER + +class UserDetailsPresenterTest { + + val view = mock(UserDetailsView::class.java) + val dbManager = mock(DatabaseManager::class.java) + val strategy = mock(CancelStrategy::class.java) + val navigator = mock(ChatRoomNavigator::class.java) + val permissionsInteractor = mock(PermissionsInteractor::class.java) + val tokenRepository = mock(TokenRepository::class.java) + val settingsInteractor = mock(GetSettingsInteractor::class.java) + val serverInteractor = mock(CurrentServerRepository::class.java) + val factory = mock(ConnectionManagerFactory::class.java) + + lateinit var userDetailsPresenter: UserDetailsPresenter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + Mockito.`when`(serverInteractor.get()).thenReturn(CURRENT_SERVER) + userDetailsPresenter = UserDetailsPresenter( + view, dbManager, strategy, navigator, permissionsInteractor, + tokenRepository, settingsInteractor, serverInteractor, factory + ) + } + + @Test + fun `navigate to profile image`() { + userDetailsPresenter.toProfileImage(AVATAR_URL) + verify(navigator).toProfileImage(AVATAR_URL) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index c144baa2e3..c5846ae085 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,9 @@ buildscript { classpath 'com.google.gms:google-services:4.3.0' classpath 'io.fabric.tools:gradle:1.29.0' classpath "com.github.ben-manes:gradle-versions-plugin:0.20.0" + classpath ('com.dicedmelon.gradle:jacoco-android:0.1.4'){ + exclude group: 'org.codehaus.groovy', module: 'groovy-all' + } } } diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..c932216606 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,20 @@ +codecov: + branch: authentication_tests + notify: + require_ci_to_pass: no + +coverage: + precision: 2 + round: down + range: 40...100 + + status: + project: + enabled: yes + threshold: 0.5% + patch: no + changes: no + +comment: + layout: "header, diff, changes" + behavior: default diff --git a/core/src/main/java/chat/rocket/android/core/lifecycle/CancelStrategy.kt b/core/src/main/java/chat/rocket/android/core/lifecycle/CancelStrategy.kt index 2f016a1b61..2f9545095a 100644 --- a/core/src/main/java/chat/rocket/android/core/lifecycle/CancelStrategy.kt +++ b/core/src/main/java/chat/rocket/android/core/lifecycle/CancelStrategy.kt @@ -8,6 +8,8 @@ import kotlinx.coroutines.Job class CancelStrategy(owner: LifecycleOwner, val jobs: Job) : LifecycleObserver { + var isTest: Boolean = false + init { owner.lifecycle.addObserver(this) } diff --git a/dependencies.gradle b/dependencies.gradle index 3f4752e38a..4a2d8e1e43 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -67,7 +67,10 @@ ext { junit : '4.12', truth : '0.42', espresso : '3.1.0-alpha4', - mockito : '2.21.0' + mockito : '3.0.0', + roboelectric : '1.0.0', + runner : '1.1.0', + uiAutomator : '2.2.0' ] libraries = [ kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}", @@ -144,7 +147,13 @@ ext { junit : "junit:junit:${versions.junit}", espressoCore : "androidx.test.espresso:espresso-core:${versions.espresso}", espressoIntents : "androidx.test.espresso:espresso-intents:${versions.espresso}", + espressoContrib : "androidx.test.espresso:espresso-contrib:${versions.espresso}", roomTest : "android.arch.persistence.room:testing:${versions.room}", - truth : "com.google.truth:truth:${versions.truth}" + truth : "com.google.truth:truth:${versions.truth}", + mockito : "org.mockito:mockito-core:${versions.mockito}", + mockitoAndroid : "org.mockito:mockito-android:${versions.mockito}", + mockitoInline : "org.mockito:mockito-inline:${versions.mockito}", + runner : "androidx.test:runner:${versions.runner}", + uiAutomator : "androidx.test.uiautomator:uiautomator:${versions.uiAutomator}" ] } diff --git a/util/src/main/java/chat/rocket/android/util/extension/Coroutines.kt b/util/src/main/java/chat/rocket/android/util/extension/Coroutines.kt index fbe47eb441..f2b85d179f 100644 --- a/util/src/main/java/chat/rocket/android/util/extension/Coroutines.kt +++ b/util/src/main/java/chat/rocket/android/util/extension/Coroutines.kt @@ -2,6 +2,7 @@ package chat.rocket.android.util.extension import chat.rocket.android.core.lifecycle.CancelStrategy import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers.Default import kotlinx.coroutines.Job import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch @@ -11,5 +12,10 @@ import kotlinx.coroutines.launch * * @param strategy a CancelStrategy for canceling the coroutine job */ -fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job = - MainScope().launch(context = strategy.jobs, block = block) +fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job { + return if (strategy.isTest) { + CoroutineScope(Default).launch(Default, block = block) + } else { + MainScope().launch(context = strategy.jobs, block = block) + } +}