diff --git a/.changeset/funny-humans-divide.md b/.changeset/funny-humans-divide.md new file mode 100644 index 000000000..83e8d006a --- /dev/null +++ b/.changeset/funny-humans-divide.md @@ -0,0 +1,7 @@ +--- +"posthog": minor +"posthog-android": patch +"posthog-android-surveys-compose": minor +--- + +Support skipSubmitButton for survey rating and single-choice questions. The Compose renderer submits eligible selections immediately and hides the submit button; multiple-choice questions and single-choice questions with an open option retain explicit submission. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 75dd5cdfa..eb15b9b78 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,6 +53,10 @@ jobs: if: needs.detect-markdown-only.outputs.markdown_only != 'true' run: make compile + - name: Test survey interactions + if: needs.detect-markdown-only.outputs.markdown_only != 'true' + run: make testSurveyUI + - name: Check release tasks and dependency locks if: needs.detect-markdown-only.outputs.markdown_only != 'true' run: make checkRelease diff --git a/Makefile b/Makefile index e6e8cead8..ef8b3dc8f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: clean compile stop checkFormat format api dryRelease release testReport test testJava generateLintBaseLine checkRelease updateLocks +.PHONY: clean compile stop checkFormat format api dryRelease release testReport test testJava generateLintBaseLine checkRelease updateLocks testSurveyUI clean: ./gradlew clean @@ -63,6 +63,10 @@ testReport: test: ./gradlew testDebugUnitTest +# Mounted Compose tests need the debug-only test host, which CI builds normally skip. +testSurveyUI: + CI=false ./gradlew :posthog-android-surveys-compose:testDebugUnitTest + # compile already runs the tests (tests only java) testJava: ./gradlew :posthog:test diff --git a/posthog-android-surveys-compose/build.gradle.kts b/posthog-android-surveys-compose/build.gradle.kts index 328b0266f..d139467f3 100644 --- a/posthog-android-surveys-compose/build.gradle.kts +++ b/posthog-android-surveys-compose/build.gradle.kts @@ -29,6 +29,10 @@ android { } } + testOptions { + unitTests.isIncludeAndroidResources = true + } + buildFeatures { compose = true } @@ -91,6 +95,10 @@ dependencies { // tests testImplementation("junit:junit:${PosthogBuildConfig.Dependencies.ANDROIDX_JUNIT}") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:${PosthogBuildConfig.Kotlin.KOTLIN}") + testImplementation("androidx.test.ext:junit:${PosthogBuildConfig.Dependencies.ANDROIDX_JUNIT}") + testImplementation("org.robolectric:robolectric:${PosthogBuildConfig.Dependencies.ROBOLECTRIC}") + testImplementation("androidx.compose.ui:ui-test-junit4") + debugImplementation("androidx.compose.ui:ui-test-manifest") } project.publishingAndroidConfig() diff --git a/posthog-android-surveys-compose/gradle.lockfile b/posthog-android-surveys-compose/gradle.lockfile index d7e5faaf7..24da799b1 100644 --- a/posthog-android-surveys-compose/gradle.lockfile +++ b/posthog-android-surveys-compose/gradle.lockfile @@ -39,6 +39,11 @@ androidx.compose.ui:ui-geometry-android:1.7.0=debugAndroidTestCompileClasspath,d androidx.compose.ui:ui-geometry:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose.ui:ui-graphics-android:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose.ui:ui-graphics:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.compose.ui:ui-test-android:1.7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.compose.ui:ui-test-junit4-android:1.7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.compose.ui:ui-test-junit4:1.7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.compose.ui:ui-test-manifest:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath +androidx.compose.ui:ui-test:1.7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose.ui:ui-text-android:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose.ui:ui-text:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose.ui:ui-tooling-android:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath @@ -53,7 +58,8 @@ androidx.compose.ui:ui-util-android:1.7.0=debugAndroidTestCompileClasspath,debug androidx.compose.ui:ui-util:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose.ui:ui:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.compose:compose-bom:2024.09.00=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.concurrent:concurrent-futures:1.1.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.concurrent:concurrent-futures-ktx:1.1.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.concurrent:concurrent-futures:1.1.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.core:core-ktx:1.13.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.core:core:1.13.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.customview:customview-poolingcontainer:1.0.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath @@ -79,8 +85,18 @@ androidx.profileinstaller:profileinstaller:1.3.1=debugAndroidTestRuntimeClasspat androidx.savedstate:savedstate-ktx:1.2.1=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.savedstate:savedstate:1.2.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.startup:startup-runtime:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.tracing:tracing:1.0.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.test.espresso:espresso-core:3.5.0=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.test.espresso:espresso-idling-resource:3.6.1=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.test.ext:junit:1.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test.services:storage:1.5.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:annotation:1.0.1=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.test:core:1.6.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:monitor:1.7.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:runner:1.5.0=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.tracing:tracing:1.0.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,releaseRuntimeClasspath +androidx.tracing:tracing:1.1.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.almworks.sqlite4java:sqlite4java:1.0.392=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.ddms:ddmlib:31.9.1=_internal-unified-test-platform-android-device-provider-ddmlib com.android.tools.emulator:proto:31.9.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention com.android.tools.utp:android-device-provider-ddmlib-proto:31.9.1=_internal-unified-test-platform-android-device-provider-ddmlib @@ -120,18 +136,24 @@ com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-t com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core com.google.auto.service:auto-service-annotations:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.auto.service:auto-service:1.1.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.auto.value:auto-value-annotations:1.11.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.auto:auto-common:1.2.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.google.code.gson:gson:2.8.9=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-launcher com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control com.google.dagger:dagger:2.48=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +com.google.errorprone:error_prone_annotation:2.34.0=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath com.google.errorprone:error_prone_annotations:2.23.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.errorprone:error_prone_annotations:2.28.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:failureaccess:1.0.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher -com.google.guava:listenablefuture:1.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.guava:guava:33.3.1-jre=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:listenablefuture:1.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,releaseRuntimeClasspath +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +com.google.j2objc:j2objc-annotations:3.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.protobuf:protobuf-java-util:3.22.3=_internal-unified-test-platform-core com.google.protobuf:protobuf-java-util:3.24.4=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher com.google.protobuf:protobuf-java:3.24.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher @@ -142,11 +164,14 @@ com.google.testing.platform:android-test-plugin:0.0.9-alpha03=_internal-unified- com.google.testing.platform:core-proto:0.0.9-alpha03=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle com.google.testing.platform:core:0.0.9-alpha03=_internal-unified-test-platform-core com.google.testing.platform:launcher:0.0.9-alpha03=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +com.google.testparameterinjector:test-parameter-injector:1.18=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.ibm.icu:icu4j:75.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.squareup.curtains:curtains:1.2.5=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.squareup.okhttp3:okhttp-bom:4.12.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.squareup.okhttp3:okhttp:4.12.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.squareup.okio:okio-jvm:3.6.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.squareup.okio:okio:3.6.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.squareup:javawriter:2.1.1=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath commons-io:commons-io:2.16.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention io.grpc:grpc-api:1.57.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core io.grpc:grpc-context:1.57.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core @@ -173,17 +198,22 @@ io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plu it.unimi.dsi:fastutil-core:8.5.12=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin jakarta.activation:jakarta.activation-api:1.2.1=dokkaGfmPartialRuntime,dokkaGfmRuntime,dokkaHtmlPartialRuntime,dokkaHtmlRuntime,dokkaJavadocPartialRuntime,dokkaJavadocRuntime,dokkaJekyllPartialRuntime,dokkaJekyllRuntime jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=dokkaGfmPartialRuntime,dokkaGfmRuntime,dokkaHtmlPartialRuntime,dokkaHtmlRuntime,dokkaJavadocPartialRuntime,dokkaJavadocRuntime,dokkaJekyllPartialRuntime,dokkaJekyllRuntime -javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle -javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core +javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +javax.inject:javax.inject:1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath,testImplementationDependenciesMetadata net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib +org.bouncycastle:bcprov-jdk18on:1.78.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher +org.checkerframework:checker-qual:3.43.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core org.codehaus.woodstox:stax2-api:4.2.1=dokkaGfmPartialRuntime,dokkaGfmRuntime,dokkaHtmlPartialRuntime,dokkaHtmlRuntime,dokkaJavadocPartialRuntime,dokkaJavadocRuntime,dokkaJekyllPartialRuntime,dokkaJekyllRuntime +org.conscrypt:conscrypt-openjdk-uber:2.5.2=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.freemarker:freemarker:2.3.32=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath,testImplementationDependenciesMetadata +org.hamcrest:hamcrest-integration:1.3=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.hamcrest:hamcrest-library:1.3=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.dokka:analysis-kotlin-descriptors:1.9.20=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin org.jetbrains.dokka:analysis-markdown:1.9.20=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin org.jetbrains.dokka:dokka-base:1.9.20=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin @@ -233,12 +263,33 @@ org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=_internal-unified-test-platfo org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,dokkaGfmPartialPlugin,dokkaGfmPartialRuntime,dokkaGfmPlugin,dokkaGfmRuntime,dokkaHtmlPartialPlugin,dokkaHtmlPartialRuntime,dokkaHtmlPlugin,dokkaHtmlRuntime,dokkaJavadocPartialPlugin,dokkaJavadocPartialRuntime,dokkaJavadocPlugin,dokkaJavadocRuntime,dokkaJekyllPartialPlugin,dokkaJekyllPartialRuntime,dokkaJekyllPlugin,dokkaJekyllRuntime,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,dokkaGfmPartialPlugin,dokkaGfmPartialRuntime,dokkaGfmPlugin,dokkaGfmRuntime,dokkaHtmlPartialPlugin,dokkaHtmlPartialRuntime,dokkaHtmlPlugin,dokkaHtmlRuntime,dokkaJavadocPartialPlugin,dokkaJavadocPartialRuntime,dokkaJavadocPlugin,dokkaJavadocRuntime,dokkaJekyllPartialPlugin,dokkaJekyllPartialRuntime,dokkaJekyllPlugin,dokkaJekyllRuntime,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm:1.7.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-html-jvm:0.9.1=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,_internal-unified-test-platform-core,_internal-unified-test-platform-launcher,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,dokkaGfmPartialPlugin,dokkaGfmPartialRuntime,dokkaGfmPlugin,dokkaGfmRuntime,dokkaHtmlPartialPlugin,dokkaHtmlPartialRuntime,dokkaHtmlPlugin,dokkaHtmlRuntime,dokkaJavadocPartialPlugin,dokkaJavadocPartialRuntime,dokkaJavadocPlugin,dokkaJavadocRuntime,dokkaJekyllPartialPlugin,dokkaJekyllPartialRuntime,dokkaJekyllPlugin,dokkaJekyllRuntime,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains:markdown-jvm:0.5.2=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin org.jetbrains:markdown:0.5.2=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin org.jsoup:jsoup:1.16.1=dokkaGfmPartialPlugin,dokkaGfmPlugin,dokkaHtmlPartialPlugin,dokkaHtmlPlugin,dokkaJavadocPartialPlugin,dokkaJavadocPlugin,dokkaJekyllPartialPlugin,dokkaJekyllPlugin +org.ow2.asm:asm-analysis:9.7.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm-commons:9.7.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-tree:9.6=bcv-rt-jvm-cp-resolver +org.ow2.asm:asm-tree:9.7.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm-util:9.7.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm:9.6=bcv-rt-jvm-cp-resolver +org.ow2.asm:asm:9.7.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:annotations:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:junit:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:nativeruntime-dist-compat:1.0.16=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:nativeruntime:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:pluginapi:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:plugins-maven-dependency-resolver:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:resources:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:robolectric:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:sandbox:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:shadowapi:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:shadows-framework:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:utils-reflector:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:utils:4.14.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.yaml:snakeyaml:2.3=debugUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath empty=androidApis,androidJdkImage,androidTestApiDependenciesMetadata,androidTestCompileOnlyDependenciesMetadata,androidTestDebugApiDependenciesMetadata,androidTestDebugCompileOnlyDependenciesMetadata,androidTestDebugImplementationDependenciesMetadata,androidTestDebugIntransitiveDependenciesMetadata,androidTestImplementationDependenciesMetadata,androidTestIntransitiveDependenciesMetadata,androidTestReleaseApiDependenciesMetadata,androidTestReleaseCompileOnlyDependenciesMetadata,androidTestReleaseImplementationDependenciesMetadata,androidTestReleaseIntransitiveDependenciesMetadata,androidTestUtil,compileOnlyDependenciesMetadata,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestApiDependenciesMetadata,debugAndroidTestCompileOnlyDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestIntransitiveDependenciesMetadata,debugAnnotationProcessorClasspath,debugApiDependenciesMetadata,debugCompileOnlyDependenciesMetadata,debugIntransitiveDependenciesMetadata,debugUnitTestAnnotationProcessorClasspath,debugUnitTestApiDependenciesMetadata,debugUnitTestCompileOnlyDependenciesMetadata,debugUnitTestImplementationDependenciesMetadata,debugUnitTestIntransitiveDependenciesMetadata,dokkaPlugin,dokkaRuntime,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,lintChecks,lintPublish,releaseAnnotationProcessorClasspath,releaseApiDependenciesMetadata,releaseCompileOnlyDependenciesMetadata,releaseImplementationDependenciesMetadata,releaseIntransitiveDependenciesMetadata,releaseUnitTestAnnotationProcessorClasspath,releaseUnitTestApiDependenciesMetadata,releaseUnitTestCompileOnlyDependenciesMetadata,releaseUnitTestImplementationDependenciesMetadata,releaseUnitTestIntransitiveDependenciesMetadata,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testDebugApiDependenciesMetadata,testDebugCompileOnlyDependenciesMetadata,testDebugImplementationDependenciesMetadata,testDebugIntransitiveDependenciesMetadata,testFixturesApiDependenciesMetadata,testFixturesCompileOnlyDependenciesMetadata,testFixturesDebugApiDependenciesMetadata,testFixturesDebugCompileOnlyDependenciesMetadata,testFixturesDebugImplementationDependenciesMetadata,testFixturesDebugIntransitiveDependenciesMetadata,testFixturesImplementationDependenciesMetadata,testFixturesIntransitiveDependenciesMetadata,testFixturesReleaseApiDependenciesMetadata,testFixturesReleaseCompileOnlyDependenciesMetadata,testFixturesReleaseImplementationDependenciesMetadata,testFixturesReleaseIntransitiveDependenciesMetadata,testIntransitiveDependenciesMetadata,testReleaseApiDependenciesMetadata,testReleaseCompileOnlyDependenciesMetadata,testReleaseImplementationDependenciesMetadata,testReleaseIntransitiveDependenciesMetadata diff --git a/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SingleChoice.kt b/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SingleChoice.kt index 61c231c0e..0d13c425d 100644 --- a/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SingleChoice.kt +++ b/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SingleChoice.kt @@ -20,6 +20,9 @@ import com.posthog.surveys.PostHogDisplayChoiceQuestion import com.posthog.surveys.PostHogDisplaySurveyAppearance import com.posthog.surveys.PostHogDisplaySurveyTextContentType +internal val PostHogDisplayChoiceQuestion.shouldAutoSubmit: Boolean + get() = skipSubmitButton && !isMultipleChoice && !hasOpenChoice + /** * Single-choice list renderer for [PostHogDisplayChoiceQuestion]s where * [PostHogDisplayChoiceQuestion.isMultipleChoice] is `false`. diff --git a/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SurveySheet.kt b/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SurveySheet.kt index e39ffd400..2f09456f3 100644 --- a/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SurveySheet.kt +++ b/posthog-android-surveys-compose/src/main/java/com/posthog/android/surveys/compose/internal/ui/SurveySheet.kt @@ -237,26 +237,34 @@ private fun RatingQuestionDispatch( ) { var rating by rememberSaveable(question.id) { mutableStateOf(null) } val canSubmit = question.isOptional || rating != null + val onRatingSelected: (Int?) -> Unit = { value -> + rating = value + if (question.skipSubmitButton && value != null) { + onSubmit(PostHogSurveyResponse.Rating(value)) + } + } QuestionHeader(question) if (question.ratingType == PostHogDisplaySurveyRatingType.EMOJI) { EmojiRating( question = question, selectedValue = rating, - onSelect = { rating = it }, + onSelect = onRatingSelected, ) } else { NumberRating( question = question, selectedValue = rating, - onSelect = { rating = it }, + onSelect = onRatingSelected, + ) + } + if (!question.skipSubmitButton) { + BottomSection( + label = question.buttonText ?: localAppearance().submitButtonText, + enabled = canSubmit, + onClick = { onSubmit(PostHogSurveyResponse.Rating(rating)) }, ) } - BottomSection( - label = question.buttonText ?: localAppearance().submitButtonText, - enabled = canSubmit, - onClick = { onSubmit(PostHogSurveyResponse.Rating(rating)) }, - ) } @Composable @@ -313,18 +321,25 @@ private fun SingleChoiceQuestionDispatch( SingleChoice( question = question, selectedChoice = selected, - onSelectedChoiceChange = { selected = it }, + onSelectedChoiceChange = { value -> + selected = value + if (question.shouldAutoSubmit && value != null) { + onSubmit(PostHogSurveyResponse.SingleChoice(value)) + } + }, openChoiceInput = openInput, onOpenChoiceInputChange = { openInput = it }, ) - BottomSection( - label = question.buttonText ?: localAppearance().submitButtonText, - enabled = canSubmit, - onClick = { - val response = if (hasOpenChoiceSelected) openInput.trim() else selected - onSubmit(PostHogSurveyResponse.SingleChoice(response)) - }, - ) + if (!question.shouldAutoSubmit) { + BottomSection( + label = question.buttonText ?: localAppearance().submitButtonText, + enabled = canSubmit, + onClick = { + val response = if (hasOpenChoiceSelected) openInput.trim() else selected + onSubmit(PostHogSurveyResponse.SingleChoice(response)) + }, + ) + } } @Composable diff --git a/posthog-android-surveys-compose/src/test/java/com/posthog/android/surveys/compose/internal/ui/SurveyAutoSubmitTest.kt b/posthog-android-surveys-compose/src/test/java/com/posthog/android/surveys/compose/internal/ui/SurveyAutoSubmitTest.kt new file mode 100644 index 000000000..532a6953e --- /dev/null +++ b/posthog-android-surveys-compose/src/test/java/com/posthog/android/surveys/compose/internal/ui/SurveyAutoSubmitTest.kt @@ -0,0 +1,45 @@ +package com.posthog.android.surveys.compose.internal.ui + +import com.posthog.surveys.PostHogDisplayChoiceQuestion +import com.posthog.surveys.PostHogDisplaySurveyTextContentType +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import kotlin.test.assertEquals + +@RunWith(Parameterized::class) +internal class SurveyAutoSubmitTest( + private val enabled: Boolean, + private val multiple: Boolean, + private val openChoice: Boolean, + private val expected: Boolean, +) { + @Test + fun `only single choice without an open option auto-submits`() { + val question = + PostHogDisplayChoiceQuestion( + id = "question", question = "Choose", questionDescription = null, + questionDescriptionContentType = PostHogDisplaySurveyTextContentType.TEXT, + isOptional = false, buttonText = null, choices = listOf("First", "Other"), + hasOpenChoice = openChoice, shuffleOptions = false, isMultipleChoice = multiple, + skipSubmitButton = enabled, + ) + assertEquals(expected, question.shouldAutoSubmit) + } + + companion object { + @JvmStatic + @Parameterized.Parameters(name = "enabled={0}, multiple={1}, open={2}") + fun cases(): List> = + listOf( + arrayOf(true, false, false, true), + arrayOf(true, false, true, false), + arrayOf(true, true, false, false), + arrayOf(true, true, true, false), + arrayOf(false, false, false, false), + arrayOf(false, false, true, false), + arrayOf(false, true, false, false), + arrayOf(false, true, true, false), + ) + } +} diff --git a/posthog-android-surveys-compose/src/testDebug/java/com/posthog/android/surveys/compose/internal/ui/SurveyAutoSubmitInteractionTest.kt b/posthog-android-surveys-compose/src/testDebug/java/com/posthog/android/surveys/compose/internal/ui/SurveyAutoSubmitInteractionTest.kt new file mode 100644 index 000000000..72a8009f9 --- /dev/null +++ b/posthog-android-surveys-compose/src/testDebug/java/com/posthog/android/surveys/compose/internal/ui/SurveyAutoSubmitInteractionTest.kt @@ -0,0 +1,163 @@ +package com.posthog.android.surveys.compose.internal.ui + +import androidx.compose.material3.MaterialTheme +import androidx.compose.ui.semantics.SemanticsProperties +import androidx.compose.ui.test.SemanticsMatcher +import androidx.compose.ui.test.assertCountEquals +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsEnabled +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.hasClickAction +import androidx.compose.ui.test.hasSetTextAction +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performTextInput +import com.posthog.surveys.PostHogDisplayChoiceQuestion +import com.posthog.surveys.PostHogDisplayRatingQuestion +import com.posthog.surveys.PostHogDisplaySurvey +import com.posthog.surveys.PostHogDisplaySurveyAppearance +import com.posthog.surveys.PostHogDisplaySurveyQuestion +import com.posthog.surveys.PostHogDisplaySurveyRatingType +import com.posthog.surveys.PostHogDisplaySurveyTextContentType +import com.posthog.surveys.PostHogNextSurveyQuestion +import com.posthog.surveys.PostHogSurveyResponse +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.ParameterizedRobolectricTestRunner +import org.robolectric.annotation.Config +import kotlin.test.assertEquals + +@RunWith(ParameterizedRobolectricTestRunner::class) +@Config(sdk = [28]) +internal class SurveyAutoSubmitInteractionTest( + private val kind: String, + private val enabled: Boolean, +) { + @get:Rule + val compose = createComposeRule() + + @Test + fun `selection submits once and follows branching without carrying selection to the next question`() { + val responses = mutableListOf>() + var closes = 0 + val survey = + PostHogDisplaySurvey( + id = "interaction-survey", + name = "Interaction survey", + questions = + listOf( + question("First question", enabled), + question("Skipped question", false), + question("Last question", false), + ), + appearance = PostHogDisplaySurveyAppearance(displayThankYouMessage = false), + ) + compose.setContent { + MaterialTheme { + SurveySheet( + survey = survey, + onSurveyShown = {}, + onSubmit = { index, response -> + responses.add(index to response) + PostHogNextSurveyQuestion(2, index == 2) + }, + onClose = { closes++ }, + ) + } + } + compose.onNodeWithText("First question").assertIsDisplayed() + val autoSubmit = enabled && kind in listOf("number", "emoji", "single") + if (autoSubmit) { + compose.onNodeWithText("Submit").assertDoesNotExist() + } else { + compose.onNodeWithText("Submit").assertIsNotEnabled() + } + + selectAnswer() + if (!autoSubmit) { + compose.runOnIdle { assertEquals(emptyList(), responses) } + compose.onNodeWithText("Submit").assertIsEnabled().performClick() + } + + compose.onNodeWithText("Last question").assertIsDisplayed() + compose.onNodeWithText("Skipped question").assertDoesNotExist() + compose.onNodeWithText("Submit").assertIsNotEnabled() + compose.runOnIdle { + assertEquals(listOf(0 to expectedResponse()), responses) + assertEquals(0, closes) + } + + // Selecting the same value again must select it on the new question, not deselect stale state. + selectAnswer() + compose.onNodeWithText("Submit").assertIsEnabled().performClick() + compose.runOnIdle { + assertEquals(listOf(0 to expectedResponse(), 2 to expectedResponse()), responses) + assertEquals(1, closes) + } + } + + private fun selectAnswer() { + when (kind) { + "number" -> compose.onNodeWithText("3").performClick() + "emoji" -> { + // Emoji choices are canvases without text; other sheet actions have accessible labels. + val choices = + compose.onAllNodes( + hasClickAction() and + SemanticsMatcher.keyNotDefined(SemanticsProperties.Text) and + SemanticsMatcher.keyNotDefined(SemanticsProperties.ContentDescription), + ) + choices.assertCountEquals(5) + choices[2].performClick() + } + "open" -> { + compose.onNodeWithText("Other:").performClick() + compose.onNode(hasSetTextAction()).performTextInput("Free form") + } + else -> compose.onNodeWithText("First").performClick() + } + } + + private fun expectedResponse(): PostHogSurveyResponse = + when (kind) { + "number", "emoji" -> PostHogSurveyResponse.Rating(3) + "multiple" -> PostHogSurveyResponse.MultipleChoice(listOf("First")) + "open" -> PostHogSurveyResponse.SingleChoice("Free form") + else -> PostHogSurveyResponse.SingleChoice("First") + } + + private fun question( + title: String, + autoSubmit: Boolean, + ): PostHogDisplaySurveyQuestion = + when (kind) { + "number", "emoji" -> + PostHogDisplayRatingQuestion( + id = title, question = title, questionDescription = null, + questionDescriptionContentType = PostHogDisplaySurveyTextContentType.TEXT, + isOptional = false, buttonText = "Submit", + ratingType = if (kind == "number") PostHogDisplaySurveyRatingType.NUMBER else PostHogDisplaySurveyRatingType.EMOJI, + scaleLowerBound = 1, scaleUpperBound = 5, lowerBoundLabel = "", upperBoundLabel = "", + skipSubmitButton = autoSubmit, + ) + else -> + PostHogDisplayChoiceQuestion( + id = title, question = title, questionDescription = null, + questionDescriptionContentType = PostHogDisplaySurveyTextContentType.TEXT, + isOptional = false, buttonText = "Submit", choices = listOf("First", "Other"), + hasOpenChoice = kind == "open", shuffleOptions = false, isMultipleChoice = kind == "multiple", + skipSubmitButton = autoSubmit, + ) + } + + companion object { + @JvmStatic + @ParameterizedRobolectricTestRunner.Parameters(name = "kind={0}, enabled={1}") + fun cases(): List> = + listOf("number", "emoji", "single", "open", "multiple").flatMap { kind -> + listOf(true, false).map { enabled -> arrayOf(kind, enabled) } + } + } +} diff --git a/posthog/api/posthog.api b/posthog/api/posthog.api index ec32a74d9..98465cb64 100644 --- a/posthog/api/posthog.api +++ b/posthog/api/posthog.api @@ -1660,9 +1660,12 @@ public final class com/posthog/surveys/OpenSurveyQuestion : com/posthog/surveys/ public final class com/posthog/surveys/PostHogDisplayChoiceQuestion : com/posthog/surveys/PostHogDisplaySurveyQuestion { public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyTextContentType;ZLjava/lang/String;Ljava/util/List;ZZZ)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyTextContentType;ZLjava/lang/String;Ljava/util/List;ZZZZ)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyTextContentType;ZLjava/lang/String;Ljava/util/List;ZZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getChoices ()Ljava/util/List; public final fun getHasOpenChoice ()Z public final fun getShuffleOptions ()Z + public final fun getSkipSubmitButton ()Z public final fun isMultipleChoice ()Z } @@ -1677,10 +1680,13 @@ public final class com/posthog/surveys/PostHogDisplayOpenQuestion : com/posthog/ public final class com/posthog/surveys/PostHogDisplayRatingQuestion : com/posthog/surveys/PostHogDisplaySurveyQuestion { public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyTextContentType;ZLjava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyRatingType;IILjava/lang/String;Ljava/lang/String;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyTextContentType;ZLjava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyRatingType;IILjava/lang/String;Ljava/lang/String;Z)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyTextContentType;ZLjava/lang/String;Lcom/posthog/surveys/PostHogDisplaySurveyRatingType;IILjava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getLowerBoundLabel ()Ljava/lang/String; public final fun getRatingType ()Lcom/posthog/surveys/PostHogDisplaySurveyRatingType; public final fun getScaleLowerBound ()I public final fun getScaleUpperBound ()I + public final fun getSkipSubmitButton ()Z public final fun getUpperBoundLabel ()Ljava/lang/String; } @@ -2157,6 +2163,7 @@ public class com/posthog/surveys/SurveyQuestion { public final fun getId ()Ljava/lang/String; public final fun getOptional ()Ljava/lang/Boolean; public final fun getQuestion ()Ljava/lang/String; + public final fun getSkipSubmitButton ()Ljava/lang/Boolean; public final fun getTranslations ()Ljava/util/Map; public final fun getType ()Lcom/posthog/surveys/SurveyQuestionType; } diff --git a/posthog/src/main/java/com/posthog/surveys/PostHogDisplaySurveyQuestion.kt b/posthog/src/main/java/com/posthog/surveys/PostHogDisplaySurveyQuestion.kt index bb9c4b127..26fd0825b 100644 --- a/posthog/src/main/java/com/posthog/surveys/PostHogDisplaySurveyQuestion.kt +++ b/posthog/src/main/java/com/posthog/surveys/PostHogDisplaySurveyQuestion.kt @@ -92,6 +92,7 @@ public open class PostHogDisplaySurveyQuestion( questionDescriptionContentType = contentType, isOptional = isOptional, buttonText = buttonText, + skipSubmitButton = question.skipSubmitButton == true, ratingType = ratingType, scaleLowerBound = scaleLower, scaleUpperBound = scaleUpper, @@ -106,6 +107,7 @@ public open class PostHogDisplaySurveyQuestion( questionDescriptionContentType = contentType, isOptional = isOptional, buttonText = buttonText, + skipSubmitButton = question.skipSubmitButton == true, ratingType = PostHogDisplaySurveyRatingType.NUMBER, scaleLowerBound = 1, scaleUpperBound = 5, @@ -128,6 +130,7 @@ public open class PostHogDisplaySurveyQuestion( choices = choices, hasOpenChoice = single?.hasOpenChoice ?: false, shuffleOptions = single?.shuffleOptions ?: false, + skipSubmitButton = question.skipSubmitButton == true, isMultipleChoice = false, ) } @@ -145,6 +148,7 @@ public open class PostHogDisplaySurveyQuestion( choices = choices, hasOpenChoice = multiple?.hasOpenChoice ?: false, shuffleOptions = multiple?.shuffleOptions ?: false, + skipSubmitButton = question.skipSubmitButton == true, isMultipleChoice = true, ) } @@ -204,27 +208,31 @@ public class PostHogDisplayLinkQuestion( * @property scaleUpperBound The upper bound of the rating scale * @property lowerBoundLabel The label for the lower bound of the rating scale * @property upperBoundLabel The label for the upper bound of the rating scale + * @property skipSubmitButton Whether selecting a rating submits without an extra submit tap */ -public class PostHogDisplayRatingQuestion( - id: String, - question: String, - questionDescription: String?, - questionDescriptionContentType: PostHogDisplaySurveyTextContentType, - isOptional: Boolean, - buttonText: String?, - public val ratingType: PostHogDisplaySurveyRatingType, - public val scaleLowerBound: Int, - public val scaleUpperBound: Int, - public val lowerBoundLabel: String, - public val upperBoundLabel: String, -) : PostHogDisplaySurveyQuestion( - id = id, - question = question, - questionDescription = questionDescription, - questionDescriptionContentType = questionDescriptionContentType, - isOptional = isOptional, - buttonText = buttonText, - ) +public class PostHogDisplayRatingQuestion + @JvmOverloads + constructor( + id: String, + question: String, + questionDescription: String?, + questionDescriptionContentType: PostHogDisplaySurveyTextContentType, + isOptional: Boolean, + buttonText: String?, + public val ratingType: PostHogDisplaySurveyRatingType, + public val scaleLowerBound: Int, + public val scaleUpperBound: Int, + public val lowerBoundLabel: String, + public val upperBoundLabel: String, + public val skipSubmitButton: Boolean = false, + ) : PostHogDisplaySurveyQuestion( + id = id, + question = question, + questionDescription = questionDescription, + questionDescriptionContentType = questionDescriptionContentType, + isOptional = isOptional, + buttonText = buttonText, + ) /** * Represents a question where users can select one or more choices @@ -233,23 +241,27 @@ public class PostHogDisplayRatingQuestion( * @property hasOpenChoice Whether the question includes an "other" option for users to input free-form text * @property shuffleOptions Whether the options should be shuffled when presented * @property isMultipleChoice Whether the user can select multiple options + * @property skipSubmitButton Whether to auto-submit single choices without an open-ended option */ -public class PostHogDisplayChoiceQuestion( - id: String, - question: String, - questionDescription: String?, - questionDescriptionContentType: PostHogDisplaySurveyTextContentType, - isOptional: Boolean, - buttonText: String?, - public val choices: List, - public val hasOpenChoice: Boolean, - public val shuffleOptions: Boolean, - public val isMultipleChoice: Boolean, -) : PostHogDisplaySurveyQuestion( - id = id, - question = question, - questionDescription = questionDescription, - questionDescriptionContentType = questionDescriptionContentType, - isOptional = isOptional, - buttonText = buttonText, - ) +public class PostHogDisplayChoiceQuestion + @JvmOverloads + constructor( + id: String, + question: String, + questionDescription: String?, + questionDescriptionContentType: PostHogDisplaySurveyTextContentType, + isOptional: Boolean, + buttonText: String?, + public val choices: List, + public val hasOpenChoice: Boolean, + public val shuffleOptions: Boolean, + public val isMultipleChoice: Boolean, + public val skipSubmitButton: Boolean = false, + ) : PostHogDisplaySurveyQuestion( + id = id, + question = question, + questionDescription = questionDescription, + questionDescriptionContentType = questionDescriptionContentType, + isOptional = isOptional, + buttonText = buttonText, + ) diff --git a/posthog/src/main/java/com/posthog/surveys/SurveyQuestion.kt b/posthog/src/main/java/com/posthog/surveys/SurveyQuestion.kt index ad1734bd0..2799dc2f4 100644 --- a/posthog/src/main/java/com/posthog/surveys/SurveyQuestion.kt +++ b/posthog/src/main/java/com/posthog/surveys/SurveyQuestion.kt @@ -8,6 +8,7 @@ public open class SurveyQuestion { public val descriptionContentType: SurveyTextContentType? = null public val optional: Boolean? = null public val buttonText: String? = null + public val skipSubmitButton: Boolean? = null public val branching: SurveyQuestionBranching? = null public val translations: Map? = null } diff --git a/posthog/src/test/java/com/posthog/surveys/SurveyAutoSubmitTest.kt b/posthog/src/test/java/com/posthog/surveys/SurveyAutoSubmitTest.kt new file mode 100644 index 000000000..5625d5274 --- /dev/null +++ b/posthog/src/test/java/com/posthog/surveys/SurveyAutoSubmitTest.kt @@ -0,0 +1,54 @@ +package com.posthog.surveys + +import com.posthog.PostHogConfig +import com.posthog.internal.PostHogSerializer +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +@RunWith(Parameterized::class) +internal class SurveyAutoSubmitTest( + private val type: String, + private val enabled: Boolean?, + private val display: String, +) { + @Test + fun `auto-submit setting survives decoding and display mapping`() { + val serializer = PostHogSerializer(PostHogConfig("test-key")) + val json = + mapOf( + "id" to "question", + "type" to type, + "question" to "Choose", + "choices" to listOf("First", "Second"), + "display" to display, + "scale" to 5, + "skipSubmitButton" to enabled, + ) + val question = assertNotNull(serializer.deserializeList(listOf(json))?.firstOrNull()) + assertEquals(enabled, question.skipSubmitButton) + val rendered = assertNotNull(PostHogDisplaySurveyQuestion.fromSurveyQuestion(question)) + val skipSubmitButton = + when (rendered) { + is PostHogDisplayRatingQuestion -> rendered.skipSubmitButton + is PostHogDisplayChoiceQuestion -> rendered.skipSubmitButton + else -> error("Unexpected question type") + } + assertEquals(enabled == true, skipSubmitButton) + } + + companion object { + @JvmStatic + @Parameterized.Parameters(name = "{0}, enabled={1}, display={2}") + fun cases(): List> = + listOf("rating", "single_choice", "multiple_choice").flatMap { type -> + listOf(true, false, null).flatMap { enabled -> + (if (type == "rating") listOf("number", "emoji") else listOf("number")).map { display -> + arrayOf(type, enabled, display) + } + } + } + } +}