From a25664b46581aa5581291450a83ff986151f8618 Mon Sep 17 00:00:00 2001 From: Syed Ahmed Jamil - Local Date: Thu, 8 Feb 2024 17:32:33 +0500 Subject: [PATCH] dev - added android test orchestrator release note - updated build version to 1.4.1 release note - updated view id names release note - fixed crash when push notification received with missing fields release note - added view notification acceptance tests --- .github/workflows/dev-push.yml | 147 +++++++++++++++--- .github/workflows/main-push.yml | 4 +- README.md | 8 +- app/build.gradle.kts | 14 +- .../features/view_notifications.feature | 13 ++ .../pushernotif/test/acceptance/Steps.kt | 52 +++++-- .../pushernotif/test/dsl/CucumberDsl.kt | 9 ++ .../test/{util => }/dsl/InstanceScreenDsl.kt | 0 .../test/dsl/NotificationScreenDsl.kt | 24 +++ .../driver/InstanceScreenDriver.kt | 0 .../dsl/driver/NotificationScreenDriver.kt | 33 ++++ .../test/dsl/pages/InstanceScreen.kt | 50 ++++++ .../test/dsl/pages/NotificationScreen.kt | 35 +++++ .../pushernotif/test/dsl/pages/System.kt | 52 +++++++ .../pushernotif/test/dsl/pages/Ui.kt | 21 +++ .../test/integration/AppContainerTest.kt | 2 +- .../pushernotif/test/util/dsl/CucumberDsl.kt | 5 - .../framework/MyPusherMessagingService.kt | 27 +++- .../ui/notification/NotificationFragment.kt | 10 +- .../notification/NotificationListAdapter.kt | 2 +- .../main/res/layout/fragment_notification.xml | 13 +- .../res/layout/notification_list_item.xml | 16 +- .../pushernotif/NotificationViewModelTest.kt | 2 +- 23 files changed, 453 insertions(+), 86 deletions(-) create mode 100644 app/src/androidTest/assets/features/view_notifications.feature create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/CucumberDsl.kt rename app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/{util => }/dsl/InstanceScreenDsl.kt (100%) create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/NotificationScreenDsl.kt rename app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/{util => dsl}/driver/InstanceScreenDriver.kt (100%) create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/driver/NotificationScreenDriver.kt create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/InstanceScreen.kt create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/NotificationScreen.kt create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/System.kt create mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/Ui.kt delete mode 100644 app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/dsl/CucumberDsl.kt diff --git a/.github/workflows/dev-push.yml b/.github/workflows/dev-push.yml index 056d47e..79047b5 100644 --- a/.github/workflows/dev-push.yml +++ b/.github/workflows/dev-push.yml @@ -16,12 +16,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - name: Setup JDK And Gradle uses: ./.github/actions/setup-jdk-gradle @@ -37,11 +31,21 @@ jobs: - name: Run Unit Test run: ./gradlew test + - name: Assemble Debug + run: ./gradlew assembleDebug + + - name: Upload Debug Apk + uses: actions/upload-artifact@v4 + with: + name: debug-apk + path: app/build/outputs/apk/debug/*.apk + - name: Upload Unit Test Report + if: always() uses: actions/upload-artifact@v3 with: name: unit-test-report - path: build/reports/unitTests + path: build/reports/unitTests integration-test: needs: [unit-test] @@ -70,13 +74,16 @@ jobs: - name: Run Integration Test uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 29 + api-level: 30 + target: google_apis + arch: x86_64 force-avd-creation: false emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: true - script: ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.cucumberUseAndroidJUnitRunner=true mergeAndroidReports + script: ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.cucumberUseAndroidJUnitRunner=true mergeAndroidReports --continue - name: Upload Integration Test Report + if: always() uses: actions/upload-artifact@v3 with: name: integration-test-report @@ -109,47 +116,139 @@ jobs: - name: Run Acceptance Test uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 29 + api-level: 30 + target: google_apis + arch: x86_64 force-avd-creation: false emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: true - script: ./gradlew connectedAndroidTest mergeAndroidReports + script: ./gradlew connectedAndroidTest mergeAndroidReports --continue - name: Upload Acceptance Test Report + if: always() uses: actions/upload-artifact@v3 with: name: acceptance-test-report path: build/androidTest-results - assemble-debug: - needs: [unit-test, integration-test, acceptance-test] + appium-tests: + needs: [unit-test] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 + with: + ref: appium-tests + + - name: Remove all apk in apps folder + run: rm -rf apps/* + + - name: Display structure of downloaded files + run: ls -la apps + + - name: Get Debug App That Was Uploaded In Unit-Test Stage + uses: actions/download-artifact@v4 + with: + name: debug-apk + path: apps + + - name: Copy And Rename APK + run: cp ./apps/[PusherNotif]* ./apps/PusherNotif.apk + + - name: Display structure of downloaded files + run: ls -la apps - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm + + - name: Setup JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + cache-read-only: true + + - name: Grant Execute Permission For Gradlew + run: chmod +x gradlew + shell: bash + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Setup And Run Appium + run: | + npm install -g appium@v2.4.1 + appium -v + appium driver install uiautomator2 + appium & + + - name: Grant Execute Permission For Fcm + run: chmod +x fcm + shell: bash + + - name: check + run: | + echo ~ + pwd + ls -la + shell: bash + + - name: Run Test + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 30 + target: google_apis + arch: x86_64 + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: | + adb root + ./gradlew test + + - name: Upload Report + if: always() + uses: actions/upload-artifact@v3 + with: + name: appium-test-report + path: build/reports + + upload-debug-firebase-app-distribution: + needs: [unit-test, integration-test, acceptance-test, appium-tests] + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 - name: Setup JDK And Gradle uses: ./.github/actions/setup-jdk-gradle with: - cache-read-only: false - + cache-read-only: false + - name: Get Google Services Json env: CERTIFICATE_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON }} run: | echo $CERTIFICATE_BASE64 | base64 --decode > app/google-services.json - - - name: Assemble Debug Apk - run: ./gradlew assembleDebug - - - name: Upload Debug Apk - uses: actions/upload-artifact@v3 - with: - name: debug-apk - path: app/build/outputs/apk/debug/*.apk \ No newline at end of file + + - name: Get Firebase App Distribution Key + env: + CERTIFICATE_BASE64: ${{ secrets.FIREBASE_APP_DISTRIBUTION_KEY }} + run: | + echo $CERTIFICATE_BASE64 | base64 --decode > app/main-firebase-app-distribution-admin-key.json + + - name: Assemble Debug + run: ./gradlew assembleDebug -PversionCode=${{ github.run_number }} + + - name: Upload To Firebase App Distribution + run: ./gradlew appDistributionUploadDebug \ No newline at end of file diff --git a/.github/workflows/main-push.yml b/.github/workflows/main-push.yml index e34653c..80faf5f 100644 --- a/.github/workflows/main-push.yml +++ b/.github/workflows/main-push.yml @@ -10,8 +10,8 @@ on: workflow_dispatch: jobs: - upload: - runs-on: macos-latest + upload-signed-release-firebase-app-distribution: + runs-on: ubuntu-latest steps: - name: Checkout diff --git a/README.md b/README.md index 70e6f0e..268c5c6 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # About -Android client app that integrates with pusher beams to show realtime in-app notifications. +Android client app that integrates with pusher beams to show realtime push notifications. Project contains: -- Code structured using `Clean Architecture` -- Acceptance tests written using `Cucumber` `Espresso` +- Code structured using `Clean Architecture` and `MVVM` +- Acceptance tests written using `Cucumber` `Espresso` `UiAutomator2` `Appium` - Integreation and unit tests written using `JUnit` - Continous Integration using `Github Actions` +- App Distribution using `Firebase App Distribution` +- Notifications stored locally using `DataStore` - Dependecy Injection using `Hilt` - Manual Dependecy Injection using custom `App Container` - Testing using fakes and mocks using `Mockk` diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 10d1d04..1968870 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,11 +24,12 @@ android { minSdk = 24 targetSdk = 33 versionCode = project.property("versionCode").toString().toInt() - versionName = "1.4.0" + versionName = "1.4.1" testApplicationId = "com.github.syedahmedjamil.pushernotif.test" // testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" // testInstrumentationRunner = "io.cucumber.android.runner.CucumberAndroidJUnitRunner" testInstrumentationRunner = "com.github.syedahmedjamil.pushernotif.test.CustomRunner" + testInstrumentationRunnerArguments["clearPackageData"] = "true" //apk file name setProperty("archivesBaseName", "${rootProject.name}-${versionName}-${versionCode}") } @@ -51,6 +52,13 @@ android { isDebuggable = true applicationIdSuffix = ".${suffix}" versionNameSuffix = "-${suffix}" + + firebaseAppDistribution { + serviceCredentialsFile = keystoreProperties["serviceCredentialsFile"] as String + artifactType = "APK" + releaseNotesFile = keystoreProperties["releaseNotesFile"] as String + testersFile = keystoreProperties["testersFile"] as String + } } release { val suffix = "release" @@ -99,6 +107,7 @@ android { useLegacyPackaging = true } } + execution = "ANDROIDX_TEST_ORCHESTRATOR" } kapt { @@ -164,6 +173,9 @@ android { androidTestImplementation("io.cucumber:cucumber-android-hilt:7.14.0") androidTestImplementation("io.mockk:mockk-android:1.13.9") androidTestImplementation("androidx.fragment:fragment-testing:1.6.2") // for DataBindingIdlingResource + androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0") + androidTestImplementation("androidx.test:runner:1.5.2") + androidTestUtil("androidx.test:orchestrator:1.4.2") } } diff --git a/app/src/androidTest/assets/features/view_notifications.feature b/app/src/androidTest/assets/features/view_notifications.feature new file mode 100644 index 0000000..cf7d4ac --- /dev/null +++ b/app/src/androidTest/assets/features/view_notifications.feature @@ -0,0 +1,13 @@ +Feature: View Notification + User can view notification for the subscribed interest + + Background: + Given I am subscribed to instance + + Scenario: User views notification from notification screen + When I receive push notification + Then I should see notification in the list + + Scenario: User views notification from status bar + When I receive push notification + Then I should see notification in status bar \ No newline at end of file diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/acceptance/Steps.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/acceptance/Steps.kt index 730eb95..27201fc 100644 --- a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/acceptance/Steps.kt +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/acceptance/Steps.kt @@ -3,7 +3,6 @@ package com.github.syedahmedjamil.pushernotif.test.acceptance import android.content.Intent import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences -import androidx.datastore.preferences.core.edit import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.IdlingRegistry import com.github.syedahmedjamil.pushernotif.test.ActivityScenarioHolder @@ -19,7 +18,6 @@ import io.cucumber.java.en.And import io.cucumber.java.en.Given import io.cucumber.java.en.Then import io.cucumber.java.en.When -import kotlinx.coroutines.runBlocking import javax.inject.Inject @HiltAndroidTest @@ -32,7 +30,6 @@ class Steps( @Inject lateinit var dataStore: DataStore - private val dataBindingIdlingResource = DataBindingIdlingResource() @Before @@ -52,58 +49,79 @@ class Steps( fun tearDown() { IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource) IdlingRegistry.getInstance().unregister(dataBindingIdlingResource) - runBlocking { - dataStore.edit { - it.clear() - } - } +// runBlocking { +// dataStore.edit { +// it.clear() +// } +// } } @Given("I am on the {string} screen") fun iAmOnThePage(arg0: String) { - dsl.instance.assertScreenTitle(arg0) + dsl.ui.assertScreenTitle(arg0) } @When("I add {string} as an interest") fun iAddAsAnInterest(arg0: String) { - dsl.instance.addInterest(arg0) + dsl.ui.instance.addInterest(arg0) } @Then("I should see {string} as an interest") fun iShouldSeeAsAnInterest(arg0: String) { - dsl.instance.assertInterestListed(arg0) + dsl.ui.instance.assertInterestListed(arg0) } @Then("I should see message {string}") fun iShouldSeeMessage(arg0: String) { - dsl.instance.assertMessage(arg0) + dsl.ui.assertSnackBarMessage(arg0) } @When("I remove {string} as an interest") fun iRemoveAsAnInterest(arg0: String) { - dsl.instance.removeInterest(arg0) + dsl.ui.instance.removeInterest(arg0) } @And("I should not see {string} as an interest") fun iShouldNotSeeAsAnInterest(arg0: String) { - dsl.instance.assertInterestNotListed(arg0) + dsl.ui.instance.assertInterestNotListed(arg0) } @Given("I set {string} as instance id") fun iSetAsInstanceId(arg0: String) { - dsl.instance.setInstanceId(arg0) + dsl.ui.instance.setInstanceId(arg0) } @When("I try to subscribe") fun iTryToSubscribe() { - dsl.instance.subscribe() + dsl.ui.instance.subscribe() } @Given("Internet connection is turned {string}") fun internetConnectionIsTurned(arg0: String) { - dsl.instance.setInternetConnection(arg0) + dsl.system.setInternetConnection(arg0) + } + + @When("I receive push notification") + fun iReceivePushNotification() { + dsl.system.sendPushNotification() + } + + @Then("I should see notification in the list") + fun iShouldSeeNotificationInTheList() { + dsl.ui.notification.assertNotificationListed() + } + + @Given("I am subscribed to instance") + fun iAmSubscribedToInstance() { + dsl.ui.instance.setInstanceId("00000000-0000-0000-0000-000000000000") + dsl.ui.instance.addInterest("test") + dsl.ui.instance.subscribe() } + @Then("I should see notification in status bar") + fun iShouldSeeNotificationInStatusBar() { + dsl.system.assertNotificationListed(); + } } \ No newline at end of file diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/CucumberDsl.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/CucumberDsl.kt new file mode 100644 index 0000000..93e4f7b --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/CucumberDsl.kt @@ -0,0 +1,9 @@ +package com.github.syedahmedjamil.pushernotif.test.dsl + +import com.github.syedahmedjamil.pushernotif.test.dsl.pages.System +import com.github.syedahmedjamil.pushernotif.test.dsl.pages.Ui + +class CucumberDsl { + val ui = Ui() + val system = System() +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/dsl/InstanceScreenDsl.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/InstanceScreenDsl.kt similarity index 100% rename from app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/dsl/InstanceScreenDsl.kt rename to app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/InstanceScreenDsl.kt diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/NotificationScreenDsl.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/NotificationScreenDsl.kt new file mode 100644 index 0000000..8c94f96 --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/NotificationScreenDsl.kt @@ -0,0 +1,24 @@ +package com.github.syedahmedjamil.pushernotif.test.dsl + +import com.github.syedahmedjamil.pushernotif.test.driver.NotificationScreenDriver + +class NotificationScreenDsl { + private val driver = NotificationScreenDriver() + + fun assertNotificationListed() { + driver.assertNotificationListed() + } + + fun assertInstanceIdName() { + driver.assertInstanceIdName() + + } + + fun removeAllNotifications() { + driver.removeAllNotifications() + } + + fun selectInterest() { + driver.selectInterest() + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/driver/InstanceScreenDriver.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/driver/InstanceScreenDriver.kt similarity index 100% rename from app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/driver/InstanceScreenDriver.kt rename to app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/driver/InstanceScreenDriver.kt diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/driver/NotificationScreenDriver.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/driver/NotificationScreenDriver.kt new file mode 100644 index 0000000..e78eabc --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/driver/NotificationScreenDriver.kt @@ -0,0 +1,33 @@ +package com.github.syedahmedjamil.pushernotif.test.driver + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import com.github.syedahmedjamil.pushernotif.R + +// Instead of Thread.sleep() use UiDevice.wait() and IdlingResource for navigation and databinding + +class NotificationScreenDriver { + fun assertNotificationListed() { + onView(withId(R.id.notification_list_view)).check(matches(ViewMatchers.hasChildCount(1))) + onView(withId(R.id.notification_title)).check(matches(withText("test_title"))) + onView(withId(R.id.notification_date)).check(matches(withText("test_date"))) + onView(withId(R.id.notification_subtext)).check(matches(withText("test_subtext"))) + onView(withId(R.id.notification_icon)).check(matches(ViewMatchers.isDisplayed())) + } + + fun assertInstanceIdName() { + + } + + fun removeAllNotifications() { + + } + + fun selectInterest() { + + } +} + diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/InstanceScreen.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/InstanceScreen.kt new file mode 100644 index 0000000..e9f9541 --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/InstanceScreen.kt @@ -0,0 +1,50 @@ +package com.github.syedahmedjamil.pushernotif.test.dsl.pages + +import androidx.test.espresso.Espresso.onData +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import com.github.syedahmedjamil.pushernotif.R +import org.hamcrest.Matchers.allOf +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.instanceOf +import org.hamcrest.Matchers.`is` +import org.hamcrest.Matchers.not + +// Instead of Thread.sleep() use UiDevice.wait() and IdlingResource for navigation and databinding + +class InstanceScreen { + + fun addInterest(arg0: String) { + onView(withId(R.id.instance_interest_edit_text)).perform(replaceText(arg0)) + onView(withId(R.id.instance_add_interest_button)).perform(click()) + } + + fun assertInterestListed(arg0: String) { + onView(withId(R.id.instance_interests_list_view)).check(matches(hasDescendant(withText(arg0)))) + } + + fun assertInterestNotListed(arg0: String) { + onView(withId(R.id.instance_interests_list_view)) + .check(matches(not(hasDescendant(withText(arg0))))) + } + + fun removeInterest(arg0: String) { + onData(allOf(`is`(instanceOf(String::class.java)), equalTo(arg0))) + .onChildView(withId(R.id.item_remove_icon)) + .perform(click()) + } + + fun setInstanceId(arg0: String) { + onView(withId(R.id.instance_id_edit_text)).perform(replaceText(arg0)) + } + + fun subscribe() { + onView(withId(R.id.instance_subscribe_button)).perform(click()) + } +} + diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/NotificationScreen.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/NotificationScreen.kt new file mode 100644 index 0000000..e988edf --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/NotificationScreen.kt @@ -0,0 +1,35 @@ +package com.github.syedahmedjamil.pushernotif.test.dsl.pages + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.hasChildCount +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import com.github.syedahmedjamil.pushernotif.R + +// Instead of Thread.sleep() use UiDevice.wait() and IdlingResource for navigation and databinding + +class NotificationScreen { + + fun assertNotificationListed() { + onView(withId(R.id.notification_list_view)).check(matches(hasChildCount(1))) + onView(withId(R.id.notification_title)).check(matches(withText("test_title"))) + onView(withId(R.id.notification_date)).check(matches(withText("test_date"))) + onView(withId(R.id.notification_subtext)).check(matches(withText("test_subtext"))) + onView(withId(R.id.notification_icon)).check(matches(isDisplayed())) + } + + fun assertInstanceIdName() { + + } + + fun removeAllNotifications() { + + } + + fun selectInterest() { + + } +} + diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/System.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/System.kt new file mode 100644 index 0000000..888eefc --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/System.kt @@ -0,0 +1,52 @@ +package com.github.syedahmedjamil.pushernotif.test.dsl.pages + +import android.content.Intent +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector +import org.junit.Assert.assertEquals + +class System { + + fun setInternetConnection(arg0: String) { + val device = InstrumentationRegistry.getInstrumentation().uiAutomation + if (arg0 == "on") + device.executeShellCommand("cmd connectivity airplane-mode disable") + if (arg0 == "off") + device.executeShellCommand("cmd connectivity airplane-mode enable") + + Thread.sleep(10000) + } + + fun assertNotificationListed() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.openNotification() + val appName = device.findObject(UiSelector().resourceId("android:id/app_name_text")).text + val subtext = device.findObject(UiSelector().resourceId("android:id/header_text")).text + val title = device.findObject(UiSelector().resourceId("android:id/title")).text + val body = device.findObject(UiSelector().resourceId("android:id/big_text")).text + assertEquals("Pusher Notif (debug)", appName) + assertEquals("test_subtext", subtext) + assertEquals("test_title", title) + assertEquals("test_body", body) + } + + fun sendPushNotification() { + val intent = Intent().apply { + action = "com.google.android.c2dm.intent.RECEIVE" + putExtra("interest", "test") + putExtra("category", "test") + putExtra("date", "test_date") + putExtra("title", "test_title") + putExtra("body", "test_body") + putExtra("subtext", "test_subtext") + putExtra("link", "https://github.com") + putExtra( + "image", + "https://user-images.githubusercontent.com/20031479/181098478-7a170d22-94f0-43f7-8f69-b9d47873d42f.png" + ) + } + InstrumentationRegistry.getInstrumentation().context.sendBroadcast(intent) + Thread.sleep(5000) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/Ui.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/Ui.kt new file mode 100644 index 0000000..66f3f37 --- /dev/null +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/dsl/pages/Ui.kt @@ -0,0 +1,21 @@ +package com.github.syedahmedjamil.pushernotif.test.dsl.pages + +import androidx.test.espresso.Espresso +import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.matcher.ViewMatchers +import com.github.syedahmedjamil.pushernotif.R + +class Ui { + public val instance = InstanceScreen() + public val notification = NotificationScreen() + + fun assertScreenTitle(arg0: String) { + Espresso.onView(ViewMatchers.withId(R.id.toolbar_title)) + .check(ViewAssertions.matches(ViewMatchers.withText(arg0))) + } + + fun assertSnackBarMessage(arg0: String) { + Espresso.onView(ViewMatchers.withId(com.google.android.material.R.id.snackbar_text)) + .check(ViewAssertions.matches(ViewMatchers.withText(arg0))) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/integration/AppContainerTest.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/integration/AppContainerTest.kt index 3973e2f..af4487a 100644 --- a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/integration/AppContainerTest.kt +++ b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/integration/AppContainerTest.kt @@ -43,4 +43,4 @@ class AppContainerTest { val dep: ImageLoader = appContainer.imageLoader Assert.assertNotNull(dep) } -} \ No newline at end of file +} diff --git a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/dsl/CucumberDsl.kt b/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/dsl/CucumberDsl.kt deleted file mode 100644 index 2835430..0000000 --- a/app/src/androidTest/java/com/github/syedahmedjamil/pushernotif/test/util/dsl/CucumberDsl.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.github.syedahmedjamil.pushernotif.test.dsl - -class CucumberDsl { - val instance = InstanceScreenDsl() -} \ No newline at end of file diff --git a/app/src/main/java/com/github/syedahmedjamil/pushernotif/framework/MyPusherMessagingService.kt b/app/src/main/java/com/github/syedahmedjamil/pushernotif/framework/MyPusherMessagingService.kt index efe7671..405ac97 100644 --- a/app/src/main/java/com/github/syedahmedjamil/pushernotif/framework/MyPusherMessagingService.kt +++ b/app/src/main/java/com/github/syedahmedjamil/pushernotif/framework/MyPusherMessagingService.kt @@ -31,6 +31,14 @@ class MyPusherMessagingService : MessagingService() { private lateinit var addNotificationUseCase: AddNotificationUseCase private lateinit var imageLoader: ImageLoader + private lateinit var title: String + private lateinit var body: String + private lateinit var subText: String + private lateinit var date: String + private lateinit var link: String + private lateinit var image: String + private lateinit var interest: String + override fun onCreate() { appContainer = (applicationContext as BaseApplication).appContainer addNotificationUseCase = appContainer.addNotificationUseCase @@ -38,14 +46,19 @@ class MyPusherMessagingService : MessagingService() { } override fun onMessageReceived(remoteMessage: RemoteMessage) { + try { + title = remoteMessage.data["title"]!! + body = remoteMessage.data["body"]!! + subText = remoteMessage.data["subtext"]!! + date = remoteMessage.data["date"]!! + link = remoteMessage.data["link"]!! + image = remoteMessage.data["image"]!! + interest = remoteMessage.data["interest"]!! + } + catch (e: Exception) { + return + } - val title = remoteMessage.data["title"]!! - val body = remoteMessage.data["body"]!! - val subText = remoteMessage.data["subtext"]!! - val date = remoteMessage.data["date"]!! - val link = remoteMessage.data["link"]!! - val image = remoteMessage.data["image"]!! - val interest = remoteMessage.data["interest"]!! val base64Image = imageLoader.getBase64(image) diff --git a/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationFragment.kt b/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationFragment.kt index f8b3860..157183b 100644 --- a/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationFragment.kt +++ b/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationFragment.kt @@ -73,12 +73,12 @@ class NotificationFragment : Fragment() { private fun setUpTabs() { for (interest in interests) { - binding.tabLayout.addTab( - binding.tabLayout.newTab().setText(interest) + binding.notificationTabLayout.addTab( + binding.notificationTabLayout.newTab().setText(interest) ) } - binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + binding.notificationTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabSelected(tab: TabLayout.Tab?) { loadNotifications() @@ -95,8 +95,8 @@ class NotificationFragment : Fragment() { } private fun loadNotifications() { - val position = binding.tabLayout.selectedTabPosition - val selectedInterest = binding.tabLayout.getTabAt(position)?.text.toString() + val position = binding.notificationTabLayout.selectedTabPosition + val selectedInterest = binding.notificationTabLayout.getTabAt(position)?.text.toString() viewModel.selectInterest(selectedInterest) } diff --git a/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationListAdapter.kt b/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationListAdapter.kt index e83e0f6..e1a3072 100644 --- a/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationListAdapter.kt +++ b/app/src/main/java/com/github/syedahmedjamil/pushernotif/ui/notification/NotificationListAdapter.kt @@ -38,7 +38,7 @@ class NotificationListAdapter( binding.date = item?.date binding.subtext= item?.subText binding.link= item?.link - binding.jobIcon.setImageBitmap(toBitmap(item?.image)) + binding.notificationIcon.setImageBitmap(toBitmap(item?.image)) return binding.root } diff --git a/app/src/main/res/layout/fragment_notification.xml b/app/src/main/res/layout/fragment_notification.xml index f85013e..bbea79e 100644 --- a/app/src/main/res/layout/fragment_notification.xml +++ b/app/src/main/res/layout/fragment_notification.xml @@ -30,17 +30,8 @@ android:layout_height="match_parent" android:orientation="vertical"> - - - - - - - - - diff --git a/app/src/main/res/layout/notification_list_item.xml b/app/src/main/res/layout/notification_list_item.xml index 0f7cfe8..35f5007 100644 --- a/app/src/main/res/layout/notification_list_item.xml +++ b/app/src/main/res/layout/notification_list_item.xml @@ -27,7 +27,7 @@ + app:layout_constraintTop_toBottomOf="@+id/notification_date"/> \ No newline at end of file diff --git a/app/src/test/java/com/github/syedahmedjamil/pushernotif/NotificationViewModelTest.kt b/app/src/test/java/com/github/syedahmedjamil/pushernotif/NotificationViewModelTest.kt index 0c0c442..061b014 100644 --- a/app/src/test/java/com/github/syedahmedjamil/pushernotif/NotificationViewModelTest.kt +++ b/app/src/test/java/com/github/syedahmedjamil/pushernotif/NotificationViewModelTest.kt @@ -128,4 +128,4 @@ class NotificationViewModelTest { // then assertTrue(result is Result.Error) } -} \ No newline at end of file +}