diff --git a/.github/test_pdfs/Testrechnung-RA-1.pdf b/.github/test_pdfs/Testrechnung-RA-1.pdf new file mode 100644 index 0000000000..5c7afbe2ce Binary files /dev/null and b/.github/test_pdfs/Testrechnung-RA-1.pdf differ diff --git a/.github/test_pdfs/sample.pdf b/.github/test_pdfs/sample.pdf new file mode 100644 index 0000000000..607655faec Binary files /dev/null and b/.github/test_pdfs/sample.pdf differ diff --git a/.github/test_pdfs/test-image-no-results.jpg b/.github/test_pdfs/test-image-no-results.jpg new file mode 100644 index 0000000000..2fa033f584 Binary files /dev/null and b/.github/test_pdfs/test-image-no-results.jpg differ diff --git a/.github/test_pdfs/test-pdf-no-results.pdf b/.github/test_pdfs/test-pdf-no-results.pdf new file mode 100644 index 0000000000..67abefa250 Binary files /dev/null and b/.github/test_pdfs/test-pdf-no-results.pdf differ diff --git a/.github/test_pdfs/test_image.jpeg b/.github/test_pdfs/test_image.jpeg new file mode 100644 index 0000000000..c1b624ae93 Binary files /dev/null and b/.github/test_pdfs/test_image.jpeg differ diff --git a/.github/test_pdfs/too-many-pages.pdf b/.github/test_pdfs/too-many-pages.pdf new file mode 100644 index 0000000000..51df9adada Binary files /dev/null and b/.github/test_pdfs/too-many-pages.pdf differ diff --git a/.github/workflows/bank-sdk.check.ui-tests.yml b/.github/workflows/bank-sdk.check.ui-tests.yml new file mode 100644 index 0000000000..8fb482fd13 --- /dev/null +++ b/.github/workflows/bank-sdk.check.ui-tests.yml @@ -0,0 +1,94 @@ +name: Check Bank SDK - UI Tests + +# TODO: Update triggers to execute only on workflow_call (from the release workflow) and via manual triggering +# (UI tests are slow and we should not run them on every push) +on: + push: + paths: + - 'bank-sdk/**' + - 'capture-sdk/**' + - 'bank-api-library/**' + - 'core-api-library/**' + - 'gradle/**' + branches: + - '**' + tags-ignore: + - '**' + pull_request: + types: [opened, edited, reopened] + paths: + - 'bank-sdk/**' + - 'capture-sdk/**' + - 'bank-api-library/**' + - 'core-api-library/**' + - 'gradle/**' + workflow_call: + secrets: + GINI_MOBILE_TEST_CLIENT_SECRET: + required: true + +jobs: + ui-tests: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + cache: 'gradle' + + - name: enable KVM group perms for emulator + 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: avd cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-x86_64-34-${{ github.ref_name }} + + - name: create avd and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 34 + arch: x86_64 + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -no-audio -no-boot-anim -camera-back emulated + disable-animations: true + script: echo "Generated AVD snapshot for caching." + + - name: run example app instrumented tests + timeout-minutes: 20 + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 34 + arch: x86_64 + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back emulated + disable-animations: true + script: > + adb uninstall net.gini.android.bank.sdk.exampleapp.test ; + adb push bank-sdk/example-app/src/androidTest/testDocuments/test_image.jpeg /sdcard/Download ; + adb shell am start -a android.intent.action.VIEW -n com.google.android.apps.photos/.home.HomeActivity -d file:///sdcard/Download/test_image.jpeg ; + adb push bank-sdk/example-app/src/androidTest/testDocuments/Testrechnung-RA-1.pdf /sdcard/Download ; + adb push bank-sdk/example-app/src/androidTest/testDocuments/sample.pdf /sdcard/Download ; + ./gradlew bank-sdk:example-app:connectedDevExampleAppDebugAndroidTest + -PclientId="gini-mobile-test" + -PclientSecret="${{ secrets.GINI_MOBILE_TEST_CLIENT_SECRET }}" + + - name: archive instrumented test results + if: always() + uses: actions/upload-artifact@v3 + with: + name: bank-sdk-example-app-instrumented-test-results + path: bank-sdk/example-app/build/outputs/androidTest-results/connected diff --git a/.github/workflows/bank-sdk.check.yml b/.github/workflows/bank-sdk.check.yml index f43e54d822..46508e8514 100644 --- a/.github/workflows/bank-sdk.check.yml +++ b/.github/workflows/bank-sdk.check.yml @@ -2,16 +2,6 @@ name: Check Bank SDK on: push: - paths: - - 'bank-sdk/**' - - 'capture-sdk/**' - - 'bank-api-library/**' - - 'core-api-library/**' - - 'gradle/**' - branches: - - '**' - tags-ignore: - - '**' pull_request: types: [opened, edited, reopened] paths: @@ -32,10 +22,10 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' @@ -44,9 +34,9 @@ jobs: - name: run unit tests run: ./gradlew bank-sdk:sdk:testDebugUnitTest - - name: archive unit test results + - name: archive unit test results3 if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bank-sdk-unit-test-results path: bank-sdk/sdk/build/reports/tests @@ -67,10 +57,10 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' @@ -121,7 +111,7 @@ jobs: - name: archive instrumented test results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bank-sdk-instrumented-test-results path: bank-sdk/sdk/build/outputs/androidTest-results/connected @@ -133,11 +123,17 @@ jobs: api-level: 33 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 push .github/test_pdfs/password-protected.pdf /sdcard/Download ; + adb push .github/test_pdfs/sample.pdf /sdcard/Download ; + adb push .github/test_pdfs/test_image.jpeg /sdcard/Download ; + adb push .github/test_pdfs/test-image-no-results.jpg /sdcard/Download ; + adb push .github/test_pdfs/test-pdf-no-results.pdf /sdcard/Download ; + adb push .github/test_pdfs/Testrechnung-RA-1.pdf /sdcard/Download ; + adb push .github/test_pdfs/too-many-pages.pdf /sdcard/Download ; adb uninstall net.gini.android.bank.sdk.exampleapp.test ; - ./gradlew bank-sdk:example-app:connectedDevExampleAppDebugAndroidTest + ./gradlew bank-sdk:example-app:connectedDevExampleAppDebugAndroidTest + -PignoreLocalTests="true" -PclientId="gini-mobile-test" -PclientSecret="${{ secrets.GINI_MOBILE_TEST_CLIENT_SECRET }}" diff --git a/.github/workflows/bank-sdk.release.yml b/.github/workflows/bank-sdk.release.yml index 38013e3090..d02aaf1349 100644 --- a/.github/workflows/bank-sdk.release.yml +++ b/.github/workflows/bank-sdk.release.yml @@ -12,9 +12,14 @@ jobs: secrets: GINI_MOBILE_TEST_CLIENT_SECRET: ${{ secrets.GINI_MOBILE_TEST_CLIENT_SECRET }} BANK_SDK_EXAMPLE_APP_KEYSTORE_PASSWORD: ${{ secrets.BANK_SDK_EXAMPLE_APP_KEYSTORE_PASSWORD }} + + check-ui-tests: + uses: ./.github/workflows/bank-sdk.check.ui-tests.yml + secrets: + GINI_MOBILE_TEST_CLIENT_SECRET: ${{ secrets.GINI_MOBILE_TEST_CLIENT_SECRET }} release: - needs: check + needs: [check, check-ui-tests] runs-on: ubuntu-latest steps: - name: checkout diff --git a/bank-sdk/example-app/build.gradle.kts b/bank-sdk/example-app/build.gradle.kts index d687f4e3f7..5a05e04383 100644 --- a/bank-sdk/example-app/build.gradle.kts +++ b/bank-sdk/example-app/build.gradle.kts @@ -72,6 +72,7 @@ android { // Use the test runner with JUnit4 support testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArguments["clearPackageData"] = "true" multiDexEnabled = true } @@ -151,6 +152,28 @@ android { } } +tasks.register("injectTestProperties") { + val propertiesMap = mutableMapOf() + + doFirst { + propertiesMap.clear() + propertiesMap.putAll(readLocalPropertiesToMapSilent(project, + listOf("ignoreLocalTests")) + ) + } + + destinations.put( + file("src/androidTest/assets/test.properties"), + propertiesMap + ) +} + +afterEvaluate { + tasks.filter { it.name.equals("connectedDevExampleAppDebugAndroidTest", ignoreCase = true) }.forEach { + it.dependsOn(tasks.getByName("injectTestProperties")) + } +} + // after upgrading to AGP 8, we need this, otherwise, gradle will complain to use the same jdk version as your machine (17 which is bundled with Android Studio) // https://youtrack.jetbrains.com/issue/KT-55947/Unable-to-set-kapt-jvm-target-version tasks.withType(type = org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask::class) { @@ -189,6 +212,7 @@ dependencies { implementation(libs.hilt.library) implementation(libs.navigation.fragment.ktx) implementation(libs.navigation.ui.ktx) + implementation(libs.androidx.test.junit.ktx) kapt(libs.hilt.compiler) implementation(libs.androidx.lifecycle.runtime.ktx) @@ -196,18 +220,20 @@ dependencies { testImplementation(libs.junit) - androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.truth) - androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.androidx.test.espresso.core) androidTestImplementation(libs.androidx.test.espresso.intents) + androidTestImplementation(libs.androidx.test.runner) + androidTestImplementation(libs.androidx.test.core) + androidTestImplementation(libs.androidx.test.junit) + androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.androidx.test.uiautomator) androidTestImplementation(libs.mockito.core) androidTestImplementation(libs.mockito.android) androidTestImplementation(libs.androidx.multidex) - androidTestImplementation(libs.androidx.test.junit) androidTestUtil(libs.androidx.test.orchestrator) + } // this is needed because of Dagger-Hilt diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/ImageUploader.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/ImageUploader.kt new file mode 100644 index 0000000000..3ed98a1b90 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/ImageUploader.kt @@ -0,0 +1,35 @@ +package net.gini.android.bank.sdk.exampleapp.ui.resources +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector + + +class ImageUploader { + private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + fun uploadImageFromPhotos() { + device.waitForIdle() + val selectPhoto = device.findObject( + UiSelector() + .className("android.widget.ImageView") + .resourceId("com.google.android.providers.media.module:id/icon_thumbnail") + ) + if (selectPhoto != null) { + selectPhoto.click() + } else { + throw Exception("First photo not found") + } + } + + fun clickAddButton() { + val addButton = device.findObject( + UiSelector() + .className("android.widget.Button") + .resourceId("com.google.android.providers.media.module:id/button_add") + ) + if (addButton.exists()) { + addButton.click() + } else { + throw java.lang.Exception("Add button not found") + } + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/PdfUploader.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/PdfUploader.kt new file mode 100644 index 0000000000..446d9dae65 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/PdfUploader.kt @@ -0,0 +1,39 @@ +package net.gini.android.bank.sdk.exampleapp.ui.resources + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiScrollable +import androidx.test.uiautomator.UiSelector + +class PdfUploader { + private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + fun uploadPdfFromFiles(file: String) { + device.waitForIdle() + + // Assuming you’re on the main screen of the Files app, search for the PDF file by name + val fileList = UiScrollable(UiSelector().scrollable(true)) + +// Find the PDF file by name and click on it + val tabTitle = device.findObject(UiSelector().className("android.widget.TextView").text("Recent")) + if (tabTitle.exists()) { +// Interact with hamburger menu + val hamburgerMenu = device.findObject(UiSelector().className("android.widget.ImageButton")) + hamburgerMenu.exists() + hamburgerMenu.click() + +// Click the 'Downloads' option + val downloadsOption = device.findObject(UiSelector() + .className("android.widget.TextView") + .text("Downloads")) + downloadsOption.exists() + downloadsOption.click() + val selectPdfFile = fileList.getChildByText(UiSelector().text(file), file) + selectPdfFile.click() + } + else { +// Select desired pdf file + val selectPdfFile = fileList.getChildByText(UiSelector().text(file), file) + selectPdfFile.click() + } + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/SimpleIdlingResource.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/SimpleIdlingResource.kt new file mode 100644 index 0000000000..72875c4aaf --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/resources/SimpleIdlingResource.kt @@ -0,0 +1,36 @@ +package net.gini.android.bank.sdk.exampleapp.ui.resources +import androidx.test.espresso.IdlingResource + +class SimpleIdlingResource(private val waitTime: Long) : IdlingResource { + + @Volatile + private var isIdleNow = true + private var callback: IdlingResource.ResourceCallback? = null + + override fun getName() = SimpleIdlingResource::class.java.name + + override fun isIdleNow() = isIdleNow + + override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) { + this.callback = callback + } + + fun setIdleState(isIdleNow: Boolean) { + this.isIdleNow = isIdleNow + if (isIdleNow && callback != null) { + callback!!.onTransitionToIdle() + } + } + + fun waitForIdle() { + isIdleNow = false + Thread { + try { + Thread.sleep(waitTime) + } catch (e: InterruptedException) { + e.printStackTrace() + } + setIdleState(true) + }.start() + } +} diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/CaptureScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/CaptureScreen.kt new file mode 100644 index 0000000000..8eed52476d --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/CaptureScreen.kt @@ -0,0 +1,92 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector +import org.hamcrest.Matchers.allOf + +class CaptureScreen { + private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + fun checkScanTextDisplayed(): Boolean { + val scanText = device.findObject( + UiSelector() + .className("android.widget.TextView") + .text("Scan") + .index(1) + ) + return scanText.waitForExists(5000) + } + + fun assertCameraTitle(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_camera_title)).check(matches(withText(net.gini.android.capture.R.string.gc_camera_info_label_only_invoice))) + return this + } + + fun clickCameraButton(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_button_camera_trigger)).perform(click()) + return this + } + + fun clickHelpButton(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_action_show_onboarding)).perform(click()) + return this + } + + fun clickCancelButton(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_navigation_bar)).perform(click()) + return this + } + + fun assertFlashIconIsDisplayed(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_camera_flash_button_subtitle)).check( + matches( + isDisplayed() + ) + ) + return this + } + + fun assertFlashIconIsOn(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_camera_flash_button_subtitle)).check( + matches( + withText(net.gini.android.capture.R.string.gc_camera_flash_on_subtitle) + ) + ) + return this + } + + fun assertFlashIconIsOff(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_camera_flash_button_subtitle)).check( + matches( + withText(net.gini.android.capture.R.string.gc_camera_flash_off_subtitle) + ) + ) + return this + } + + fun clickFilesButton(): CaptureScreen { + onView(withId(net.gini.android.capture.R.id.gc_button_import_document)).perform(click()) + return this + } + + fun clickPhotos(): CaptureScreen { + onView( + allOf(withId(net.gini.android.capture.R.id.gc_app_label), withText("Photos"))) + .perform(click()) + return this + } + + fun clickFiles(): CaptureScreen { + onView( + allOf(withId(net.gini.android.capture.R.id.gc_app_label), withText("Files"))) + .perform(click()) + return this + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ConfigurationScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ConfigurationScreen.kt new file mode 100644 index 0000000000..a5a6b17a3c --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ConfigurationScreen.kt @@ -0,0 +1,44 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.scrollTo +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.withText +import net.gini.android.bank.sdk.exampleapp.R + +class ConfigurationScreen { + + fun scrollToAnalysisText(): ConfigurationScreen { + onView(withText("Analysis")) + .perform(scrollTo()) + return this + } + + fun clickFlashToggleToEnable() { + onView(ViewMatchers.withId(R.id.switch_flashOnByDefault)).perform( + closeSoftKeyboard(), + click() + ) + } + + fun assertFlashToggleIsDisable(): ConfigurationScreen { + onView(ViewMatchers.withId(R.id.switch_flashOnByDefault)).check(matches(isDisplayed())) + return this + } + + fun scrollToUICustomizationText(): ConfigurationScreen { + onView(withText("UI customization")) + .perform(scrollTo()) + return this + } + + fun clickReturnReasonsDialogToEnable(): ConfigurationScreen { + onView(ViewMatchers.withId(R.id.switch_returnReasonsDialog)).perform(click() + ) + return this + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/DigitalInvoiceEditButton.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/DigitalInvoiceEditButton.kt new file mode 100644 index 0000000000..c88f285470 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/DigitalInvoiceEditButton.kt @@ -0,0 +1,167 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.clearText +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.uiautomator.UiCollection +import androidx.test.uiautomator.UiSelector +import org.hamcrest.Matchers.allOf + +class DigitalInvoiceEditButton { + + fun checkEditButtonTitleIsDisplayed() :Boolean { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + val editButton = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView") + .text("Edit") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gbs_edit_button"), 0) + return editButton.isEnabled + } + + fun clickEditButtonOnDigitalInvoiceScreen() { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + val editButton = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView") + .text("Edit") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gbs_edit_button"), 0) + if(editButton.exists() && editButton.isEnabled) { + editButton.click() + } + } + + fun checkElementTitleIsDisplayed(resourceId: Int): Boolean { + var isElementTitleDisplayed = false + onView(withText(resourceId)) + .check { view, _ -> + if (view.isShown()) { + isElementTitleDisplayed = true + } + } + return isElementTitleDisplayed + } + + fun editElementTextOnArticleBottomSheet(resourceId: Int, text: String) { + onView((withId(resourceId))).perform(click()).perform(replaceText(text)) + } + + fun removeTextFromElementOnArticleBottomSheet(resourceId: Int) { + onView((withId(resourceId))).perform(click()).perform(clearText()) + } + + fun verifyInlineErrorOnElement(resourceId: Int, inlineError: String): Boolean { + var isInlineErrorDisplayed = false + onView(allOf(withId(resourceId), + withText(inlineError))) + .check { view, _ -> + if (view.isShown()) { + isInlineErrorDisplayed = true + } + } + return isInlineErrorDisplayed + } + + fun clickSaveButtonOnEditArticleBottomSheet() { + onView(withText(net.gini.android.bank.sdk.R.string.gbs_digital_invoice_line_item_details_save)).perform(click()) + } + + fun clickCancelButtonOnEditArticleBottomSheet() { + onView(withId(net.gini.android.bank.sdk.R.id.gbs_close_bottom_sheet)).perform(click()) + } + + fun saveNameValueOnDigitalInvoiceScreen() { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + val textView = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView") + .resourceId("R.id.gbs_description") + , 0) + if(textView.exists() && textView.isEnabled) { + textView.text + } + } + + fun checkNameIsUpdated(text: String): Boolean { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + val textView = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gbs_description") + , 0) + if (textView.exists()) { + val actualText = textView.text.replace(Regex("\\d+x\\s*"), "") + if (actualText == text) { + return true + } + } + return false + } + + fun checkUnitPriceIsUpdated(text: String): Boolean { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + val textView = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gbs_per_unit") + , 0) + if (textView.exists()) { + val actualText = textView.text + val expectedText = "€$text per unit" + if (actualText == expectedText) { + return true + } + } + return false + } + + fun checkQuantityIsUpdated(text: String): Boolean { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + val textView = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gbs_description") + , 0) + if (textView.exists()) { + val actualText = extractQuantity(textView.text) + if (actualText == text) { + return true + } + } + return false + } + + fun clickPlusToIncreaseQuantity(increaseTimes: Int){ + for (i in 1 until increaseTimes) { + onView(withId(net.gini.android.bank.sdk.R.id.gbs_add_quantity)) + .perform((click())) + } + } + + fun clickMinusToDecreaseQuantity(decreaseTimes: Int){ + for (i in 4 downTo decreaseTimes) { + onView(withId(net.gini.android.bank.sdk.R.id.gbs_remove_quantity)) + .perform((click())) + } + } + + fun checkCurrencyForUnitPrice(): Boolean { + var isCurrencyEuro = false + onView(allOf(withId(net.gini.android.bank.sdk.R.id.gbs_drop_down_selection_value), withText("EUR"))) + .check { view, _ -> + if (view.isShown()) { + isCurrencyEuro = true + } + } + return isCurrencyEuro + } + + private fun extractQuantity(input: String): String? { + val regex = Regex("""^(\d+)x""") + val matchResult = regex.find(input) + return matchResult?.groups?.get(1)?.value + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/DigitalInvoiceScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/DigitalInvoiceScreen.kt new file mode 100644 index 0000000000..adb7c5fa6d --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/DigitalInvoiceScreen.kt @@ -0,0 +1,232 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import android.widget.TextView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.hasChildCount +import androidx.test.espresso.matcher.ViewMatchers.withClassName +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiCollection +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector +import org.hamcrest.Matchers.allOf +import org.hamcrest.Matchers.`is` + + +class DigitalInvoiceScreen { + private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + private var initialValue: String? = null + private var updatedValue: String? = null + + fun checkDigitalInvoiceTitleIsDisplayed(): Boolean { + val uiCollection = + UiCollection(UiSelector().className("android.view.ViewGroup")) + + val digitalInvoiceText = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView").text("Digital invoice"), 0) + + return digitalInvoiceText.isEnabled + } + + fun checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed(): Boolean { + val onboardingScreenText = device.findObject( + UiSelector() + .className("android.widget.TextView") + .text("Digital invoice") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/onboarding_text_1") + ) + return onboardingScreenText.waitForExists(8000) + } + + fun checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed(): Boolean { + val onboardingScreenButton = device.findObject( + UiSelector() + .className("android.widget.Button") + .text("Get Started") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/done_button") + ) + return onboardingScreenButton.waitForExists(10000) + } + + fun clickGetStartedButtonOnOnboardingScreen() { + val onboardingScreenButton = device.findObject( + UiSelector() + .className("android.widget.Button") + .text("Get Started") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/done_button") + ) + if (onboardingScreenButton.waitForExists(5000) && onboardingScreenButton.isClickable) { + onboardingScreenButton.click() + } + } + + fun clickCancelButton() { + val cancelButton = device.findObject( + UiSelector() + .className("android.widget.ImageButton") + .descriptionContains("Close") + ) + if(cancelButton.exists() && cancelButton.isClickable()){ + cancelButton.click() + } + } + + fun assertOtherChargesDisplayed() : Boolean { + var isOtherChargesDisplayed = false + onView(withText(net.gini.android.bank.sdk.R.string.gbs_digital_invoice_addon_other_charges)) + .check { view,_ -> + if (view.isShown()) { + isOtherChargesDisplayed = true + } + } + return isOtherChargesDisplayed + } + + fun clickProceedButton() { + onView(withText(net.gini.android.bank.sdk.R.string.gbs_proceed)).perform(click()) + } + + fun clickArticleSwitch(): DigitalInvoiceScreen { + val articleSwitch = device.findObject( + UiSelector() + .className("android.widget.Switch") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gbs_enable_switch") + .index(1) + ) + if(articleSwitch.exists() && articleSwitch.isClickable){ + articleSwitch.click() + } + return this + } + + fun checkForReturnReasonsList(): Boolean { + var isReturnReasonDisplayed = false + onView(withText(net.gini.android.bank.sdk.R.string.gbs_digital_invoice_return_reason_dialog_title)) + .check { view, _ -> + if (view.isShown()) { + isReturnReasonDisplayed = true + } + } + return isReturnReasonDisplayed + } + + fun returnItemCountOnReturnReasonsList(): Int{ + val uiCollection = + UiCollection(UiSelector().className("android.widget.ListView")) + val itemSize = uiCollection.childCount + onView(withClassName(`is`("android.widget.ListView"))).check(matches(hasChildCount(itemSize))) + return itemSize + } + + fun clickItemOnReturnReasonsList() { + val uiCollection = + UiCollection(UiSelector().className("android.widget.ListView")) + val returnReasonsItems = uiCollection.getChildByInstance( + UiSelector().className("android.widget.TextView"), 0) + returnReasonsItems.click() + } + + fun checkItemIsDisabledFromDigitalScreen(): Boolean { + val returnReasonsItems = device.findObject(UiSelector() + .className("android.view.ViewGroup") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gsb_line_item") + .index(0)) + return !(returnReasonsItems.isEnabled) + } + + fun checkItemIsEnabledFromDigitalScreen(): Boolean { + val returnReasonsItems = device.findObject(UiSelector() + .className("android.view.ViewGroup") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gsb_line_item") + .index(0)) + return returnReasonsItems.isEnabled + } + + fun clickHelpButtonOnDigitalInvoiceScreen() { + val helpButton = device.findObject( + UiSelector() + .className("android.widget.Button") + .descriptionContains("Help") + ) + if(helpButton.exists()){ + helpButton.click() + } + } + + fun verifyHelpTextOnNextScreen(): Boolean { + val helpText = device.findObject( + UiSelector() + .className("android.widget.TextView") + .text("Help") + ) + return helpText.exists() + } + + fun verifyFirstTitleOnHelpScreen(): Boolean { + var isFirstTitleDisplayed = false + onView( + allOf(withId(net.gini.android.bank.sdk.R.id.gbs_help_title), + withText("1. How does a digital invoice work?") + ) + ) + .check { view, _ -> + if (view.isShown()) { + isFirstTitleDisplayed = true + } + } + return isFirstTitleDisplayed + } + + fun checkTotalTitleIsDisplayed(): Boolean { + var isTotalTitleDisplayed = false + onView( + allOf(withId(net.gini.android.bank.sdk.R.id.total_label), + withText("Total") + ) + ) + .check { view, _ -> + if (view.isShown()) { + isTotalTitleDisplayed = true + } + } + return isTotalTitleDisplayed + } + + fun checkTotalPriceIsDisplayed() : Boolean{ + var isTotalPriceDisplayed = false + onView((withId(net.gini.android.bank.sdk.R.id.gross_price_total_integral_part))) + .check { view, _ -> + if (view.isShown()) { + isTotalPriceDisplayed = true + } + } + return isTotalPriceDisplayed + } + + fun storeInitialPrice() { + onView(withId(net.gini.android.bank.sdk.R.id.gross_price_total_integral_part)) + .check { view, _ -> + val totalTextView = view as TextView + initialValue = totalTextView.text.toString() + } + } + + fun verifyTotalSumValue(): Boolean{ + var isSumDifferent = false + if(initialValue!=updatedValue) { + isSumDifferent = true + } + return isSumDifferent + } + + fun storeUpdatedPrice() { + onView(withId(net.gini.android.bank.sdk.R.id.gross_price_total_integral_part)) + .check { view, _ -> + val totalTextView = view as TextView + updatedValue = totalTextView.text.toString() + } + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ErrorScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ErrorScreen.kt new file mode 100644 index 0000000000..1a34a6fa1d --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ErrorScreen.kt @@ -0,0 +1,113 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiObject +import androidx.test.uiautomator.UiSelector +import androidx.test.uiautomator.Until + +class ErrorScreen { + private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + fun checkErrorTextDisplayed(): Boolean { + val errorText = device.findObject( + UiSelector().className("android.widget.TextView").text("Error").index(1) + ) + return errorText.waitForExists(5000) + } + + fun checkErrorHeaderTextDisplayed(content: String): Boolean { + val errorHeaderText = device.findObject( + UiSelector().className("android.widget.TextView") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gc_error_header").index(1) + ) + if (errorHeaderText.waitForExists(5000)) { + if (errorHeaderText.text == content) return true + } + return false + } + + fun checkErrorTextViewDisplayed(content: String): Boolean { + val errorTextViewText = device.findObject( + UiSelector().className("android.widget.TextView") + .resourceId("net.gini.android.bank.sdk.exampleapp:id/gc_error_textview").index(3) + ) + if (errorTextViewText.waitForExists(5000)) { + if (errorTextViewText.text == content) return true + } + return false + } + + fun checkEnterManuallyButtonIsDisplayed(): Boolean { + var enterManuallyButtonDisplayed = false + onView(withText(net.gini.android.capture.R.string.gc_noresults_enter_manually)).check { view, _ -> + if (view.isShown()) { + enterManuallyButtonDisplayed = true + } + } + return enterManuallyButtonDisplayed + } + + fun clickEnterManuallyButton() { + onView(withText(net.gini.android.capture.R.string.gc_noresults_enter_manually)).perform( + click() + ) + } + + fun checkBackToCameraButtonIsDisplayed(): Boolean { + var backToCameraButtonDisplayed = false + onView(withText(net.gini.android.capture.R.string.gc_error_back_to_camera)).check { view, _ -> + if (view.isShown()) { + backToCameraButtonDisplayed = true + } + } + return backToCameraButtonDisplayed + } + + fun clickBackToCameraButton() { + onView(withText(net.gini.android.capture.R.string.gc_error_back_to_camera)).perform( + click() + ) + } + + fun disconnectTheInternetConnection() { + device.openQuickSettings() + Thread.sleep(3000) + if (UiObject(UiSelector().text("AndroidWifi")).exists()) { + device.findObject(By.text("AndroidWifi")).click() + device.wait(Until.hasObject(By.text("Internet")), 3000) + //Mobile Networks - LTE, 3G, 4G + val mobileNetworkSwitch = device.findObject( + UiSelector().className("android.widget.Switch") + .resourceId("com.android.systemui:id/mobile_toggle").index(0) + ) + mobileNetworkSwitch.click() + //Wifi + val wifiText = device.findObject( + UiSelector().className("android.widget.TextView") + .resourceId("com.android.systemui:id/wifi_toggle_title").text("Wi‑Fi") + ) + wifiText.waitForExists(5000) + + val wifiSwitch = device.findObject( + UiSelector().className("android.widget.Switch") + .resourceId("com.android.systemui:id/wifi_toggle").descriptionContains("Wi‑Fi") + .index(0) + ) + if (wifiSwitch.waitForExists(5000) && wifiSwitch.isChecked) { + wifiSwitch.click() + } + } + device.pressBack() + val centerOfDevice = (device.displayWidth) / 2 + val bottomOfDevice = (device.displayHeight * 1.5).toInt() + val steps = 40 + device.swipe(centerOfDevice, bottomOfDevice, centerOfDevice, 500, steps) + Thread.sleep(3000) + device.swipe(centerOfDevice, bottomOfDevice, centerOfDevice, 500, steps) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ExtractionScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ExtractionScreen.kt new file mode 100644 index 0000000000..fe1183c0b3 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ExtractionScreen.kt @@ -0,0 +1,33 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.matcher.ViewMatchers.withHint +import androidx.test.espresso.matcher.ViewMatchers.withId +import net.gini.android.bank.sdk.exampleapp.R +import org.hamcrest.Matchers.allOf + +class ExtractionScreen { + + fun clickTransferSummaryButton(): ExtractionScreen { + onView(withId(R.id.transfer_summary)).perform(click()) + return this + } + + fun editTransferSummaryFields(hint: String, value: String) { + onView(allOf(withId(R.id.text_value), withHint(hint))) + .perform(click()) + .perform(replaceText(value)) + } + + fun checkTransferSummaryButtonIsClickable(): Boolean { + var isTransferSummaryButtonClickable = false + onView(withId(R.id.transfer_summary)) .check { view, noViewFoundException -> + if (noViewFoundException == null || view.isClickable()) { + isTransferSummaryButtonClickable = true + } + } + return isTransferSummaryButtonClickable + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/FileImportErrorDialog.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/FileImportErrorDialog.kt new file mode 100644 index 0000000000..ec8609098b --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/FileImportErrorDialog.kt @@ -0,0 +1,23 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.matcher.ViewMatchers.withText +import org.hamcrest.Matchers.allOf + +class FileImportErrorDialog { + fun checkContentIsDisplayed(resourceId: Int, content: String): Boolean { + var isContentPanelDisplayed = false + onView( + allOf( + withText(resourceId), + withText(content) + ) + ) + .check { view, _ -> + if (view.isShown()) { + isContentPanelDisplayed = true + } + } + return isContentPanelDisplayed + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/HelpScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/HelpScreen.kt new file mode 100644 index 0000000000..ecc50f68bb --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/HelpScreen.kt @@ -0,0 +1,91 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import org.hamcrest.CoreMatchers.allOf + +class HelpScreen { + fun clickTipsForBestResults(): HelpScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_help_item_title), + withText(net.gini.android.capture.R.string.gc_help_item_photo_tips_title), + isDescendantOfA(withId(net.gini.android.capture.R.id.gc_help_items)) + ) + ) + .perform(click()) + return this + } + + fun assertTipsForBestResultsExists(): HelpScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_help_item_title), + withText(net.gini.android.capture.R.string.gc_help_item_photo_tips_title), + isDescendantOfA(withId(net.gini.android.capture.R.id.gc_help_items)) + ) + ) + .check(matches(withText(net.gini.android.capture.R.string.gc_help_item_photo_tips_title))) + return this + } + + fun clickSupportedFormats(): HelpScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_help_item_title), + withText(net.gini.android.capture.R.string.gc_help_item_supported_formats_title), + isDescendantOfA(withId(net.gini.android.capture.R.id.gc_help_items)) + ) + ) + .perform(click()) + return this + } + + fun assertSupportedFormatsExists(): HelpScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_help_item_title), + withText(net.gini.android.capture.R.string.gc_help_item_supported_formats_title), + isDescendantOfA(withId(net.gini.android.capture.R.id.gc_help_items)) + ) + ) + .check(matches(withText(net.gini.android.capture.R.string.gc_help_item_supported_formats_title))) + return this + } + + fun clickImportDocs(): HelpScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_help_item_title), + withText(net.gini.android.capture.R.string.gc_help_item_file_import_guide_title), + isDescendantOfA(withId(net.gini.android.capture.R.id.gc_help_items)) + ) + ) + .perform(click()) + return this + } + + fun assertImportDocsExists(): HelpScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_help_item_title), + withText(net.gini.android.capture.R.string.gc_help_item_file_import_guide_title), + isDescendantOfA(withId(net.gini.android.capture.R.id.gc_help_items)) + ) + ) + .check(matches(withText(net.gini.android.capture.R.string.gc_help_item_file_import_guide_title))) + return this + } + + fun clickBackButton(): HelpScreen { + onView(withContentDescription(net.gini.android.capture.R.string.gc_back_button_description)).perform( + click() + ) + return this + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/MainScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/MainScreen.kt new file mode 100644 index 0000000000..084b3d3365 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/MainScreen.kt @@ -0,0 +1,28 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.matcher.ViewMatchers.withId +import net.gini.android.bank.sdk.exampleapp.R + +class MainScreen { + fun assertDescriptionTitle(): Boolean { + var isDescriptionTitleDisplayed = false + onView(withId(R.id.tv_exampleOfPhotoPayment)) + .check { view, _ -> + if (view.isShown()) { + isDescriptionTitleDisplayed = true + } + } + return isDescriptionTitleDisplayed + } + + fun clickPhotoPaymentButton() { + onView(withId(R.id.button_startScanner)).perform(click()) + } + + fun clickSettingButton() { + onView(withId(R.id.text_giniBankVersion)).perform(scrollTo(), click()) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/NoResultScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/NoResultScreen.kt new file mode 100644 index 0000000000..32f050315c --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/NoResultScreen.kt @@ -0,0 +1,24 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withText + +class NoResultScreen { + + fun checkElementWithTextIsDisplayed(resourceId: Int) : Boolean { + var isElementDisplayed = false + onView(withText(resourceId)). + check { view, _ -> + if (view.isShown()) { + isElementDisplayed = true + } + } + return isElementDisplayed + } + + fun clickEnterManuallyButton() { + onView(withText(net.gini.android.capture.R.string.gc_noresults_enter_manually)).perform( + click()) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/OnboardingScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/OnboardingScreen.kt new file mode 100644 index 0000000000..616968d09a --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/OnboardingScreen.kt @@ -0,0 +1,47 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isClickable +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import org.hamcrest.CoreMatchers.allOf + +class OnboardingScreen { + fun checkOnboardingScreenTitle(onboardingTitle: Int): OnboardingScreen { + onView( + allOf( + withId(net.gini.android.capture.R.id.gc_title), withText(onboardingTitle) + ) + ).check(matches(isDisplayed())) + return this + } + + fun checkNextButtonText(): OnboardingScreen { + onView(withId(net.gini.android.capture.R.id.gc_next)).check(matches(withText("Next"))) + return this + } + + fun clickNextButton(): OnboardingScreen { + onView(withId(net.gini.android.capture.R.id.gc_next)).check(matches(isDisplayed())) + .check(matches(isClickable())).perform(click()) + return this + } + + fun checkSkipButtonText(): OnboardingScreen { + onView(withId(net.gini.android.capture.R.id.gc_skip)).check(matches(withText("Skip"))) + return this + } + + fun clickSkipButton(): OnboardingScreen { + onView(withId(net.gini.android.capture.R.id.gc_skip)).perform(click()) + return this + } + + fun checkGetStartedButton(): OnboardingScreen { + onView(withId(net.gini.android.capture.R.id.gc_get_started)).check(matches(withText("Get Started"))) + return this + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ReviewScreen.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ReviewScreen.kt new file mode 100644 index 0000000000..0f9baa4fde --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/screens/ReviewScreen.kt @@ -0,0 +1,54 @@ +package net.gini.android.bank.sdk.exampleapp.ui.screens + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector +import org.hamcrest.Matchers.allOf + +class ReviewScreen { + fun assertReviewTitleIsDisplayed(): ReviewScreen { + onView(withText("Review")).check(matches(isDisplayed())) + return this + } + + fun clickProcessButton(): ReviewScreen { + onView( + allOf(withId(net.gini.android.capture.R.id.gc_button_next), withText("Process"))) + .perform(click()) + return this + } + + fun clickCancelButton(): ReviewScreen { + onView( + allOf(withContentDescription("Close"))) + .perform(click()) + return this + } + + fun clickDeleteButton(): ReviewScreen { + onView( + allOf(withId(net.gini.android.capture.R.id.gc_button_delete), withContentDescription("Delete page"))) + .perform(click()) + return this + } + + fun clickAddMorePagesButton(): ReviewScreen { + onView(withId(net.gini.android.capture.R.id.gc_add_page)).perform(click()) + return this + } + + fun pinchToZoomInvoice(): ReviewScreen { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + val documentPage = device.findObject(UiSelector().descriptionContains("Document page")) + documentPage.click() + documentPage.pinchOut(100, 50) + return this + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/CaptureScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/CaptureScreenTests.kt new file mode 100644 index 0000000000..eb25c94739 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/CaptureScreenTests.kt @@ -0,0 +1,92 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.espresso.Espresso.pressBack +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.filters.FlakyTest +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ConfigurationScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +/** + * Test class for flash on/off on CaptureScreen. + */ +class CaptureScreenTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val configurationScreen = ConfigurationScreen() + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private lateinit var idlingResource: SimpleIdlingResource + + @Before + fun setup() { + idlingResource = SimpleIdlingResource(10000) + IdlingRegistry.getInstance().register(idlingResource) + } + + + @Test + fun test1_flashIsOnByDefault() { + mainScreen.clickSettingButton() + configurationScreen.scrollToAnalysisText() + configurationScreen.clickFlashToggleToEnable() + pressBack() + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.assertFlashIconIsDisplayed() + captureScreen.assertFlashIconIsOn() + } + + @Test + fun test2_flashEnabledWhenImageIsCaptured() { + mainScreen.clickSettingButton() + configurationScreen.scrollToAnalysisText() + configurationScreen.clickFlashToggleToEnable() + pressBack() + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.assertFlashIconIsDisplayed() + captureScreen.assertFlashIconIsOn() + } + + @Test + fun test3_flashIsOffByDefault() { + mainScreen.clickSettingButton() + configurationScreen.scrollToAnalysisText() + configurationScreen.assertFlashToggleIsDisable() + pressBack() + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.assertFlashIconIsDisplayed() + captureScreen.assertFlashIconIsOff() + } + + @Test + fun test4_flashDisabledWhenImageIsCaptured() { + mainScreen.clickSettingButton() + configurationScreen.scrollToAnalysisText() + configurationScreen.assertFlashToggleIsDisable() + pressBack() + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.assertFlashIconIsDisplayed() + captureScreen.assertFlashIconIsOff() + captureScreen.clickCameraButton() + } + +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/DigitalInvoiceEditButtonTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/DigitalInvoiceEditButtonTests.kt new file mode 100644 index 0000000000..179c82d2c8 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/DigitalInvoiceEditButtonTests.kt @@ -0,0 +1,372 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import android.content.Context +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.PdfUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.DigitalInvoiceEditButton +import net.gini.android.bank.sdk.exampleapp.ui.screens.DigitalInvoiceScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals +import org.junit.Assume +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.util.Properties + +/** + * Test class for Edit button on Digital Invoice Screen. + */ +class DigitalInvoiceEditButtonTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val digitalInvoiceScreen = DigitalInvoiceScreen() + private val digitalInvoiceEditButton = DigitalInvoiceEditButton() + private val pdfUploader = PdfUploader() + private lateinit var idlingResource: SimpleIdlingResource + private val increaseQuantity = 5 + private val decreaseQuantity = 2 + + val testProperties = Properties().apply { + getApplicationContext().resources.assets + .open("test.properties").use { load(it) } + } + + private fun cancelTestIfRunOnCi() { + val ignoreTests = testProperties["ignoreLocalTests"] as String + Assume.assumeTrue(ignoreTests != "true") + } + + @Before + fun setup() { + cancelTestIfRunOnCi() + idlingResource = SimpleIdlingResource(10000) + IdlingRegistry.getInstance().register(idlingResource) + } + + private fun clickPhotoPaymentAndUploadFile() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + } + + @Test + fun test1_verifyNameIsUpdatedAfterEditing() { + clickPhotoPaymentAndUploadFile() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + val isNameTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_name) + assertEquals(true, isNameTextVisible) + + digitalInvoiceEditButton.editElementTextOnArticleBottomSheet(net.gini.android.bank.sdk.R.id.gbs_article_name_edit_txt, "Testing") + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + + val isDigitalInvoiceTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + val isNameFieldUpdated = digitalInvoiceEditButton.checkNameIsUpdated("Testing") + assertEquals(true, isNameFieldUpdated) + } + + @Test + fun test2_verifyUnitPriceIsUpdatedAfterEditing() { + clickPhotoPaymentAndUploadFile() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + + val isUnitPriceTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_unit_price) + assertEquals(true, isUnitPriceTextVisible) + digitalInvoiceEditButton.editElementTextOnArticleBottomSheet(net.gini.android.bank.sdk.R.id.gbs_unit_price_edit_txt, "10.00") + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + + val isDigitalInvoiceTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + val isUnitPriceFieldUpdated = digitalInvoiceEditButton.checkUnitPriceIsUpdated("10.00") + assertEquals(true, isUnitPriceFieldUpdated) + } + + @Test + fun test3_verifyQuantityIsUpdatedAfterEditing() { + clickPhotoPaymentAndUploadFile() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + + val isQuantityTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_quantity) + assertEquals(true, isQuantityTextVisible) + digitalInvoiceEditButton.editElementTextOnArticleBottomSheet(net.gini.android.bank.sdk.R.id.gbs_quantity_edit_txt, "4") + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + + val isDigitalInvoiceTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + val isQuantityFieldUpdated = digitalInvoiceEditButton.checkQuantityIsUpdated("4") + assertEquals(true, isQuantityFieldUpdated) + } + + @Test + fun test4_increaseQuantityByTappingPlus() { + clickPhotoPaymentAndUploadFile() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + + val isQuantityTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_quantity) + assertEquals(true, isQuantityTextVisible) + digitalInvoiceEditButton.clickPlusToIncreaseQuantity(increaseQuantity) + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + + val isDigitalInvoiceTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + val isQuantityFieldUpdated = digitalInvoiceEditButton.checkQuantityIsUpdated("$increaseQuantity") + assertEquals(true, isQuantityFieldUpdated) + } + + @Test + fun test5_decreaseQuantityByTappingMinus() { + clickPhotoPaymentAndUploadFile() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + + val isQuantityTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_quantity) + assertEquals(true, isQuantityTextVisible) + digitalInvoiceEditButton.clickPlusToIncreaseQuantity(increaseQuantity) + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + idlingResource.waitForIdle() + digitalInvoiceEditButton.clickMinusToDecreaseQuantity(decreaseQuantity) + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + + val isDigitalInvoiceTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + val isQuantityFieldUpdated = digitalInvoiceEditButton.checkQuantityIsUpdated("$decreaseQuantity") + assertEquals(true, isQuantityFieldUpdated) + } + + @Test + fun test6_verifyThatMinimumQuantityIs1() { + clickPhotoPaymentAndUploadFile() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + + val isQuantityTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_quantity) + assertEquals(true, isQuantityTextVisible) + digitalInvoiceEditButton.editElementTextOnArticleBottomSheet(net.gini.android.bank.sdk.R.id.gbs_quantity_edit_txt, "0") + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + + val isDigitalInvoiceTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + val isQuantityFieldUpdated = digitalInvoiceEditButton.checkQuantityIsUpdated("0") + assertNotEquals(1, isQuantityFieldUpdated) + } + + @Test + fun test7_checkCurrencyForUnitPrice() { + clickPhotoPaymentAndUploadFile() + + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + val isEditArticleTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + idlingResource.waitForIdle() + val isUnitPriceTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_unit_price) + assertEquals(true, isUnitPriceTextVisible) + idlingResource.waitForIdle() + val isCurrencyEuroVisible = digitalInvoiceEditButton.checkCurrencyForUnitPrice() + assertEquals(true, isCurrencyEuroVisible) + } + + @Test + fun test8_clickCancelButtonAndVerifyItemDetailsRemainUnchanged() { + clickPhotoPaymentAndUploadFile() + + val isOnboardingScreenTextVisible = + digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = + digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val initialName = + digitalInvoiceEditButton.saveNameValueOnDigitalInvoiceScreen() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + + + val isEditArticleTextVisible = + digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + val isNameTextVisible = + digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_name) + assertEquals(true, isNameTextVisible) + digitalInvoiceEditButton.clickCancelButtonOnEditArticleBottomSheet() + + val updatedName = + digitalInvoiceEditButton.saveNameValueOnDigitalInvoiceScreen() + if (initialName == updatedName) { + val isDigitalInvoiceTextVisible = + digitalInvoiceScreen.checkDigitalInvoiceTitleIsDisplayed() + assertEquals(true, isDigitalInvoiceTextVisible) + } + } + + @Test + fun test9_verifyInlineErrorWhenNameFieldIsEmpty() { + clickPhotoPaymentAndUploadFile() + idlingResource.waitForIdle() + val isOnboardingScreenTextVisible = + digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = + digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + + val isEditArticleTextVisible = + digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + val isNameTextVisible = + digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_name) + assertEquals(true, isNameTextVisible) + + digitalInvoiceEditButton.removeTextFromElementOnArticleBottomSheet(net.gini.android.bank.sdk.R.id.gbs_article_name_edit_txt) + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + val isInlineErrorVisible = + digitalInvoiceEditButton.verifyInlineErrorOnElement(net.gini.android.bank.sdk.R.id.gbs_name_error_textView, "Please enter the article name.") + assertEquals(true, isInlineErrorVisible) + } + + @Test + fun test10_verifyInlineErrorWhenUnitPriceFieldIsEmpty() { + clickPhotoPaymentAndUploadFile() + + val isOnboardingScreenTextVisible = + digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = + digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + + val isEditButtonVisible = digitalInvoiceEditButton.checkEditButtonTitleIsDisplayed() + assertEquals(true, isEditButtonVisible) + digitalInvoiceEditButton.clickEditButtonOnDigitalInvoiceScreen() + + val isEditArticleTextVisible = + digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_edit_article) + assertEquals(true, isEditArticleTextVisible) + val isUnitPriceTextVisible = digitalInvoiceEditButton.checkElementTitleIsDisplayed(net.gini.android.bank.sdk.R.string.gbs_unit_price) + assertEquals(true, isUnitPriceTextVisible) + + digitalInvoiceEditButton.removeTextFromElementOnArticleBottomSheet(net.gini.android.bank.sdk.R.id.gbs_unit_price_edit_txt) + digitalInvoiceEditButton.clickSaveButtonOnEditArticleBottomSheet() + idlingResource.waitForIdle() + val isInlineErrorVisible = + digitalInvoiceEditButton.verifyInlineErrorOnElement(net.gini.android.bank.sdk.R.id.gbs_price_error_textView, "Please enter the article price.") + assertEquals(true, isInlineErrorVisible) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/DigitalInvoiceScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/DigitalInvoiceScreenTests.kt new file mode 100644 index 0000000000..ff2c82afbf --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/DigitalInvoiceScreenTests.kt @@ -0,0 +1,226 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.espresso.Espresso.pressBack +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.PdfUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ConfigurationScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.DigitalInvoiceScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ExtractionScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +/** + * Test class for Digital Invoice Screen. + */ +class DigitalInvoiceScreenTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val configurationScreen = ConfigurationScreen() + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val digitalInvoiceScreen = DigitalInvoiceScreen() + private val extractionScreen = ExtractionScreen() + private val pdfUploader = PdfUploader() + private lateinit var idlingResource: SimpleIdlingResource + + @Before + fun setup() { + idlingResource = SimpleIdlingResource(10000) + IdlingRegistry.getInstance().register(idlingResource) + } + + @Test + fun test1_digitalInvoiceOnboardingScreenIsDisplayed() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenTextVisible = digitalInvoiceScreen.checkDigitalInvoiceTextOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenTextVisible) + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + } + + @Test + fun test2_disableToggleSwitchToRemoveItemFromList() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + digitalInvoiceScreen.clickArticleSwitch() + val isItemEnabled = digitalInvoiceScreen.checkItemIsEnabledFromDigitalScreen() + assertEquals(false, isItemEnabled) + } + + @Test + fun test3_returnReasonDisplaysWhenToggleSwitchIsDisabled() { + mainScreen.clickSettingButton() + configurationScreen.scrollToUICustomizationText() + configurationScreen.clickReturnReasonsDialogToEnable() + pressBack() + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + idlingResource.waitForIdle() + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + digitalInvoiceScreen.clickArticleSwitch() + idlingResource.waitForIdle() + val isDisplayed = digitalInvoiceScreen.checkForReturnReasonsList() + idlingResource.waitForIdle() + assertEquals(true, isDisplayed) + } + + @Test + fun test4_verifyCountOnReturnReasonsList() { + test3_returnReasonDisplaysWhenToggleSwitchIsDisabled() + val totalItemsOnReturnReason = 7 + val itemSize = digitalInvoiceScreen.returnItemCountOnReturnReasonsList() + assertEquals(totalItemsOnReturnReason, itemSize) + } + + @Test + fun test5_checkItemOnListIsDisabledAfterClickItemOnReturnReasonsList() { + test3_returnReasonDisplaysWhenToggleSwitchIsDisabled() + digitalInvoiceScreen.clickItemOnReturnReasonsList() + idlingResource.waitForIdle() + val isItemDisabled = digitalInvoiceScreen.checkItemIsDisabledFromDigitalScreen() + assertEquals(true, isItemDisabled) + } + + @Test + fun test6_enableToggleSwitchAndVerifyAnItemIsAddedBackToList() { + test5_checkItemOnListIsDisabledAfterClickItemOnReturnReasonsList() + idlingResource.waitForIdle() + digitalInvoiceScreen.clickArticleSwitch() + val isItemEnabled = digitalInvoiceScreen.checkItemIsEnabledFromDigitalScreen() + assertEquals(true, isItemEnabled) + } + + @Test + fun test7_differenceInTotalAmountWithSwitchEnabledOrDisabled() { + test5_checkItemOnListIsDisabledAfterClickItemOnReturnReasonsList() + idlingResource.waitForIdle() + + val isTotalTitleVisible = digitalInvoiceScreen.checkTotalTitleIsDisplayed() + assertEquals(true, isTotalTitleVisible) + + val isTotalPriceVisible = digitalInvoiceScreen.checkTotalPriceIsDisplayed() + assertEquals(true, isTotalPriceVisible) + + digitalInvoiceScreen.storeInitialPrice() + val hasTotalSumDistinct = digitalInvoiceScreen.verifyTotalSumValue() + assertEquals(true, hasTotalSumDistinct) + + digitalInvoiceScreen.clickArticleSwitch() + idlingResource.waitForIdle() + + val isTotalPriceReAppear = digitalInvoiceScreen.checkTotalPriceIsDisplayed() + assertEquals(true, isTotalPriceReAppear) + + digitalInvoiceScreen.storeUpdatedPrice() + val hasTotalSumChanged = digitalInvoiceScreen.verifyTotalSumValue() + assertEquals(true, hasTotalSumChanged) + idlingResource.waitForIdle() + } + + @Test + fun test8_verifyAdditionalChargesOnDigitalInvoice() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + val isDisplayed = digitalInvoiceScreen.assertOtherChargesDisplayed() + idlingResource.waitForIdle() + assertEquals(true, isDisplayed) + } + + @Test + fun test9_checkTransferSummaryButtonIsClickableAfterClickOnProceedButton() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + digitalInvoiceScreen.clickProceedButton() + val isTransferSummaryButtonVisible = extractionScreen.checkTransferSummaryButtonIsClickable() + assertEquals(true, isTransferSummaryButtonVisible) + } + + @Test + fun test10_clickHelpButtonAndVerifyContentOnHelpScreen() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + digitalInvoiceScreen.clickHelpButtonOnDigitalInvoiceScreen() + val isHelpTextVisible = digitalInvoiceScreen.verifyHelpTextOnNextScreen() + assertEquals(true, isHelpTextVisible) + + val isFirstTitleTextVisible = digitalInvoiceScreen.verifyFirstTitleOnHelpScreen() + assertEquals(true, isFirstTitleTextVisible) + } + + @Test + fun test11_checkMainScreenTitleIsDisplayedAfterClickOnCancelButton() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("Testrechnung-RA-1.pdf") + idlingResource.waitForIdle() + val isOnboardingScreenButtonVisible = digitalInvoiceScreen.checkDigitalInvoiceButtonOnOnboardingScreenIsDisplayed() + assertEquals(true, isOnboardingScreenButtonVisible) + digitalInvoiceScreen.clickGetStartedButtonOnOnboardingScreen() + idlingResource.waitForIdle() + digitalInvoiceScreen.clickCancelButton() + val isDescriptionTitleVisible = mainScreen.assertDescriptionTitle() + assertEquals(true, isDescriptionTitleVisible) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ErrorScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ErrorScreenTests.kt new file mode 100644 index 0000000000..add8d55667 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ErrorScreenTests.kt @@ -0,0 +1,111 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import android.content.Context +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ErrorScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.Assert.assertEquals +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import java.util.Properties + +/** + * Test class for Error Screens. + */ +class ErrorScreenTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val errorScreen = ErrorScreen() + private lateinit var idlingResource: SimpleIdlingResource + + val testProperties = Properties().apply { + getApplicationContext().resources.assets + .open("test.properties").use { load(it) } + } + + private fun cancelTestIfRunOnCi() { + val ignoreTests = testProperties["ignoreLocalTests"] as String + Assume.assumeTrue(ignoreTests != "true") + } + + @Before + fun setup() { + cancelTestIfRunOnCi() + idlingResource = SimpleIdlingResource(5000) + IdlingRegistry.getInstance().register(idlingResource) + } + + private fun clickPhotoPaymentButtonAndSkipOnboarding(){ + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickCameraButton() + idlingResource.waitForIdle() + } + + @Test + fun test1_verifyUploadErrorScreen() { + clickPhotoPaymentButtonAndSkipOnboarding() + + val errorTextVisible = errorScreen.checkErrorTextDisplayed() + assertEquals(true, errorTextVisible) + val errorHeaderVisible = errorScreen.checkErrorHeaderTextDisplayed( "There was a problem with the upload") + assertEquals(true, errorHeaderVisible) + val errorTextViewVisible = errorScreen.checkErrorTextViewDisplayed("The document couldn’t be accepted. Please check if the image is sharp, the document contains payment information and has the right file type.") + assertEquals(true, errorTextViewVisible) + } + + @Test + fun test2_verifyNetworkErrorScreen() { + errorScreen.disconnectTheInternetConnection() + clickPhotoPaymentButtonAndSkipOnboarding() + idlingResource.waitForIdle() + val errorTextVisible = errorScreen.checkErrorTextDisplayed() + assertEquals(true, errorTextVisible) + val errorHeaderVisible = errorScreen.checkErrorHeaderTextDisplayed( "There was a problem connecting to the internet") + assertEquals(true, errorHeaderVisible) + val errorTextViewVisible = errorScreen.checkErrorTextViewDisplayed("Please check your internet connection and try again later on.") + assertEquals(true, errorTextViewVisible) + } + + @Test + fun test3_navigateToMainScreenByClickingEnterManuallyButton() { + clickPhotoPaymentButtonAndSkipOnboarding() + + val enterManuallyButtonVisible = errorScreen.checkEnterManuallyButtonIsDisplayed() + assertEquals(true, enterManuallyButtonVisible) + errorScreen.clickEnterManuallyButton() + val isDescriptionTitleVisible = mainScreen.assertDescriptionTitle() + assertEquals(true, isDescriptionTitleVisible) + } + + @Test + fun test4_navigateToCameraScreenByClickingBackToCameraButton() { + clickPhotoPaymentButtonAndSkipOnboarding() + + val backToCameraButtonVisible = errorScreen.checkBackToCameraButtonIsDisplayed() + assertEquals(true, backToCameraButtonVisible) + errorScreen.clickBackToCameraButton() + val isScanTextVisible = captureScreen.checkScanTextDisplayed() + assertEquals(true, isScanTextVisible) + } + +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ExtractionScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ExtractionScreenTests.kt new file mode 100644 index 0000000000..e2ec278a98 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ExtractionScreenTests.kt @@ -0,0 +1,148 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import android.content.Context +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.espresso.Espresso.pressBack +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule +import androidx.test.uiautomator.UiDevice +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.ImageUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ExtractionScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ReviewScreen +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.util.Properties + + +/** + * Test class for Extraction screen. + */ +class ExtractionScreenTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val imageUploader = ImageUploader() + private val reviewScreen = ReviewScreen() + private val extractionScreen = ExtractionScreen() + private lateinit var idlingResource: SimpleIdlingResource + + private fun grantStoragePermission() { + val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.executeShellCommand("pm grant net.gini.android.bank.sdk.exampleapp android.permission.READ_EXTERNAL_STORAGE") + device.executeShellCommand("pm grant net.gini.android.bank.sdk.exampleapp android.permission.WRITE_EXTERNAL_STORAGE") + } + + val testProperties = Properties().apply { + getApplicationContext().resources.assets + .open("test.properties").use { load(it) } + } + + @Before + fun setup() { + cancelTestIfRunOnCi() + grantStoragePermission() + idlingResource = SimpleIdlingResource(2000) + IdlingRegistry.getInstance().register(idlingResource) + } + + @Test + fun test1_clickTransferSummaryButton() { + chooseAndUploadImageFromPhotos() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + reviewScreen.clickProcessButton() + idlingResource.waitForIdle() + extractionScreen.clickTransferSummaryButton() + } + + @Test + fun test2_editIbanFieldAndCheckTransferSummaryButtonClickable() { + chooseAndUploadImageFromPhotos() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + reviewScreen.clickProcessButton() + idlingResource.waitForIdle() + extractionScreen.editTransferSummaryFields("iban", "DE48120400000180115890") + extractionScreen.checkTransferSummaryButtonIsClickable() + } + + @Test + fun test3_editAmountFieldAndCheckTransferSummaryButtonClickable() { + chooseAndUploadImageFromPhotos() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + reviewScreen.clickProcessButton() + idlingResource.waitForIdle() + extractionScreen.editTransferSummaryFields("amountToPay", "200:EUR") + extractionScreen.checkTransferSummaryButtonIsClickable() + } + + @Test + fun test4_editPurposeFieldAndCheckTransferSummaryButtonClickable() { + chooseAndUploadImageFromPhotos() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + reviewScreen.clickProcessButton() + idlingResource.waitForIdle() + extractionScreen.editTransferSummaryFields("paymentPurpose", "Rent") + extractionScreen.checkTransferSummaryButtonIsClickable() + } + + @Test + fun test5_editRecipientFieldAndCheckTransferSummaryButtonClickable() { + chooseAndUploadImageFromPhotos() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + reviewScreen.clickProcessButton() + idlingResource.waitForIdle() + extractionScreen.editTransferSummaryFields("paymentRecipient", "Zalando Gmbh & Co. KG") + extractionScreen.checkTransferSummaryButtonIsClickable() + } + + @Test + fun test6_pressBackOnTransferSummaryAndShowsMainScreenOnSubsequentLaunches() { + chooseAndUploadImageFromPhotos() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + reviewScreen.clickProcessButton() + pressBack() + mainScreen.assertDescriptionTitle() + } + + private fun chooseAndUploadImageFromPhotos() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickPhotos() + imageUploader.uploadImageFromPhotos() + imageUploader.clickAddButton() + } + + private fun cancelTestIfRunOnCi() { + val ignoreTests = testProperties["ignoreLocalTests"] as String + Assume.assumeTrue(ignoreTests != "true") + } + + @After + fun tearDown() { + IdlingRegistry.getInstance().unregister(idlingResource) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/FileImportErrorDialogTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/FileImportErrorDialogTests.kt new file mode 100644 index 0000000000..6efe56b7b9 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/FileImportErrorDialogTests.kt @@ -0,0 +1,72 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.PdfUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.FileImportErrorDialog +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + + +/** + * Test class for Error dialogs of different File Import. + */ +class FileImportErrorDialogTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val fileImportErrorDialog = FileImportErrorDialog() + private val pdfUploader = PdfUploader() + private lateinit var idlingResource: SimpleIdlingResource + + @Before + fun setup() { + idlingResource = SimpleIdlingResource(2000) + IdlingRegistry.getInstance().register(idlingResource) + } + + @Test + fun test1_importPasswordProtectedFileAndVerifyErrorDialogIsDisplayed() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + idlingResource.waitForIdle() + pdfUploader.uploadPdfFromFiles("password-protected.pdf") + idlingResource.waitForIdle() + val isContentPanelVisible = + fileImportErrorDialog.checkContentIsDisplayed(net.gini.android.capture.R.string.gc_error_file_import_password_title,"Password protected documents cannot be analysed.") + assertEquals(true, isContentPanelVisible) + } + + @Test + fun test2_importTooManyPagesFileAndVerifyErrorDialogIsDisplayed() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + idlingResource.waitForIdle() + pdfUploader.uploadPdfFromFiles("too-many-pages.pdf") + idlingResource.waitForIdle() + val isContentPanelVisible = + fileImportErrorDialog.checkContentIsDisplayed(net.gini.android.capture.R.string.gc_error_file_import_page_count_title,"The document can only have a maximum of 10 pages.") + assertEquals(true, isContentPanelVisible) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/HelpScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/HelpScreenTests.kt new file mode 100644 index 0000000000..3c588d893f --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/HelpScreenTests.kt @@ -0,0 +1,60 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.HelpScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.Rule +import org.junit.Test + +/** + * Test class for help screen flow. + */ +class HelpScreenTests { + + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val helpScreen = HelpScreen() + + @Test + fun test2_verifyHelpItemTipsForBestResult() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickHelpButton() + helpScreen.assertTipsForBestResultsExists() + helpScreen.clickTipsForBestResults() + helpScreen.clickBackButton() + } + + @Test + fun test3_verifyHelpItemSupportedFormats() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickHelpButton() + helpScreen.assertSupportedFormatsExists() + helpScreen.clickSupportedFormats() + helpScreen.clickBackButton() + } + + @Test + fun test4_verifyHelpItemImportDocuments() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickHelpButton() + helpScreen.assertImportDocsExists() + helpScreen.clickImportDocs() + helpScreen.clickBackButton() + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ImportPdfImageTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ImportPdfImageTests.kt new file mode 100644 index 0000000000..4f5ea67043 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ImportPdfImageTests.kt @@ -0,0 +1,75 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.ImageUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.PdfUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ReviewScreen +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +/** + * Test class for Import PDF and Photos. + * + * No automation for step 4 and 5, since it is not part of our SDK + */ +class ImportPdfImageTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val imageUploader = ImageUploader() + private val pdfUploader = PdfUploader() + private val reviewScreen = ReviewScreen() + private lateinit var idlingResource: SimpleIdlingResource + + + @Before + fun setup() { + idlingResource = SimpleIdlingResource(2000) + IdlingRegistry.getInstance().register(idlingResource) + } + + @Test + fun test1_uploadPhoto() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickPhotos() + imageUploader.uploadImageFromPhotos() + imageUploader.clickAddButton() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + } + + @Test + fun test2_cancelUploadedPhoto() { + test1_uploadPhoto() + reviewScreen.clickCancelButton() + mainScreen.assertDescriptionTitle() + } + + @Test + fun test3_uploadPdf() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("sample.pdf") + idlingResource.waitForIdle() + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/MainScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/MainScreenTests.kt new file mode 100644 index 0000000000..7dc90b437c --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/MainScreenTests.kt @@ -0,0 +1,52 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import android.app.Activity +import android.app.Instrumentation +import android.content.Intent +import android.net.Uri +import androidx.test.espresso.intent.Intents +import androidx.test.espresso.intent.Intents.intending +import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction +import androidx.test.espresso.intent.matcher.IntentMatchers.hasType +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import org.hamcrest.Matchers.allOf +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class MainScreenTests { + + @get: Rule + val activityRule = ActivityScenarioRule(MainActivity::class.java) + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + + @Before + fun setUp() { + Intents.init() + } + + @Test + fun test1_pdfImportFromFiles() { + mainScreen.clickPhotoPaymentButton() + val resultData = Intent() + val fileUri = + Uri.parse("/Users/syedaquratulainasad/Documents/Gini/GitHub/gini-mobile-android/bank-sdk/example-app/src/androidTest/assets/test_pdf.pdf") + resultData.setData(fileUri) + val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData) + intending( + allOf( + hasAction(Intent.ACTION_OPEN_DOCUMENT), + hasType("image/*") + ) + ).respondWith(result) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/NoResultsTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/NoResultsTests.kt new file mode 100644 index 0000000000..d5d18f4d1d --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/NoResultsTests.kt @@ -0,0 +1,137 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.ImageUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.PdfUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.NoResultScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ReviewScreen +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +/** + * Test class for No Result screen. + */ +class NoResultsTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val imageUploader = ImageUploader() + private val pdfUploader = PdfUploader() + private val reviewScreen = ReviewScreen() + private val noResultScreen = NoResultScreen() + private lateinit var idlingResource: SimpleIdlingResource + + @Before + fun setup() { + idlingResource = SimpleIdlingResource(5000) + IdlingRegistry.getInstance().register(idlingResource) + } + @Test + fun test1_uploadInvalidImageAndClickEnterManuallyButton_NavigatesToMainScreen() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickPhotos() + imageUploader.uploadImageFromPhotos() + imageUploader.clickAddButton() + idlingResource.waitForIdle() + reviewScreen.clickProcessButton() + val isNoResultTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_title_no_results) + assertEquals(true, isNoResultTitleVisible) + + val isNoResultHeaderVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_noresults_header) + assertEquals(true, isNoResultHeaderVisible) + + val isUsefulTipsVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_useful_tips) + assertEquals(true, isUsefulTipsVisible) + + val isGoodLightingTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_photo_tip_good_lighting_title) + assertEquals(true, isGoodLightingTitleVisible) + + val isFlattenTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_photo_tip_flatten_the_page_title) + assertEquals(true, isFlattenTitleVisible) + + val isParallelTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_photo_tip_parallel_title) + assertEquals(true, isParallelTitleVisible) + + val isPositionInTheFrameTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_photo_tip_align_title) + assertEquals(true, isPositionInTheFrameTitleVisible) + + val isMultiPagesTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_photo_tip_multiple_pages_title) + assertEquals(true, isMultiPagesTitleVisible) + + idlingResource.waitForIdle() + val isEnterManuallyButtonVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_noresults_enter_manually) + assertEquals(true, isEnterManuallyButtonVisible) + + noResultScreen.clickEnterManuallyButton() + + val isDescriptionTitleVisible = mainScreen.assertDescriptionTitle() + assertEquals(true, isDescriptionTitleVisible) + } + + + @Test + fun test2_uploadInvalidPdfAndClickEnterManuallyButton_NavigatesToMainScreen() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickFiles() + pdfUploader.uploadPdfFromFiles("test-pdf-no-results.pdf") + idlingResource.waitForIdle() + val isNoResultTitleVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_title_no_results) + assertEquals(true, isNoResultTitleVisible) + + val isNoResultHeaderVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_noresults_header) + assertEquals(true, isNoResultHeaderVisible) + + val isSupportedFormatVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_supported_format_section_header) + assertEquals(true, isSupportedFormatVisible) + + val isComputerGeneratedInvoiceTextVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_supported_format_printed_invoices) + assertEquals(true, isComputerGeneratedInvoiceTextVisible) + + val isOneSidedPhotoTextVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_supported_format_single_page_as_jpeg_png_gif) + assertEquals(true, isOneSidedPhotoTextVisible) + + val isPdfDocumentTextVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_supported_format_pdf) + assertEquals(true, isPdfDocumentTextVisible) + + val isQRCodeTextVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_supported_format_qr_code) + assertEquals(true, isQRCodeTextVisible) + + val isMonitorScreenPhotosTextVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_unsupported_format_photos_of_screens) + assertEquals(true, isMonitorScreenPhotosTextVisible) + + val isNotSupportedFormatVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_unsupported_format_section_header) + assertEquals(true, isNotSupportedFormatVisible) + + val isHandwritingTextVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_unsupported_format_handwriting) + assertEquals(true, isHandwritingTextVisible) + + idlingResource.waitForIdle() + val isEnterManuallyButtonVisible = noResultScreen.checkElementWithTextIsDisplayed(net.gini.android.capture.R.string.gc_noresults_enter_manually) + assertEquals(true, isEnterManuallyButtonVisible) + + noResultScreen.clickEnterManuallyButton() + + val isDescriptionTitleVisible = mainScreen.assertDescriptionTitle() + assertEquals(true, isDescriptionTitleVisible) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/OnboardingScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/OnboardingScreenTests.kt new file mode 100644 index 0000000000..97fa6259e9 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/OnboardingScreenTests.kt @@ -0,0 +1,117 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import androidx.test.espresso.Espresso.pressBack +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.rule.GrantPermissionRule +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +/** + * Test class for onboarding screen flow. + */ +class OnboardingScreenTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private lateinit var idlingResource: SimpleIdlingResource + + @Before + fun setUp() { + idlingResource = SimpleIdlingResource(2000) + IdlingRegistry.getInstance().register(idlingResource) + } + + @Test + fun test1_assertFlatPaperTitle() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.checkOnboardingScreenTitle(net.gini.android.capture.R.string.gc_onboarding_align_corners_title) + } + + @Test + fun test2_clickNextButtonAndAssertGoodLightningTitle() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickNextButton() + onboardingScreen.checkOnboardingScreenTitle(net.gini.android.capture.R.string.gc_onboarding_lighting_title) + } + + @Test + fun test3_clickNextButtonAndAssertAddMultiPageTitle() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickNextButton() + idlingResource.waitForIdle() + onboardingScreen.clickNextButton() + onboardingScreen.checkOnboardingScreenTitle(net.gini.android.capture.R.string.gc_onboarding_multipage_title) + } + + @Test + fun test4_clickNextButtonAndAssertQRCodeTitle() { + mainScreen.clickPhotoPaymentButton() + idlingResource.waitForIdle() + onboardingScreen.clickNextButton() + idlingResource.waitForIdle() + onboardingScreen.clickNextButton() + idlingResource.waitForIdle() + onboardingScreen.clickNextButton() + idlingResource.waitForIdle() + onboardingScreen.checkOnboardingScreenTitle(net.gini.android.capture.R.string.gc_onboarding_qr_code_title) + } + + @Test + fun test5_assertNextButton() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.checkNextButtonText() + } + + @Test + fun test6_assertSkipButton() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.checkSkipButtonText() + } + + @Test + fun test7_assertGetStartedButton() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickNextButton() + onboardingScreen.clickNextButton() + onboardingScreen.clickNextButton() + onboardingScreen.checkGetStartedButton() + } + + @Test + fun test8a_assertOnboardingOnFirstLaunch() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.checkOnboardingScreenTitle(net.gini.android.capture.R.string.gc_onboarding_align_corners_title) + onboardingScreen.checkSkipButtonText() + } + + @Test + fun test8b_skipsOnboardingAndShowsCameraScreenOnSubsequentLaunches() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + pressBack() + mainScreen.assertDescriptionTitle() + mainScreen.clickPhotoPaymentButton() + captureScreen.assertCameraTitle() + } + + @After + fun tearDown() { + IdlingRegistry.getInstance().unregister(idlingResource) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ReviewScreenTests.kt b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ReviewScreenTests.kt new file mode 100644 index 0000000000..d21541a127 --- /dev/null +++ b/bank-sdk/example-app/src/androidTest/java/net/gini/android/bank/sdk/exampleapp/ui/testcases/ReviewScreenTests.kt @@ -0,0 +1,118 @@ +package net.gini.android.bank.sdk.exampleapp.ui.testcases + +import android.Manifest +import android.content.Context +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule +import androidx.test.uiautomator.UiDevice +import net.gini.android.bank.sdk.exampleapp.ui.MainActivity +import net.gini.android.bank.sdk.exampleapp.ui.resources.ImageUploader +import net.gini.android.bank.sdk.exampleapp.ui.resources.SimpleIdlingResource +import net.gini.android.bank.sdk.exampleapp.ui.screens.CaptureScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.MainScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.OnboardingScreen +import net.gini.android.bank.sdk.exampleapp.ui.screens.ReviewScreen +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.util.Properties + + +/** + * Test class for Review screen. + */ +class ReviewScreenTests { + @get:Rule + val activityRule = activityScenarioRule() + + @get: Rule + val grantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.CAMERA) + + private val mainScreen = MainScreen() + private val onboardingScreen = OnboardingScreen() + private val captureScreen = CaptureScreen() + private val imageUploader = ImageUploader() + private val reviewScreen = ReviewScreen() + private lateinit var idlingResource: SimpleIdlingResource + + private fun grantStoragePermission() { + val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.executeShellCommand("pm grant net.gini.android.bank.sdk.exampleapp android.permission.READ_EXTERNAL_STORAGE") + device.executeShellCommand("pm grant net.gini.android.bank.sdk.exampleapp android.permission.WRITE_EXTERNAL_STORAGE") + } + + val testProperties = Properties().apply { + getApplicationContext().resources.assets + .open("test.properties").use { load(it) } + } + + private fun cancelTestIfRunOnCi() { + val ignoreTests = testProperties["ignoreLocalTests"] as String + Assume.assumeTrue(ignoreTests != "true") + } + + @Before + fun setup() { + cancelTestIfRunOnCi() + grantStoragePermission() + idlingResource = SimpleIdlingResource(2000) + IdlingRegistry.getInstance().register(idlingResource) + } + + @Test + fun test1_reviewUploadedInvoice() { + mainScreen.clickPhotoPaymentButton() + onboardingScreen.clickSkipButton() + captureScreen.clickFilesButton() + captureScreen.clickPhotos() + imageUploader.uploadImageFromPhotos() + imageUploader.clickAddButton() + idlingResource.waitForIdle() + reviewScreen.assertReviewTitleIsDisplayed() + } + + @Test + fun test2_pinchToZoomInvoice() { + test1_reviewUploadedInvoice() + reviewScreen.pinchToZoomInvoice() + } + + @Test + fun test3_clickCloseButtonForZoomedInvoice() { + test2_pinchToZoomInvoice() + reviewScreen.clickCancelButton() + reviewScreen.assertReviewTitleIsDisplayed() + } + + @Test + fun test4_cancelUploadedInvoice() { + test1_reviewUploadedInvoice() + reviewScreen.clickCancelButton() + mainScreen.assertDescriptionTitle() + } + + @Test + fun test5_deleteUploadedInvoice() { + test1_reviewUploadedInvoice() + reviewScreen.clickDeleteButton() + captureScreen.assertCameraTitle() + } + + @Test + fun test6_addMorePagesToUploadedInvoice() { + test1_reviewUploadedInvoice() + reviewScreen.clickAddMorePagesButton() + captureScreen.assertCameraTitle() + } + + @After + fun tearDown() { + IdlingRegistry.getInstance().unregister(idlingResource) + } +} \ No newline at end of file diff --git a/bank-sdk/example-app/src/androidTest/testDocuments/Testrechnung-RA-1.pdf b/bank-sdk/example-app/src/androidTest/testDocuments/Testrechnung-RA-1.pdf new file mode 100644 index 0000000000..5c7afbe2ce Binary files /dev/null and b/bank-sdk/example-app/src/androidTest/testDocuments/Testrechnung-RA-1.pdf differ diff --git a/bank-sdk/example-app/src/androidTest/testDocuments/sample.pdf b/bank-sdk/example-app/src/androidTest/testDocuments/sample.pdf new file mode 100644 index 0000000000..607655faec Binary files /dev/null and b/bank-sdk/example-app/src/androidTest/testDocuments/sample.pdf differ diff --git a/bank-sdk/example-app/src/androidTest/testDocuments/test_image.jpeg b/bank-sdk/example-app/src/androidTest/testDocuments/test_image.jpeg new file mode 100644 index 0000000000..c1b624ae93 Binary files /dev/null and b/bank-sdk/example-app/src/androidTest/testDocuments/test_image.jpeg differ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 20e4a7a85a..7a742ddd24 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,6 +51,7 @@ androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", versi androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "androidx-camera" } androidx-annotation = "androidx.annotation:annotation:1.7.1" androidx-test-core-ktx = { module = "androidx.test:core-ktx", version.ref = "androidx-test" } +androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" } androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test" } androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test" } androidx-test-orchestrator = "androidx.test:orchestrator:1.4.2" @@ -124,4 +125,4 @@ accompanist-themeAdapter = { module = "com.google.android.material:compose-theme koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" } koin-core = { module = "io.insert-koin:koin-core" } koin-android = { module = "io.insert-koin:koin-android" } -koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose" } \ No newline at end of file +koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose" }