Compare commits
	
		
			1 Commits
		
	
	
		
			fix-bottom
			...
			37cd7d5d8c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 37cd7d5d8c | 
							
								
								
									
										65
									
								
								.gitea/workflows/common_coverage.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								.gitea/workflows/common_coverage.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| name: Coverage | ||||
| on: | ||||
|   workflow_call: | ||||
|  | ||||
| jobs: | ||||
|   BuildAndTestAndCoverage: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out repository code | ||||
|         uses: actions/checkout@v4 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - name: Fetch tags | ||||
|         run: git fetch --tags -p | ||||
|       - uses: actions/setup-java@v4 | ||||
|         with: | ||||
|           distribution: 'temurin' | ||||
|           java-version: '17' | ||||
|           cache: gradle | ||||
|       - uses: gradle/actions/setup-gradle@v3 | ||||
|       - uses: android-actions/setup-android@v3 | ||||
|       - name: Configure gradle... | ||||
|         run: mkdir -p ~/.gradle && echo "ignoreGitVersion=true" >> ~/.gradle/gradle.properties | ||||
|       - uses: KengoTODA/actions-setup-docker-compose@v1 | ||||
|         with: | ||||
|           version: "2.23.3" | ||||
|       - name: run selfoss | ||||
|         run: | | ||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml up -d | ||||
|       - name: Set env url | ||||
|         run: | | ||||
|           export SELFOSS_URL=172.17.0.1:8888 | ||||
|       # https://github.com/ReactiveCircus/android-emulator-runner/issues/385 | ||||
|       - name: Kill crashpad_handler processes | ||||
|         if: always() | ||||
|         run: | | ||||
|           pkill -SIGTERM crashpad_handler || true | ||||
|           sleep 5 | ||||
|           pkill -SIGKILL crashpad_handler || true | ||||
|       - name: Tests | ||||
|         uses: reactivecircus/android-emulator-runner@v2 | ||||
|         with: | ||||
|           api-level: 29 | ||||
|           script: | | ||||
|             ./gradlew androidApp:connectedAndroidTest | ||||
|             killall -INT crashpad_handler || true | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         if: failure() | ||||
|         with: | ||||
|           name: failure-espresso | ||||
|           path: build/reports/androidTests/connected/screenshots | ||||
|           retention-days: 2 | ||||
|           overwrite: true | ||||
|           include-hidden-files: true | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: coverage-espresso | ||||
|           path: build/reports/coverage/androidTest/githubConfig/debug/connected | ||||
|           retention-days: 1 | ||||
|           overwrite: true | ||||
|           include-hidden-files: true | ||||
|       - name: Clean | ||||
|         if: always() | ||||
|         run: | | ||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml stop | ||||
| @@ -3,89 +3,149 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|       - chore-crowdin-ci | ||||
|  | ||||
| jobs: | ||||
|   Lint: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out repository code | ||||
|         uses: actions/checkout@v4 | ||||
|       - uses: actions/setup-java@v4 | ||||
|         with: | ||||
|           distribution: 'temurin' | ||||
|           java-version: '17' | ||||
|           cache: gradle | ||||
|       - name: Install klint | ||||
|         run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.5.0/ktlint && chmod a+x ktlint && mv ktlint /usr/local/bin/ | ||||
|       - name: Install detekt | ||||
|         run: curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7.zip && unzip detekt-cli-1.23.7.zip | ||||
|       - name: Linting... | ||||
|         run: ktlint 'shared/**/*.kt' 'androidApp/**/*.kt' '!shared/build' | ||||
|       - name: Detecting... | ||||
|         run: ./detekt-cli-1.23.7/bin/detekt-cli -c detekt.yml --excludes '**/shared/build/**/*.kt' | ||||
|   translations: | ||||
|   BuildAndTestAndCoverage: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out repository code | ||||
|         uses: actions/checkout@v4 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - name: "Check translations changes" | ||||
|         id: check-translations-changes | ||||
|         uses: tj-actions/changed-files@v45 | ||||
|       - name: Fetch tags | ||||
|         run: git fetch --tags -p | ||||
|       - uses: actions/setup-java@v4 | ||||
|         with: | ||||
|           files: | | ||||
|             androidApp/src/main/res/values/strings.xml | ||||
|       - name: upload translation sources | ||||
|         if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
|         uses: crowdin/github-action@v2 | ||||
|           distribution: 'temurin' | ||||
|           java-version: '17' | ||||
|       - uses: gradle/actions/setup-gradle@v3 | ||||
|       - uses: android-actions/setup-android@v3 | ||||
|       - name: Configure gradle... | ||||
|         run: mkdir -p ~/.gradle && echo "ignoreGitVersion=true" >> ~/.gradle/gradle.properties | ||||
|       - uses: KengoTODA/actions-setup-docker-compose@v1 | ||||
|         with: | ||||
|           config: './.gitea/workflows/assets/crowdin.yml' | ||||
|           upload_sources: true | ||||
|           upload_translations: false | ||||
|           download_translations: false | ||||
|           create_pull_request: false | ||||
|           push_translations: false | ||||
|         env: | ||||
|           CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | ||||
|           CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | ||||
|       - name: wait | ||||
|         if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
|         run: sleep 10s | ||||
|       - name: download translations | ||||
|         if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
|         uses: crowdin/github-action@v2 | ||||
|         with: | ||||
|           config: './.gitea/workflows/assets/crowdin.yml' | ||||
|           upload_sources: false | ||||
|           upload_translations: false | ||||
|           download_translations: true | ||||
|           create_pull_request: false | ||||
|           push_translations: false | ||||
|         env: | ||||
|           CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | ||||
|           CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | ||||
|       - name: Check for uncommitted changes | ||||
|         if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
|         id: check-changes | ||||
|         uses: mskri/check-uncommitted-changes-action@v1.0.1 | ||||
|       - name: Commit Changes | ||||
|         if: steps.check-api-changes.outputs.any_modified == 'true' && steps.check-changes.outputs.changes != '' | ||||
|           version: "2.23.3" | ||||
|       - name: run selfoss | ||||
|         run: | | ||||
|           git config --global user.email aminecmi+giteadrone@pm.me | ||||
|           git config --global user.name giteadrone | ||||
|           git add ./androidApp/src/main/res/* | ||||
|           git commit -m "translation: translation files" | ||||
|       - name: Push changes | ||||
|         if: steps.check-api-changes.outputs.any_modified == 'true' && steps.check-changes.outputs.changes != '' | ||||
|         uses: appleboy/git-push-action@v1.0.0 | ||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml up -d | ||||
|       - name: Set env url | ||||
|         run: | | ||||
|           export SELFOSS_URL=172.17.0.1:8888 | ||||
|       # https://github.com/ReactiveCircus/android-emulator-runner/issues/385 | ||||
|       - name: Kill crashpad_handler processes | ||||
|         if: always() | ||||
|         run: | | ||||
|           pkill -SIGTERM crashpad_handler || true | ||||
|           sleep 5 | ||||
|           pkill -SIGKILL crashpad_handler || true | ||||
|       - name: Tests | ||||
|         uses: reactivecircus/android-emulator-runner@v2 | ||||
|         with: | ||||
|           author_name: giteadrone | ||||
|           author_email: aminecmi+giteadrone@pm.me | ||||
|           remote: ${{ secrets.REMOTE_URL }} | ||||
|           ssh_key: ${{ secrets.PRIVATE_KEY }} | ||||
|           branch: ${{ github.head_ref || github.ref_name }} | ||||
|   build: | ||||
|     needs: Lint | ||||
|     uses: ./.gitea/workflows/common_build.yml | ||||
|           api-level: 29 | ||||
|           script: | | ||||
|             ./gradlew androidApp:connectedAndroidTest | ||||
|             killall -INT crashpad_handler || true | ||||
|             ./gradlew androidApp:fetchScreenshots | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         if: failure() | ||||
|         with: | ||||
|           name: failure-espresso | ||||
|           path: build/reports/androidTests/connected/screenshots | ||||
|           retention-days: 2 | ||||
|           overwrite: true | ||||
|           include-hidden-files: true | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: coverage-espresso | ||||
|           path: build/reports/coverage/androidTest/githubConfig/debug/connected | ||||
|           retention-days: 1 | ||||
|           overwrite: true | ||||
|           include-hidden-files: true | ||||
|       - name: Clean | ||||
|         if: always() | ||||
|         run: | | ||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml stop | ||||
|  | ||||
| #  Lint: | ||||
| #    runs-on: ubuntu-latest | ||||
| #    steps: | ||||
| #      - name: Check out repository code | ||||
| #        uses: actions/checkout@v4 | ||||
| #      - uses: actions/setup-java@v4 | ||||
| #        with: | ||||
| #          distribution: 'temurin' | ||||
| #          java-version: '17' | ||||
| #          cache: gradle | ||||
| #      - name: Install klint | ||||
| #        run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.5.0/ktlint && chmod a+x ktlint && mv ktlint /usr/local/bin/ | ||||
| #      - name: Install detekt | ||||
| #        run: curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7.zip && unzip detekt-cli-1.23.7.zip | ||||
| #      - name: Linting... | ||||
| #        run: ktlint 'shared/**/*.kt' 'androidApp/**/*.kt' '!shared/build' | ||||
| #      - name: Detecting... | ||||
| #        run: ./detekt-cli-1.23.7/bin/detekt-cli -c detekt.yml --excludes '**/shared/build/**/*.kt' | ||||
| #  translations: | ||||
| #    runs-on: ubuntu-latest | ||||
| #    steps: | ||||
| #      - name: Check out repository code | ||||
| #        uses: actions/checkout@v4 | ||||
| #        with: | ||||
| #          fetch-depth: 0 | ||||
| #      - name: "Check translations changes" | ||||
| #        id: check-translations-changes | ||||
| #        uses: tj-actions/changed-files@v45 | ||||
| #        with: | ||||
| #          files: | | ||||
| #            androidApp/src/main/res/values/strings.xml | ||||
| #      - name: upload translation sources | ||||
| #        if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
| #        uses: crowdin/github-action@v2 | ||||
| #        with: | ||||
| #          config: './.gitea/workflows/assets/crowdin.yml' | ||||
| #          upload_sources: true | ||||
| #          upload_translations: false | ||||
| #          download_translations: false | ||||
| #          create_pull_request: false | ||||
| #          push_translations: false | ||||
| #        env: | ||||
| #          CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | ||||
| #          CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | ||||
| #      - name: wait | ||||
| #        if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
| #        run: sleep 10s | ||||
| #      - name: download translations | ||||
| #        if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
| #        uses: crowdin/github-action@v2 | ||||
| #        with: | ||||
| #          config: './.gitea/workflows/assets/crowdin.yml' | ||||
| #          upload_sources: false | ||||
| #          upload_translations: false | ||||
| #          download_translations: true | ||||
| #          create_pull_request: false | ||||
| #          push_translations: false | ||||
| #        env: | ||||
| #          CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | ||||
| #          CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | ||||
| #      - name: Check for uncommitted changes | ||||
| #        if: steps.check-api-changes.outputs.any_modified == 'true' | ||||
| #        id: check-changes | ||||
| #        uses: mskri/check-uncommitted-changes-action@v1.0.1 | ||||
| #      - name: Commit Changes | ||||
| #        if: steps.check-api-changes.outputs.any_modified == 'true' && steps.check-changes.outputs.changes != '' | ||||
| #        run: | | ||||
| #          git config --global user.email aminecmi+giteadrone@pm.me | ||||
| #          git config --global user.name giteadrone | ||||
| #          git add ./androidApp/src/main/res/* | ||||
| #          git commit -m "translation: translation files" | ||||
| #      - name: Push changes | ||||
| #        if: steps.check-api-changes.outputs.any_modified == 'true' && steps.check-changes.outputs.changes != '' | ||||
| #        uses: appleboy/git-push-action@v1.0.0 | ||||
| #        with: | ||||
| #          author_name: giteadrone | ||||
| #          author_email: aminecmi+giteadrone@pm.me | ||||
| #          remote: ${{ secrets.REMOTE_URL }} | ||||
| #          ssh_key: ${{ secrets.PRIVATE_KEY }} | ||||
| #          branch: ${{ github.head_ref || github.ref_name }} | ||||
| #  build: | ||||
| #    needs: Lint | ||||
| #    uses: ./.gitea/workflows/common_build.yml | ||||
|   | ||||
| @@ -96,6 +96,7 @@ android { | ||||
|         // tests | ||||
|         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||
|         testInstrumentationRunnerArguments["clearPackageData"] = "true" | ||||
|         testInstrumentationRunnerArguments["useTestStorageService"] = "true" | ||||
|     } | ||||
|     packaging { | ||||
|         resources { | ||||
| @@ -109,6 +110,11 @@ android { | ||||
|             proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") | ||||
|         } | ||||
|         getByName("debug") { | ||||
|             isTestCoverageEnabled = true | ||||
|             enableAndroidTestCoverage = true | ||||
|             installation { | ||||
|                 installOptions("-g", "-r") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     flavorDimensions.add("build") | ||||
| @@ -154,8 +160,8 @@ dependencies { | ||||
|     implementation("androidx.multidex:multidex:2.0.1") | ||||
|  | ||||
|     // About | ||||
|     implementation("com.mikepenz:aboutlibraries-core:10.5.1") | ||||
|     implementation("com.mikepenz:aboutlibraries:10.5.1") | ||||
|     implementation("com.mikepenz:aboutlibraries-core:11.6.3") | ||||
|     implementation("com.mikepenz:aboutlibraries:11.6.3") | ||||
|  | ||||
|     // Material-ish things | ||||
|     implementation("com.ashokvarma.android:bottom-navigation-bar:2.2.0") | ||||
| @@ -197,14 +203,16 @@ dependencies { | ||||
|     testImplementation("io.mockk:mockk:1.13.14") | ||||
|     testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1") | ||||
|     implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") | ||||
|     androidTestImplementation("androidx.test:runner:1.6.2") | ||||
|     androidTestImplementation("androidx.test:rules:1.6.1") | ||||
|     androidTestImplementation("androidx.test:runner:1.7.0-alpha01") | ||||
|     androidTestImplementation("androidx.test:rules:1.7.0-alpha01") | ||||
|     androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") | ||||
|     implementation("androidx.test.espresso:espresso-idling-resource:3.6.1") | ||||
|     androidTestImplementation("androidx.test.ext:junit-ktx:1.2.1") | ||||
|     androidTestUtil("androidx.test:orchestrator:1.5.1") | ||||
|     androidTestUtil("androidx.test:orchestrator:1.6.0-alpha02") | ||||
|     androidTestUtil("androidx.test.services:test-services:1.6.0-alpha02") | ||||
|     testImplementation("org.robolectric:robolectric:4.14.1") | ||||
|     testImplementation("androidx.test:core-ktx:1.6.1") | ||||
|     testImplementation("androidx.test:core-ktx:1.7.0-alpha01") | ||||
|     androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0") | ||||
|  | ||||
|     implementation("ch.acra:acra-http:$acraVersion") | ||||
|     implementation("ch.acra:acra-toast:$acraVersion") | ||||
| @@ -227,6 +235,7 @@ tasks.withType<Test> { | ||||
| } | ||||
|  | ||||
| aboutLibraries { | ||||
|     excludeFields = arrayOf("generated") | ||||
|     offlineMode = true | ||||
|     fetchRemoteLicense = false | ||||
|     fetchRemoteFunding = false | ||||
| @@ -235,3 +244,33 @@ aboutLibraries { | ||||
|     duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE | ||||
|     duplicationRule = com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP | ||||
| } | ||||
|  | ||||
| // Screenshot failure handling | ||||
| val reportsDirectory = file("$buildDir/reports/androidTests/connected") | ||||
|  | ||||
| val clearScreenshotsTask = | ||||
|     tasks.register<Exec>("clearScreenshots") { | ||||
|         println("AMINE : clear") | ||||
|         commandLine = listOf("adb", "shell", "rm", "-r", "/sdcard/Pictures/selfoss_tests") | ||||
|     } | ||||
|  | ||||
| val createScreenshotDirectoryTask = | ||||
|     tasks.register<Exec>("createScreenshotDirectory") { | ||||
|         println("AMINE : create directory") | ||||
|         group = "reporting" | ||||
|         commandLine = listOf("adb", "shell", "mkdir", "-p", "/sdcard/Pictures/selfoss_tests") | ||||
|     } | ||||
|  | ||||
| tasks.register<Exec>("fetchScreenshots") { | ||||
|     println("AMINE : fetch") | ||||
|     group = "reporting" | ||||
|     executable(android.adbExecutable.toString()) | ||||
|     commandLine = listOf("adb", "pull", "/sdcard/Pictures/selfoss_tests/.", reportsDirectory.toString()) | ||||
|  | ||||
|     finalizedBy(clearScreenshotsTask) | ||||
|     dependsOn(createScreenshotDirectoryTask) | ||||
|  | ||||
|     doFirst { | ||||
|         reportsDirectory.mkdirs() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,11 @@ | ||||
| package bou.amine.apps.readerforselfossv2.android | ||||
|  | ||||
| import android.content.Context | ||||
| import android.os.Environment.DIRECTORY_PICTURES | ||||
| import android.os.Environment.getExternalStoragePublicDirectory | ||||
| import android.util.Log | ||||
| import androidx.annotation.ArrayRes | ||||
| import androidx.test.espresso.Espresso | ||||
| import androidx.test.espresso.Espresso.onData | ||||
| import androidx.test.espresso.Espresso.onView | ||||
| import androidx.test.espresso.action.ViewActions.click | ||||
| @@ -9,18 +13,33 @@ import androidx.test.espresso.action.ViewActions.replaceText | ||||
| import androidx.test.espresso.action.ViewActions.typeTextIntoFocusedView | ||||
| import androidx.test.espresso.assertion.ViewAssertions.doesNotExist | ||||
| import androidx.test.espresso.assertion.ViewAssertions.matches | ||||
| import androidx.test.espresso.base.DefaultFailureHandler | ||||
| import androidx.test.espresso.matcher.ViewMatchers.isChecked | ||||
| import androidx.test.espresso.matcher.ViewMatchers.isDisplayed | ||||
| import androidx.test.espresso.matcher.ViewMatchers.isNotChecked | ||||
| import androidx.test.espresso.matcher.ViewMatchers.withId | ||||
| import androidx.test.espresso.matcher.ViewMatchers.withText | ||||
| import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation | ||||
| import androidx.test.runner.screenshot.BasicScreenCaptureProcessor | ||||
| import androidx.test.runner.screenshot.Screenshot | ||||
| import androidx.test.uiautomator.UiDevice | ||||
| import androidx.test.uiautomator.UiSelector | ||||
| import org.hamcrest.CoreMatchers.allOf | ||||
| import org.hamcrest.Matchers.hasToString | ||||
| import org.junit.BeforeClass | ||||
| import org.junit.rules.TestWatcher | ||||
| import org.junit.runner.Description | ||||
| import java.io.File | ||||
| import java.io.IOException | ||||
| import java.util.Locale | ||||
|  | ||||
| val defaultUrl = (System.getenv("SELFOSS_URL") ?: "").ifEmpty { "http://10.0.2.2:8888" } | ||||
|  | ||||
| fun performLogin(someUrl: String? = null) { | ||||
|     Log.i("AUTOMATION", "The url used will be ${if (!someUrl.isNullOrEmpty()) someUrl else defaultUrl}") | ||||
|     onView(withId(R.id.urlView)).perform(click()).perform( | ||||
|         typeTextIntoFocusedView( | ||||
|             if (!someUrl.isNullOrEmpty()) someUrl else "http://10.0.2.2:8888", | ||||
|             if (!someUrl.isNullOrEmpty()) someUrl else defaultUrl, | ||||
|         ), | ||||
|     ) | ||||
|     onView(withId(R.id.signInButton)).perform(click()) | ||||
| @@ -119,3 +138,86 @@ fun testAddSourceWithUrl( | ||||
|         .perform(click()) | ||||
|     onView(withText(sourceName)).check(matches(isDisplayed())) | ||||
| } | ||||
|  | ||||
| open class WithANRException { | ||||
|     companion object { | ||||
|         // Running count of the number of Android Not Responding dialogues to prevent endless dismissal. | ||||
|         private var anrCount = 0 | ||||
|  | ||||
|         // `RootViewWithoutFocusException` class is private, need to match the message (instead of using type matching). | ||||
|         private val rootViewWithoutFocusExceptionMsg = | ||||
|             java.lang.String.format( | ||||
|                 Locale.ROOT, | ||||
|                 "Waited for the root of the view hierarchy to have " + | ||||
|                     "window focus and not request layout for 10 seconds. If you specified a non " + | ||||
|                     "default root matcher, it may be picking a root that never takes focus. " + | ||||
|                     "Root:", | ||||
|             ) | ||||
|  | ||||
|         private fun handleAnrDialogue() { | ||||
|             val device = UiDevice.getInstance(getInstrumentation()) | ||||
|             // If running the device in English Locale | ||||
|             val waitButton = device.findObject(UiSelector().textContains("wait")) | ||||
|             if (waitButton.exists()) waitButton.click() | ||||
|         } | ||||
|  | ||||
|         @JvmStatic | ||||
|         @BeforeClass | ||||
|         fun setUpHandler() { | ||||
|             Espresso.setFailureHandler { error, viewMatcher -> | ||||
|  | ||||
|                 if (error.message!!.contains(rootViewWithoutFocusExceptionMsg) && anrCount < 3) { | ||||
|                     anrCount++ | ||||
|                     handleAnrDialogue() | ||||
|                 } else { // chain all failures down to the default espresso handler | ||||
|                     DefaultFailureHandler(getInstrumentation().targetContext).handle(error, viewMatcher) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| class MyScreenCaptureProcessor( | ||||
|     parentFolderPath: String, | ||||
| ) : BasicScreenCaptureProcessor() { | ||||
|     init { | ||||
|         this.mDefaultScreenshotPath = | ||||
|             File( | ||||
|                 File( | ||||
|                     getExternalStoragePublicDirectory(DIRECTORY_PICTURES), | ||||
|                     "selfoss_tests", | ||||
|                 ).absolutePath, | ||||
|                 "screenshots/$parentFolderPath", | ||||
|             ) | ||||
|     } | ||||
|  | ||||
|     override fun getFilename(prefix: String): String = prefix | ||||
| } | ||||
|  | ||||
| fun takeScreenshot( | ||||
|     parentFolderPath: String = "", | ||||
|     screenShotName: String, | ||||
| ) { | ||||
|     Log.d("Screenshots", "Taking screenshot of '$screenShotName'") | ||||
|     val screenCapture = Screenshot.capture() | ||||
|     val processors = setOf(MyScreenCaptureProcessor(parentFolderPath)) | ||||
|     try { | ||||
|         screenCapture.apply { | ||||
|             name = screenShotName | ||||
|             process(processors) | ||||
|         } | ||||
|         Log.d("Screenshots", "Screenshot taken") | ||||
|     } catch (ex: IOException) { | ||||
|         Log.e("Screenshots", "Could not take the screenshot", ex) | ||||
|     } | ||||
| } | ||||
|  | ||||
| class ScreenshotTakingRule : TestWatcher() { | ||||
|     override fun failed( | ||||
|         e: Throwable?, | ||||
|         description: Description, | ||||
|     ) { | ||||
|         val parentFolderPath = "failures/${description.className}" | ||||
|         takeScreenshot(parentFolderPath = parentFolderPath, screenShotName = description.methodName) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -18,14 +18,22 @@ import org.hamcrest.CoreMatchers.not | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class HomeActivityTest { | ||||
| class HomeActivityTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     @Before | ||||
|     fun init() { | ||||
|         loginAndInitHome() | ||||
|   | ||||
| @@ -17,14 +17,22 @@ import org.junit.After | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class LoginActivityTest { | ||||
| class LoginActivityTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     @Before | ||||
|     fun registerIdlingResource() { | ||||
|         IdlingRegistry | ||||
|   | ||||
| @@ -24,14 +24,22 @@ import org.hamcrest.CoreMatchers.not | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class SettingsActivityGeneralTest { | ||||
| class SettingsActivityGeneralTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     @Before | ||||
|     fun init() { | ||||
|         loginAndInitHome() | ||||
|   | ||||
| @@ -19,14 +19,22 @@ import org.hamcrest.CoreMatchers.not | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class SettingsActivityOfflineTest { | ||||
| class SettingsActivityOfflineTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     lateinit var context: Context | ||||
|  | ||||
|     @Before | ||||
|   | ||||
| @@ -17,14 +17,22 @@ import org.hamcrest.CoreMatchers.not | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class SettingsActivityReaderTest { | ||||
| class SettingsActivityReaderTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     lateinit var context: Context | ||||
|  | ||||
|     @Before | ||||
|   | ||||
| @@ -15,13 +15,22 @@ import org.hamcrest.CoreMatchers.not | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class SettingsActivityTest { | ||||
| class SettingsActivityTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     lateinit var context: Context | ||||
|  | ||||
|     @Before | ||||
|   | ||||
| @@ -18,15 +18,23 @@ import org.junit.After | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.runner.RunWith | ||||
| import java.util.UUID | ||||
|  | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| @LargeTest | ||||
| class SourcesActivityTest { | ||||
| class SourcesActivityTest : WithANRException() { | ||||
|     @get:Rule | ||||
|     val activityRule = ActivityScenarioRule(LoginActivity::class.java) | ||||
|  | ||||
|     @JvmField | ||||
|     @Rule | ||||
|     val ruleChain: RuleChain = | ||||
|         RuleChain | ||||
|             .outerRule(activityRule) | ||||
|             .around(ScreenshotTakingRule()) | ||||
|  | ||||
|     lateinit var sourceName: String | ||||
|  | ||||
|     @Before | ||||
|   | ||||
| @@ -27,3 +27,4 @@ org.gradle.caching=true | ||||
| ignoreGitVersion=false | ||||
| kotlin.native.cacheKind.iosX64=none | ||||
| org.gradle.configureondemand=true | ||||
| kotlin.jvm.target.validation.mode=IGNORE | ||||
|   | ||||
		Reference in New Issue
	
	Block a user