diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edd04783..e3476ae8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,9 @@ on: paths-ignore: - '**.md' +env: + JAVA_VERSION: '17' + jobs: test: name: 'Test Unit' @@ -21,7 +24,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/gradle-build-action@v2 with: @@ -44,6 +47,9 @@ jobs: fail-fast: false matrix: include: + - compile: 34 + target: 34 + appcompat: 1.6.1 - compile: 33 target: 33 appcompat: 1.5.1 @@ -60,7 +66,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/gradle-build-action@v2 with: @@ -82,7 +88,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/gradle-build-action@v2 with: @@ -119,14 +125,72 @@ jobs: profile: Nexus 6 script: | brew install parallel - parallel --retries 3 ::: "./gradlew sdk:connectedCheck" + parallel --retries 3 ::: "./gradlew test:connectedCheck" - if: failure() uses: actions/upload-artifact@v3 with: name: androidTest-results path: | - sdk/build/outputs/androidTest-results - sdk/build/reports/androidTests + test/build/outputs/androidTest-results + test/build/reports/androidTests + + test-minified: + name: 'Test UI Minified' + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + api-level: [29] + target: [default] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: adopt + - uses: gradle/gradle-build-action@v2 + with: + cache-read-only: false + - name: 'Cache AVD' + uses: actions/cache@v3 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-api-${{ matrix.api-level }}-target-${{ matrix.target }} + - name: 'Create AVD' + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + target: ${{ matrix.target }} + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + force-avd-creation: false + disable-animations: false + arch: x86_64 + profile: Nexus 6 + script: echo "Generated AVD snapshot for caching." + - name: 'Tests' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + target: ${{ matrix.target }} + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + force-avd-creation: false + disable-animations: true + arch: x86_64 + profile: Nexus 6 + script: | + brew install parallel + parallel --retries 3 ::: "./gradlew test:connectedCheck -P testingMinimizedBuild=true -P android.enableR8.fullMode=false" + - if: failure() + uses: actions/upload-artifact@v3 + with: + name: androidTest-minified-results + path: | + test/build/outputs/androidTest-results + test/build/reports/androidTests test-benchmark: name: 'Test Benchmark' @@ -140,7 +204,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/gradle-build-action@v2 with: @@ -174,13 +238,13 @@ jobs: disable-animations: true arch: x86_64 profile: Nexus 6 - script: ./gradlew bench:connectedReleaseAndroidTest + script: ./gradlew benchmark:connectedReleaseAndroidTest - name: Diff benchmark result id: diff-benchmark uses: ./.github/actions/android-benchmark-diff with: reference: benchmark/data/ci-benchmarkData.json - compare-with: benchmark/build/outputs/connected_android_test_additional_output/releaseAndroidTest/connected/test(AVD) - 10/com.hcaptcha.sdk.bench.test-benchmarkData.json + compare-with: benchmark/build/outputs/connected_android_test_additional_output/releaseAndroidTest/connected/test(AVD) - 10/com_hcaptcha_sdk_bench_test-benchmarkData.json - name: Log diff benchmark reuslts run: echo "${{ steps.diff-benchmark.outputs.markdown-table }}" - uses: peter-evans/find-comment@v2 @@ -215,7 +279,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/gradle-build-action@v2 with: @@ -241,7 +305,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/gradle-build-action@v2 with: diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 7703a48f..f776e392 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -7,8 +7,22 @@ There is automated testing for every `push` command through github actions (see `.github/workflows/ci.yml`). You can manually test before pushing by running both unit tests and instrumented tests: -* ```gradlew test``` -* ```gradlew connectedDebugAndroidTest``` +* `./gradlew sdk:test` +* `./gradlew test:connectedAndroidTest` +* `./gradlew test:connectedAndroidTest -P testingMinimizedBuild=true -P android.enableR8.fullMode=false` + +## Manual testing + ++ {normal,invisible,compact} -> verify -> success -> mark used ++ {normal,invisible,compact} -> verify -> success -> token timeout + ++ {normal,invisible,compact} -> verify -> touch outside -> challenge closed ++ {normal,invisible,compact} -> verify -> back button -> challenge closed + ++ {normal,invisible,compact} -> verify -> rotate device (recreate activity) -> hcaptcha gone, no callbacks fired ++ {normal,invisible,compact} -> verify -> send app to background -> open app from history again -> hcaptcha is displayed + ++ {hide dialog} -> verify -> token obtained -> mark used # Publishing diff --git a/benchmark/build.gradle b/benchmark/build.gradle index 0c487b3c..e8015157 100644 --- a/benchmark/build.gradle +++ b/benchmark/build.gradle @@ -4,7 +4,7 @@ plugins { } android { - compileSdkVersion 33 + compileSdk 34 namespace 'com.hcaptcha.sdk.bench' compileOptions { @@ -14,7 +14,7 @@ android { defaultConfig { minSdkVersion 16 - targetSdkVersion 33 + targetSdkVersion 34 testInstrumentationRunner 'androidx.benchmark.junit4.AndroidBenchmarkRunner' testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,EMULATOR,LOW-BATTERY,UNLOCKED" @@ -36,14 +36,29 @@ android { } dependencies { - androidTestImplementation 'androidx.test:runner:1.5.1' - androidTestImplementation 'androidx.test.ext:junit:1.1.4' + androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.1.1' + androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.2.0' implementation project(path: ':sdk') - implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'androidx.appcompat:appcompat:1.6.1' } // Workaround for: java.lang.ClassNotFoundException: com.android.tools.lint.client.api.Vendor -lint.enabled = false \ No newline at end of file +lint.enabled = false + +tasks.register('pullBenchmarkData', Exec) { + def packageName = android.namespace + ".test" + + commandLine java.nio.file.Paths.get(android.sdkDirectory.absolutePath, "platform-tools", "adb"), + "pull", + "/storage/emulated/0/Android/media/" \ + + "${packageName}/additional_test_output/" \ + + "${packageName.replace('.', '_')}-benchmarkData.json", + "${projectDir}/build/outputs/" + + doFirst { + println "pullBenchmarkData: ${commandLine.join(' ')}" + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 562958a8..292133d2 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,9 @@ buildscript { maven { url 'https://jitpack.io' } } dependencies { - classpath 'com.android.tools.build:gradle:7.2.2' - classpath 'androidx.benchmark:benchmark-gradle-plugin:1.1.1' + classpath 'com.android.tools.build:gradle:8.1.3' + classpath 'androidx.benchmark:benchmark-gradle-plugin:1.2.0' + classpath 'com.slack.keeper:keeper:0.15.0' } } diff --git a/example-app/build.gradle b/example-app/build.gradle index dc4c3f08..fbc7f607 100644 --- a/example-app/build.gradle +++ b/example-app/build.gradle @@ -9,14 +9,12 @@ def prop(name, fallback) { } android { - compileSdkVersion intProp("exampleCompileSdkVersion", 32) - buildToolsVersion "30.0.3" + compileSdk intProp("exampleCompileSdkVersion", 34) namespace 'com.hcaptcha.example' defaultConfig { - applicationId "com.hcaptcha.example" minSdkVersion 16 - targetSdkVersion intProp("exampleTargetSdkVersion", 32) + targetSdkVersion intProp("exampleTargetSdkVersion", 34) versionCode 1 versionName "0.0.1" diff --git a/example-app/src/main/java/com/hcaptcha/example/App.java b/example-app/src/main/java/com/hcaptcha/example/App.java index d783b16a..28bc8ff8 100644 --- a/example-app/src/main/java/com/hcaptcha/example/App.java +++ b/example-app/src/main/java/com/hcaptcha/example/App.java @@ -8,7 +8,7 @@ public class App extends Application { public void onCreate() { super.onCreate(); - if (BuildConfig.DEBUG) { + if (com.hcaptcha.sdk.BuildConfig.DEBUG) { StrictMode.setThreadPolicy( new StrictMode.ThreadPolicy.Builder() .detectAll() diff --git a/gradle.properties b/gradle.properties index 710b2f09..2b1e584a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,5 @@ org.gradle.jvmargs=-Xmx2048m android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true -# Software Components will not be created automatically for Maven publishing from Android Gradle Plugin 8.0 -android.disableAutomaticComponentCreation=true # To test more aggressive optimizations android.enableR8.fullMode=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661e..84a0b92f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/sdk/build.gradle b/sdk/build.gradle index 7901da5d..84535379 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -1,23 +1,25 @@ plugins { + id "com.android.library" id "pmd" id "jacoco" id "checkstyle" - id "com.github.spotbugs" version "4.8.0" + id "maven-publish" + id "com.github.spotbugs" version "5.2.3" id "org.owasp.dependencycheck" version "7.1.1" id "org.sonarqube" version "3.4.0.2513" } -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' - android { - compileSdkVersion 33 - buildToolsVersion "30.0.3" + compileSdk 34 namespace 'com.hcaptcha.sdk' + buildFeatures { + buildConfig true + } + defaultConfig { minSdkVersion 16 - targetSdkVersion 33 + targetSdkVersion 34 // See https://developer.android.com/studio/publish/versioning // versionCode must be integer and be incremented by one for every new update @@ -30,10 +32,8 @@ android { buildConfigField 'String', 'VERSION_NAME', "\"${defaultConfig.versionName}_${defaultConfig.versionCode}\"" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - multiDexEnabled true } compileOptions { @@ -65,27 +65,15 @@ android { } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) //noinspection GradleDependency implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' - compileOnly 'org.projectlombok:lombok:1.18.16' - annotationProcessor 'org.projectlombok:lombok:1.18.16' + compileOnly 'org.projectlombok:lombok:1.18.30' + annotationProcessor 'org.projectlombok:lombok:1.18.30' testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-inline:3.6.28' - testImplementation 'org.skyscreamer:jsonassert:1.5.0' - - androidTestImplementation 'androidx.test:core:1.5.0' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test:rules:1.5.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation 'androidx.test.espresso:espresso-web:3.5.1' - androidTestImplementation 'androidx.fragment:fragment-testing:1.4.1' // cannot upgrade because https://issuetracker.google.com/issues/266687550 - - androidTestImplementation "androidx.multidex:multidex:2.0.1" - androidTestImplementation "org.mockito:mockito-android:3.6.28" + testImplementation 'org.mockito:mockito-inline:4.8.1' + testImplementation 'org.skyscreamer:jsonassert:1.5.1' compileOnly 'com.google.code.findbugs:annotations:3.0.1' } @@ -143,8 +131,8 @@ android.libraryVariants.all { variant -> dependsOn variant.packageLibraryProvider doFirst { - String aarPath = variant.packageLibraryProvider.get().archivePath - long aarSizeKb = file(aarPath).length() / 1024 + var aarPath = variant.packageLibraryProvider.get().archiveFile.get().getAsFile() + long aarSizeKb = aarPath.length() / 1024 println("File ${aarPath} is ${aarSizeKb}Kbyte") } } @@ -155,8 +143,8 @@ android.libraryVariants.all { variant -> dependsOn variant.packageLibraryProvider doFirst { - String aarPath = variant.packageLibraryProvider.get().archivePath - long aarSizeKb = file(aarPath).length() / 1024 + var aarFile = variant.packageLibraryProvider.get().archiveFile.get().getAsFile() + long aarSizeKb = aarFile.length() / 1024 if (aarSizeKb > MAX_AAR_SIZE_KB) { throw new GradleException("${aarPath} size exceeded! ${aarSizeKb}Kbyte > ${MAX_AAR_SIZE_KB}Kbyte") } @@ -244,8 +232,8 @@ spotbugs { gradle.taskGraph.beforeTask { task -> if (task.name.toLowerCase().contains('spotbugs')) { task.reports { - html.enabled = true - xml.enabled = true + html.enabled true + xml.enabled true } } } @@ -271,8 +259,8 @@ task jacocoUnitTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) executionData.from = "${project.buildDir}/jacoco/testDebugUnitTest.exec" reports { - xml.enabled = true - html.enabled = true + xml.required = true + html.required = true } } @@ -289,7 +277,7 @@ sonarqube { property "sonar.sources", "src/main" property "sonar.java.binaries", "${project.buildDir}/intermediates/javac/debug/classes" - property "sonar.tests", ["src/test/", "src/androidTest/"] + property "sonar.tests", ["src/test/", "../test/src/androidTest/"] property "sonar.android.lint.report", "${project.buildDir}/outputs/lint-results.xml" property "sonar.java.spotbugs.reportPaths", ["${project.buildDir}/reports/spotbugs/debug.xml", "${project.buildDir}/reports/spotbugs/release.xml"] @@ -300,3 +288,4 @@ sonarqube { } project.tasks["sonarqube"].dependsOn "check" + diff --git a/sdk/consumer-rules.pro b/sdk/consumer-rules.pro index 8d5fa2b0..d08a981c 100644 --- a/sdk/consumer-rules.pro +++ b/sdk/consumer-rules.pro @@ -1,6 +1,10 @@ -dontwarn javax.annotation.processing.** -dontwarn lombok.core.configuration.** -dontwarn org.apache.tools.** +-dontwarn android.content.pm.PackageManager$ApplicationInfoFlags +-dontwarn edu.umd.cs.findbugs.annotations.* +-dontwarn java.beans.* +-dontwarn lombok.* # Prevent obfuscating the names when serializing to JSON -keep class com.hcaptcha.sdk.HCaptchaConfig { *; } diff --git a/sdk/src/androidTest/AndroidManifest.xml b/sdk/src/androidTest/AndroidManifest.xml deleted file mode 100644 index f3d6cf30..00000000 --- a/sdk/src/androidTest/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/ExampleInstrumentedTest.java b/sdk/src/androidTest/java/com/hcaptcha/sdk/ExampleInstrumentedTest.java deleted file mode 100644 index 7fc12d44..00000000 --- a/sdk/src/androidTest/java/com/hcaptcha/sdk/ExampleInstrumentedTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.hcaptcha.sdk; - -import static org.junit.Assert.assertEquals; - -import android.content.Context; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - final Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); - assertEquals("com.hcaptcha.sdk.test", appContext.getPackageName()); - } -} diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/TestActivity.java b/sdk/src/androidTest/java/com/hcaptcha/sdk/TestActivity.java deleted file mode 100644 index 64d17547..00000000 --- a/sdk/src/androidTest/java/com/hcaptcha/sdk/TestActivity.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.hcaptcha.sdk; - -import androidx.fragment.app.FragmentActivity; - -public class TestActivity extends FragmentActivity { -} diff --git a/sdk/src/test/java/com/hcaptcha/sdk/HCaptchaTest.java b/sdk/src/test/java/com/hcaptcha/sdk/HCaptchaTest.java index ac5136d5..620dd902 100644 --- a/sdk/src/test/java/com/hcaptcha/sdk/HCaptchaTest.java +++ b/sdk/src/test/java/com/hcaptcha/sdk/HCaptchaTest.java @@ -125,11 +125,11 @@ public void test_verify_with_hcaptcha_passes_site_key_as_config() { final String siteKey = HCaptchaConfigTest.MOCK_SITE_KEY; final HCaptcha hCaptcha = HCaptcha.getClient(fragmentActivity); - dialogFragmentMock.verify(never(), () -> + dialogFragmentMock.verify(() -> HCaptchaDialogFragment.newInstance( any(HCaptchaConfig.class), any(HCaptchaInternalConfig.class), - any(HCaptchaStateListener.class))); + any(HCaptchaStateListener.class)), never()); hCaptcha.verifyWithHCaptcha(siteKey); @@ -199,11 +199,11 @@ public void test_verify_config_has_priority_over_setup_config() throws Exception .verifyWithHCaptcha(verifyConfig); verify(packageManager, never()).getApplicationInfo(any(String.class), anyInt()); - dialogFragmentMock.verify(times(2), () -> + dialogFragmentMock.verify(() -> HCaptchaDialogFragment.newInstance( hCaptchaConfigCaptor.capture(), any(HCaptchaInternalConfig.class), - any(HCaptchaStateListener.class))); + any(HCaptchaStateListener.class)), times(2)); assertEquals(verifyConfig, hCaptchaConfigCaptor.getValue()); } @@ -216,11 +216,11 @@ public void test_verify_site_key_has_priority_over_setup_config() throws Excepti .verifyWithHCaptcha(siteKey); verify(packageManager, never()).getApplicationInfo(any(String.class), anyInt()); - dialogFragmentMock.verify(times(2), () -> + dialogFragmentMock.verify(() -> HCaptchaDialogFragment.newInstance( hCaptchaConfigCaptor.capture(), any(HCaptchaInternalConfig.class), - any(HCaptchaStateListener.class))); + any(HCaptchaStateListener.class)), times(2)); assertEquals(siteKey, hCaptchaConfigCaptor.getValue().getSiteKey()); } diff --git a/settings.gradle b/settings.gradle index 96e2fce7..892e2df7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ -include ':example-app' -include ':sdk' rootProject.name = "hcaptcha-android-sdk" +include ':sdk' +include ':test' include ':benchmark' +include ':example-app' diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +/build diff --git a/test/build.gradle b/test/build.gradle new file mode 100644 index 00000000..e4387dca --- /dev/null +++ b/test/build.gradle @@ -0,0 +1,61 @@ +apply plugin: 'com.android.application' +if (project.hasProperty("testingMinimizedBuild")) { + apply plugin: 'com.slack.keeper' +} + +android { + compileSdk 34 + namespace 'com.hcaptcha.sdk.test' + + defaultConfig { + applicationId "com.hcaptcha.sdk.test" + minSdkVersion 19 + targetSdkVersion 34 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + signingConfig signingConfigs.debug + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android.txt'), '../sdk/consumer-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testBuildType = project.hasProperty("testingMinimizedBuild") ? "release" : "debug" +} + +androidComponents { + beforeVariants(selector().all()) { variantBuilder -> + if (variantBuilder.name == "release") { + variantBuilder.registerExtension( + com.slack.keeper.KeeperVariantMarker.class, + com.slack.keeper.KeeperVariantMarker.INSTANCE) + } + } +} + +dependencies { + implementation project(path: ':sdk') + implementation 'androidx.appcompat:appcompat:1.6.1' + + testImplementation 'junit:junit:4.13.2' + + androidTestImplementation 'androidx.fragment:fragment-testing:1.6.2' + androidTestImplementation 'androidx.test:core:1.5.0' + androidTestImplementation 'androidx.test:rules:1.5.0' + androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'androidx.test.espresso:espresso-web:3.5.1' + androidTestImplementation 'org.mockito:mockito-android:5.3.1' +} diff --git a/test/proguard-rules.pro b/test/proguard-rules.pro new file mode 100644 index 00000000..e23fa22e --- /dev/null +++ b/test/proguard-rules.pro @@ -0,0 +1 @@ +# Proguard rules that are applied to your test apk/code. diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/AssertUtil.java b/test/src/androidTest/java/com/hcaptcha/sdk/AssertUtil.java similarity index 100% rename from sdk/src/androidTest/java/com/hcaptcha/sdk/AssertUtil.java rename to test/src/androidTest/java/com/hcaptcha/sdk/AssertUtil.java diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaDialogFragmentTest.java b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaDialogFragmentTest.java similarity index 97% rename from sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaDialogFragmentTest.java rename to test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaDialogFragmentTest.java index 3cd4f57b..c4ef51c4 100644 --- a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaDialogFragmentTest.java +++ b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaDialogFragmentTest.java @@ -41,6 +41,9 @@ import androidx.test.espresso.web.webdriver.Locator; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.hcaptcha.sdk.test.TestActivity; + +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; @@ -217,6 +220,8 @@ void onFailure(HCaptchaException exception) { @Test public void webViewNotInstalled() throws InterruptedException { + Assume.assumeTrue("Skip test for release, because impossible to mock LayoutInflater", BuildConfig.DEBUG); + final LayoutInflater inflater = mock(LayoutInflater.class); when(inflater.inflate(eq(R.layout.hcaptcha_fragment), any(), eq(false))) .thenThrow(InflateException.class); @@ -350,13 +355,14 @@ public void testVerifyOnStoppedFragmentNoException() throws InterruptedException @Test(expected = IllegalArgumentException.class) public void testReset() { - final FragmentScenario scenario = launchInContainer( - config, new HCaptchaStateTestAdapter()); + try (final FragmentScenario scenario = launchInContainer( + config, new HCaptchaStateTestAdapter())) { - scenario.onFragment(HCaptchaDialogFragment::reset); + scenario.onFragment(HCaptchaDialogFragment::reset); - // The fragment has been removed from the FragmentManager already. - scenario.onFragment(fragment -> assertTrue(fragment.isDetached())); + // The fragment has been removed from the FragmentManager already. + scenario.onFragment(fragment -> assertTrue(fragment.isDetached())); + } } @Test diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaHeadlessWebViewTest.java b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaHeadlessWebViewTest.java similarity index 99% rename from sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaHeadlessWebViewTest.java rename to test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaHeadlessWebViewTest.java index 9dc2073d..45bafe1d 100644 --- a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaHeadlessWebViewTest.java +++ b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaHeadlessWebViewTest.java @@ -13,6 +13,8 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.hcaptcha.sdk.test.TestActivity; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaStateTestAdapter.java b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaStateTestAdapter.java similarity index 100% rename from sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaStateTestAdapter.java rename to test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaStateTestAdapter.java diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java similarity index 97% rename from sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java rename to test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java index d8088bbd..1754eb8d 100644 --- a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java +++ b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java @@ -9,6 +9,8 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule; import com.hcaptcha.sdk.tasks.OnSuccessListener; +import com.hcaptcha.sdk.test.TestActivity; + import org.junit.Rule; import org.junit.Test; @@ -99,7 +101,7 @@ public void e2eWithDebugTokenFragmentDialog() throws Exception { response.markUsed(); latch.countDown(); }) - .addOnFailureListener(exception -> fail("No errors expected"))); + .addOnFailureListener(exception -> fail("No errors expected but received: " + exception.getHCaptchaError()))); assertTrue(latch.await(E2E_AWAIT_CALLBACK_MS, TimeUnit.MILLISECONDS)); } diff --git a/sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTestHtml.java b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTestHtml.java similarity index 100% rename from sdk/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTestHtml.java rename to test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTestHtml.java diff --git a/test/src/main/AndroidManifest.xml b/test/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d9151625 --- /dev/null +++ b/test/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/src/main/java/com/hcaptcha/sdk/test/TestActivity.java b/test/src/main/java/com/hcaptcha/sdk/test/TestActivity.java new file mode 100644 index 00000000..0287f9a1 --- /dev/null +++ b/test/src/main/java/com/hcaptcha/sdk/test/TestActivity.java @@ -0,0 +1,4 @@ +package com.hcaptcha.sdk.test; + +public class TestActivity extends androidx.appcompat.app.AppCompatActivity { +} \ No newline at end of file diff --git a/test/src/main/res/drawable/ic_launcher_background.xml b/test/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/test/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..317d6ccf Binary files /dev/null and b/test/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/test/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b45165c8 Binary files /dev/null and b/test/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/test/src/main/res/values/strings.xml b/test/src/main/res/values/strings.xml new file mode 100644 index 00000000..fde7ba53 --- /dev/null +++ b/test/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + test + \ No newline at end of file