diff --git a/Ext/Accessibility/build.gradle b/Ext/Accessibility/build.gradle index 81db4d568..98faef6b5 100644 --- a/Ext/Accessibility/build.gradle +++ b/Ext/Accessibility/build.gradle @@ -2,6 +2,8 @@ plugins { id 'com.android.library' id 'kotlin-android' id 'org.jetbrains.dokka' + id 'maven-publish' + id 'signing' } ext { diff --git a/Ext/Compose/build.gradle b/Ext/Compose/build.gradle index 47a207ee5..e59e1450a 100644 --- a/Ext/Compose/build.gradle +++ b/Ext/Compose/build.gradle @@ -1,7 +1,12 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id 'com.android.library' id 'kotlin-android' id 'org.jetbrains.dokka' + id 'maven-publish' + id 'signing' + alias(libs.plugins.compose.compiler) } ext { @@ -66,15 +71,16 @@ android { compose true } - kotlinOptions { - jvmTarget = '17' + kotlin { + compilerOptions { + allWarningsAsErrors.set(true) + jvmTarget.set(JvmTarget.JVM_21) + freeCompilerArgs.addAll("-Xcontext-parameters") + } } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - composeOptions { - kotlinCompilerExtensionVersion "1.5.14" + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } dependencies { diff --git a/Ext/Fullscreen/build.gradle b/Ext/Fullscreen/build.gradle index a0e81200b..c3f434284 100644 --- a/Ext/Fullscreen/build.gradle +++ b/Ext/Fullscreen/build.gradle @@ -2,6 +2,8 @@ plugins { id 'com.android.library' id 'kotlin-android' id 'org.jetbrains.dokka' + id 'maven-publish' + id 'signing' } ext { diff --git a/Library/build.gradle b/Library/build.gradle index d5d95d7ef..c04078f67 100644 --- a/Library/build.gradle +++ b/Library/build.gradle @@ -1,8 +1,12 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id 'com.android.library' id 'kotlin-android' id 'org.jetbrains.dokka' id 'jacoco' + id 'maven-publish' + id 'signing' } ext { @@ -26,23 +30,23 @@ archivesBaseName = pom.artifact jacoco { toolVersion = "0.8.10" } android { - kotlinOptions { - jvmTarget = '17' - } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } defaultConfig { - compileSdk libs.versions.compileSdk.get().toInteger() + compileSdkVersion libs.versions.compileSdk.get().toInteger() minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdk.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled = true - kotlinOptions { - allWarningsAsErrors = true - freeCompilerArgs = ["-Xcontext-receivers"] + kotlin { + compilerOptions { + allWarningsAsErrors.set(true) + jvmTarget.set(JvmTarget.JVM_21) + freeCompilerArgs.addAll("-Xcontext-parameters") + } } } @@ -156,4 +160,4 @@ project.afterEvaluate { executionData(files("${project.buildDir}/jacoco/${testTaskName}.exec")) } } -} \ No newline at end of file +} diff --git a/Library/src/androidTest/java/dev/testify/BitmapCompareTest.kt b/Library/src/androidTest/java/dev/testify/BitmapCompareTest.kt index 07909d658..910c6c98e 100644 --- a/Library/src/androidTest/java/dev/testify/BitmapCompareTest.kt +++ b/Library/src/androidTest/java/dev/testify/BitmapCompareTest.kt @@ -87,7 +87,7 @@ class BitmapCompareTest { @Test fun fuzzy() { - val similarBitmap = baselineBitmap.copy(baselineBitmap.config, true)!! + val similarBitmap = baselineBitmap.copy(baselineBitmap.config!!, true)!! similarBitmap.setPixel(0, 0, similarBitmap.getPixel(0, 0) + 1) assertFalse(FuzzyCompare(TestifyConfiguration(exactness = 1.0f)).compareBitmaps(similarBitmap, baselineBitmap)) diff --git a/Library/src/androidTest/java/dev/testify/FuzzyCompareBitmapTest.kt b/Library/src/androidTest/java/dev/testify/FuzzyCompareBitmapTest.kt index 1ca01b3c9..c3df09545 100644 --- a/Library/src/androidTest/java/dev/testify/FuzzyCompareBitmapTest.kt +++ b/Library/src/androidTest/java/dev/testify/FuzzyCompareBitmapTest.kt @@ -56,7 +56,7 @@ class FuzzyCompareBitmapTest { fun fuzzy() { val baselineBitmap = loadBitmap("test") - val similarBitmap = baselineBitmap.copy(baselineBitmap.config, true)!! + val similarBitmap = baselineBitmap.copy(baselineBitmap.config!!, true)!! similarBitmap.setPixel(0, 0, similarBitmap.getPixel(0, 0) + 1) assertFalse(FuzzyCompare(TestifyConfiguration(exactness = 1.0f)).compareBitmaps(similarBitmap, baselineBitmap)) diff --git a/Library/src/main/java/dev/testify/ScreenshotRule.kt b/Library/src/main/java/dev/testify/ScreenshotRule.kt index c0f6e48dd..e53cc68d8 100644 --- a/Library/src/main/java/dev/testify/ScreenshotRule.kt +++ b/Library/src/main/java/dev/testify/ScreenshotRule.kt @@ -109,7 +109,7 @@ import org.junit.runners.model.Statement @Suppress("unused", "MemberVisibilityCanBePrivate") open class ScreenshotRule @JvmOverloads constructor( protected val activityClass: Class, - @IdRes override var rootViewId: Int = android.R.id.content, + @field:IdRes override var rootViewId: Int = android.R.id.content, initialTouchMode: Boolean = false, enableReporter: Boolean = false, override val configuration: TestifyConfiguration = TestifyConfiguration() diff --git a/Library/src/main/java/dev/testify/ScreenshotUtility.kt b/Library/src/main/java/dev/testify/ScreenshotUtility.kt index 65aec552f..bbb3a40cb 100644 --- a/Library/src/main/java/dev/testify/ScreenshotUtility.kt +++ b/Library/src/main/java/dev/testify/ScreenshotUtility.kt @@ -33,16 +33,15 @@ import android.graphics.BitmapFactory import android.os.Debug import android.util.Log import android.view.View -import androidx.test.annotation.ExperimentalTestApi import dev.testify.core.getDeviceDescription import dev.testify.internal.helpers.loadAsset import dev.testify.output.Destination import dev.testify.output.PNG_EXTENSION import dev.testify.output.getDestination import dev.testify.output.getFileRelativeToRoot +import java.io.File import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import java.io.File /** * The default, preferred [BitmapFactory.Options] to use when decoding a [Bitmap]. @@ -138,7 +137,6 @@ fun loadBaselineBitmapForComparison( * @return A [Bitmap] representing the captured [screenshotView] in [activity] * Will return [null] if there is an error capturing the bitmap. */ -@ExperimentalTestApi fun createBitmapFromActivity( activity: Activity, fileName: String, diff --git a/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt b/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt index 5666e1a6a..0669b653b 100644 --- a/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt +++ b/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt @@ -78,7 +78,7 @@ data class TestifyConfiguration( * Set the exactness of the bitmap comparison. The exactness is a value between 0.0 and 1.0, where 0.0 is the least * exact and 1.0 is the most exact. The default value is 0.0. */ - @FloatRange(from = 0.0, to = 1.0) var exactness: Float? = null, + @field:FloatRange(from = 0.0, to = 1.0) var exactness: Float? = null, /** * Install an activity monitor and set the requested orientation. Blocks and waits for the orientation change to @@ -140,7 +140,7 @@ data class TestifyConfiguration( * Set the @IdRes of the view that should be focused before the bitmap is captured. * Allows Testify to deliberately set the keyboard focus to the specified view ID. */ - @IdRes var focusTargetId: Int = View.NO_ID, + @field:IdRes var focusTargetId: Int = View.NO_ID, /** * Pause the test execution after the bitmap is captured. diff --git a/Library/src/main/java/dev/testify/internal/modification/FocusModification.kt b/Library/src/main/java/dev/testify/internal/modification/FocusModification.kt index b309e2526..f608bfb55 100644 --- a/Library/src/main/java/dev/testify/internal/modification/FocusModification.kt +++ b/Library/src/main/java/dev/testify/internal/modification/FocusModification.kt @@ -43,7 +43,7 @@ import java.util.concurrent.TimeUnit * * @param focusTargetId the id of the view to request focus on. If [View.NO_ID] is provided, the root view will be used. */ -class FocusModification(@IdRes var focusTargetId: Int) : ViewModification() { +class FocusModification(@field:IdRes var focusTargetId: Int) : ViewModification() { /** * Returns the view to request focus on. diff --git a/Library/src/main/java/dev/testify/report/ReportSession.kt b/Library/src/main/java/dev/testify/report/ReportSession.kt index 02e0241aa..917fd9e55 100644 --- a/Library/src/main/java/dev/testify/report/ReportSession.kt +++ b/Library/src/main/java/dev/testify/report/ReportSession.kt @@ -25,6 +25,7 @@ package dev.testify.report import android.app.Instrumentation +import android.os.Build import androidx.annotation.VisibleForTesting import dev.testify.internal.annotation.ExcludeFromJacocoGeneratedReport import java.io.BufferedReader @@ -214,7 +215,13 @@ internal open class ReportSession { */ @VisibleForTesting internal fun getSessionId(instrumentation: Instrumentation, thread: Thread): String { - return "${instrumentation.context.hashCode().toString(16).padStart(8, '0')}-${thread.id}" + val id = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) { + thread.threadId() + } else { + @Suppress("DEPRECATION") + thread.id + } + return "${instrumentation.context.hashCode().toString(16).padStart(8, '0')}-$id" } } } diff --git a/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt b/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt index 650060a39..0d13f029c 100644 --- a/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt +++ b/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt @@ -108,9 +108,9 @@ import kotlin.contracts.contract * @param configuration The [TestifyConfiguration] for the current test */ open class ScreenshotScenarioRule @JvmOverloads constructor( - @IdRes override var rootViewId: Int = android.R.id.content, + @field:IdRes override var rootViewId: Int = android.R.id.content, enableReporter: Boolean = false, - @LayoutRes override var targetLayoutId: Int = View.NO_ID, + @field:LayoutRes override var targetLayoutId: Int = View.NO_ID, override val configuration: TestifyConfiguration = TestifyConfiguration() ) : TestWatcher(), @@ -501,10 +501,10 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( } ?: throw ScenarioRequiredException() } - context (ActivityScenario<*>) + context (scenario: ActivityScenario<*>) @JvmName("assertSameContext") fun assertSame() { - assertSame(this@ActivityScenario) + assertSame(scenario) } private fun assertSame(scenario: ActivityScenario<*>) { diff --git a/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt b/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt index be00ff812..cb31e5604 100644 --- a/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt +++ b/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt @@ -139,7 +139,7 @@ class ResourceWrapperTest { } overrideResourceConfiguration( - locale = Locale("fr_CA") + locale = Locale.of("fr_CA") ) verify(exactly = 1) { ResourceWrapper.addOverride(any()) } verify { wrappedResource.beforeActivityLaunched() } @@ -171,7 +171,7 @@ class ResourceWrapperTest { } overrideResourceConfiguration( - locale = Locale("fr_CA"), + locale = Locale.of("fr_CA"), fontScale = 1.5f ) verify(exactly = 2) { ResourceWrapper.addOverride(any()) } diff --git a/Library/src/test/java/dev/testify/report/ReportSessionTest.kt b/Library/src/test/java/dev/testify/report/ReportSessionTest.kt index 12307bab1..c7a730076 100644 --- a/Library/src/test/java/dev/testify/report/ReportSessionTest.kt +++ b/Library/src/test/java/dev/testify/report/ReportSessionTest.kt @@ -105,7 +105,10 @@ class ReportSessionTest { val context: Context = mockk() every { instrumentation.context } returns context - every { thread.id } returns 123L + every { + @Suppress("DEPRECATION") + thread.id + } returns 123L val id = ReportSession.getSessionId(instrumentation, thread) assertTrue("^[0-9a-fA-F]{8}-123".toRegex().containsMatchIn(id)) diff --git a/Plugins/Gradle/build.gradle b/Plugins/Gradle/build.gradle index 94f51d7b1..dc8bc3fc5 100644 --- a/Plugins/Gradle/build.gradle +++ b/Plugins/Gradle/build.gradle @@ -7,6 +7,8 @@ plugins { id 'org.jetbrains.kotlin.jvm' id 'org.jetbrains.dokka' id 'jacoco' + id 'maven-publish' + id 'signing' } def gradleProperties = new Properties() diff --git a/Samples/Flix/FlixLibrary/build.gradle b/Samples/Flix/FlixLibrary/build.gradle index e0e446b5c..2ce85dfd0 100644 --- a/Samples/Flix/FlixLibrary/build.gradle +++ b/Samples/Flix/FlixLibrary/build.gradle @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + buildscript { ext { versions = [ @@ -17,15 +19,16 @@ plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' id 'dev.testify' + alias(libs.plugins.compose.compiler) } android { namespace 'dev.testify.samples.flix.library' - compileSdk 34 + compileSdk 36 defaultConfig { - minSdk 24 - targetSdk 33 + minSdkVersion 26 + targetSdkVersion 36 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -40,11 +43,13 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } - kotlinOptions { - jvmTarget = '17' + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } } buildFeatures { compose true @@ -70,26 +75,27 @@ testify { } dependencies { - kapt "com.google.dagger:dagger-compiler:2.46.1" - kapt "com.google.dagger:hilt-compiler:2.48" + kapt "com.google.dagger:dagger-compiler:2.57.1" + kapt "com.google.dagger:hilt-compiler:2.57.1" - def composeBom = platform('androidx.compose:compose-bom:2024.05.00') + def composeBom = platform('androidx.compose:compose-bom:2025.08.01') implementation composeBom + //noinspection UseTomlInstead implementation "androidx.hilt:hilt-navigation-compose:1.2.0" - implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.1" - implementation "androidx.test.espresso.idling:idling-concurrent:3.6.0-rc01" - implementation "com.google.dagger:hilt-android:2.48" - implementation 'androidx.compose.material3:material3:1.2.1' - implementation 'androidx.core:core-ktx:1.13.1' - implementation 'io.ktor:ktor-client-android:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0' - implementation("io.coil-kt:coil-compose:2.2.2") + implementation "androidx.lifecycle:lifecycle-runtime-compose:2.9.3" + implementation "androidx.test.espresso.idling:idling-concurrent:3.7.0" + implementation "com.google.dagger:hilt-android:2.57.1" + implementation 'androidx.compose.material3:material3:1.3.2' + implementation 'androidx.core:core-ktx:1.17.0' + implementation 'io.ktor:ktor-client-android:3.2.3' + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0' + implementation("io.coil-kt:coil-compose:2.7.0") androidTestImplementation composeBom androidTestImplementation "androidx.compose.ui:ui-test-junit4:${versions.compose.ui}" - androidTestImplementation "androidx.test:rules:1.5.0" + androidTestImplementation "androidx.test:rules:1.7.0" androidTestImplementation project(":Library") androidTestImplementation project(":ComposeExtensions") - androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.ext:junit:1.3.0' } \ No newline at end of file diff --git a/Samples/Flix/FlixLibrary/src/main/java/dev/testify/samples/flix/repository/CastMemberRepository.kt b/Samples/Flix/FlixLibrary/src/main/java/dev/testify/samples/flix/repository/CastMemberRepository.kt index b1abc106e..eb0e81b35 100644 --- a/Samples/Flix/FlixLibrary/src/main/java/dev/testify/samples/flix/repository/CastMemberRepository.kt +++ b/Samples/Flix/FlixLibrary/src/main/java/dev/testify/samples/flix/repository/CastMemberRepository.kt @@ -31,8 +31,9 @@ import dev.testify.samples.flix.data.remote.tmdb.TheMovieDbUrlResolver import dev.testify.samples.flix.data.remote.tmdb.entity.Person import dev.testify.samples.flix.data.translator.toFlixPerson import io.ktor.client.HttpClient +import io.ktor.client.call.body import io.ktor.client.request.get -import io.ktor.http.pathComponents +import io.ktor.http.appendPathSegments import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.flow.Flow @@ -53,20 +54,23 @@ class CastMemberRepository @Inject constructor( val apiConfigurationDeferred = async { configurationApi.getApiConfiguration() } val personApiSpec = GetApiSpec("person", id.toString()) + val person: Person = client.get { url { val allUrlComponents: List = buildList { add(personApiSpec.apiVersion.toString()) addAll(personApiSpec.pathSegments) } - pathComponents(allUrlComponents) + appendPathSegments(allUrlComponents) } - } + }.body() val apiConfiguration = apiConfigurationDeferred.await() val urlResolver = TheMovieDbUrlResolver(apiConfiguration.baseUrl, apiConfiguration.headlineImageSizeKey) person.toFlixPerson(urlResolver) + + null // TODO? } .onFailure { when (it) { diff --git a/Samples/Flix/build.gradle b/Samples/Flix/build.gradle index 5c92ed17c..9b183a778 100644 --- a/Samples/Flix/build.gradle +++ b/Samples/Flix/build.gradle @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + buildscript { ext { versions = [ @@ -19,6 +21,7 @@ plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' id 'dev.testify' + alias(libs.plugins.compose.compiler) } secrets { @@ -27,12 +30,12 @@ secrets { android { namespace 'dev.testify.samples.flix' - compileSdk 34 + compileSdk 36 defaultConfig { applicationId "dev.testify.samples.flix" - minSdk 24 - targetSdk 33 + minSdkVersion 26 + targetSdk 36 versionCode 1 versionName "1.0" @@ -49,11 +52,14 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } - kotlinOptions { - jvmTarget = '17' + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime") + } } buildFeatures { compose true @@ -83,38 +89,44 @@ dependencies { implementation project(":FlixLibrary") // Core Android - implementation 'androidx.core:core-ktx:1.10.1' - implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7" - implementation "androidx.appcompat:appcompat:1.7.0" + implementation 'androidx.core:core-ktx:1.17.0' + implementation "androidx.lifecycle:lifecycle-runtime-compose:2.9.3" + implementation "androidx.appcompat:appcompat:1.7.1" // UI Layer - def composeBom = platform('androidx.compose:compose-bom:2024.05.00') + def composeBom = platform('androidx.compose:compose-bom:2025.08.01') implementation composeBom - implementation 'androidx.compose.material3:material3:1.2.1' + implementation 'androidx.compose.material3:material3:1.3.2' implementation 'androidx.compose.ui:ui-tooling-preview' - implementation 'androidx.activity:activity-compose:1.9.0' - implementation("io.coil-kt:coil-compose:2.2.2") - implementation "com.google.accompanist:accompanist-systemuicontroller:0.34.0" + implementation 'androidx.activity:activity-compose:1.10.1' + implementation("io.coil-kt:coil-compose:2.7.0") + implementation "com.google.accompanist:accompanist-systemuicontroller:0.36.0" debugImplementation 'androidx.compose.ui:ui-tooling' androidTestImplementation composeBom // Dependency injection - implementation "com.google.dagger:hilt-android:2.48" - kapt "com.google.dagger:hilt-compiler:2.48" + implementation "com.google.dagger:hilt-android:2.57.1" + kapt "com.google.dagger:hilt-compiler:2.57.1" // Navigation - implementation "androidx.navigation:navigation-compose:2.7.7" + implementation "androidx.navigation:navigation-compose:2.9.3" implementation "androidx.hilt:hilt-navigation-compose:1.2.0" - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1") - implementation "androidx.test.espresso.idling:idling-concurrent:3.6.0-rc01" + implementation "androidx.test.espresso.idling:idling-concurrent:3.7.0" // Network Stack - implementation 'io.ktor:ktor-client-android:1.5.0' - implementation 'io.ktor:ktor-client-serialization:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0' - implementation 'io.ktor:ktor-client-logging-jvm:1.5.0' + implementation("io.ktor:ktor-client-core:3.2.3") + implementation("io.ktor:ktor-client-android:3.2.3") +// implementation 'io.ktor:ktor-client-serialization:3.2.3' +// implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0' + implementation("io.ktor:ktor-client-logging:3.2.3") + implementation("io.ktor:ktor-client-content-negotiation:3.2.3") // Or your specific Ktor version + implementation("io.ktor:ktor-serialization-kotlinx-json:3.2.3") // Or your specific Ktor version + +// implementation 'io.ktor:ktor-client-logging-jvm:3.2.3' + // Test Support testImplementation 'junit:junit:4.13.2' @@ -123,9 +135,9 @@ dependencies { androidTestImplementation project(path: ":ComposeExtensions") androidTestImplementation project(":FullscreenCaptureMethod") androidTestImplementation project(":Accessibility") - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation "androidx.test:rules:1.5.0" + androidTestImplementation 'androidx.test.ext:junit:1.3.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0' + androidTestImplementation "androidx.test:rules:1.7.0" androidTestImplementation "androidx.compose.ui:ui-test-junit4:${versions.compose.ui}" } diff --git a/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/TheMovieDbApi.kt b/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/TheMovieDbApi.kt index 518b6064a..aedb809db 100644 --- a/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/TheMovieDbApi.kt +++ b/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/TheMovieDbApi.kt @@ -33,13 +33,14 @@ import dev.testify.samples.flix.data.remote.tmdb.entity.MovieDetail import dev.testify.samples.flix.data.remote.tmdb.entity.MovieReleaseDates import dev.testify.samples.flix.data.remote.tmdb.entity.Page import io.ktor.client.HttpClient -import io.ktor.client.features.ResponseException -import io.ktor.client.features.ServerResponseException +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException +import io.ktor.client.plugins.ServerResponseException import io.ktor.client.request.get -import io.ktor.http.pathComponents +import io.ktor.http.appendPathSegments +import kotlinx.serialization.SerializationException import java.io.IOException import java.util.concurrent.CancellationException -import kotlinx.serialization.SerializationException import javax.inject.Inject class TheMovieDbApi @Inject constructor( @@ -141,9 +142,9 @@ class TheMovieDbApi @Inject constructor( add(apiVersion.toString()) addAll(getSubstitutedPathSegments()) } - pathComponents(allUrlComponents) + appendPathSegments(allUrlComponents) } - } + }.body() ) } catch (t: CancellationException) { Log.d(LOG_TAG, "Cancellation exception $t") diff --git a/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/httpclient/KtorHttpClient.kt b/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/httpclient/KtorHttpClient.kt index 7f3cdf31e..ed22d265b 100644 --- a/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/httpclient/KtorHttpClient.kt +++ b/Samples/Flix/src/main/java/dev/testify/samples/flix/data/remote/tmdb/httpclient/KtorHttpClient.kt @@ -25,22 +25,29 @@ package dev.testify.samples.flix.data.remote.tmdb.httpclient +//import io.ktor.client.features.DefaultRequest +//import io.ktor.client.features.defaultRequest +//import io.ktor.client.features.json.JsonFeature +//import io.ktor.client.features.json.serializer.KotlinxSerializer +//import io.ktor.client.features.logging.LogLevel +//import io.ktor.client.features.logging.Logger +//import io.ktor.client.features.logging.Logging import android.util.Log import dev.testify.samples.flix.application.foundation.secret.SecretsProvider import io.ktor.client.HttpClient import io.ktor.client.engine.android.Android -import io.ktor.client.features.DefaultRequest -import io.ktor.client.features.defaultRequest -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.serializer.KotlinxSerializer -import io.ktor.client.features.logging.LogLevel -import io.ktor.client.features.logging.Logger -import io.ktor.client.features.logging.Logging +import io.ktor.client.plugins.DefaultRequest +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging import io.ktor.client.request.header import io.ktor.client.request.headers import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.URLProtocol +import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json private const val TIME_OUT = 60_000 @@ -67,9 +74,9 @@ internal fun buildKtorHttpClient( } } - install(JsonFeature) { - serializer = KotlinxSerializer( - json = Json(Json) { + install(ContentNegotiation) { // Replace JsonFeature with ContentNegotiation + json( // Use the json() extension function + Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true diff --git a/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieDomainModel.kt b/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieDomainModel.kt index 97c7ab2e9..751fb449a 100644 --- a/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieDomainModel.kt +++ b/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieDomainModel.kt @@ -25,8 +25,10 @@ package dev.testify.samples.flix.domain.model -import kotlinx.datetime.Instant +import kotlin.time.ExperimentalTime +import kotlin.time.Instant +@OptIn(ExperimentalTime::class) data class MovieDomainModel( val id: Int, val title: String, diff --git a/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieReleaseDatesDomainModel.kt b/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieReleaseDatesDomainModel.kt index 6f69c1528..02f777931 100644 --- a/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieReleaseDatesDomainModel.kt +++ b/Samples/Flix/src/main/java/dev/testify/samples/flix/domain/model/MovieReleaseDatesDomainModel.kt @@ -25,7 +25,7 @@ package dev.testify.samples.flix.domain.model -import kotlinx.datetime.Instant +import kotlin.time.Instant data class MovieReleaseDatesDomainModel( val releaseDateMap: Map> diff --git a/Samples/Legacy/build.gradle b/Samples/Legacy/build.gradle index cafdf24e4..b872d06e1 100644 --- a/Samples/Legacy/build.gradle +++ b/Samples/Legacy/build.gradle @@ -15,24 +15,26 @@ plugins { id 'com.android.application' id 'kotlin-android' id 'dev.testify' + alias(libs.plugins.compose.compiler) } android { compileSdk 34 kotlinOptions { - jvmTarget = '17' + jvmTarget = '21' freeCompilerArgs = ["-Xcontext-receivers"] } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } defaultConfig { applicationId "dev.testify.sample" - minSdkVersion 21 - targetSdkVersion 33 + minSdkVersion 26 + compileSdkVersion 35 + targetSdkVersion 35 versionCode 1 versionName "1.0" diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt index 602025f52..0ba45344c 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt @@ -85,6 +85,9 @@ class ScenarioComposeActivityScreenshotTest { } } + /** + * If this screenshot test fails, double-check that animations have been disabled on your emulator + */ @ScreenshotInstrumentation @Test fun dropDownExpanded() { diff --git a/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/ClientDetailsContract.kt b/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/ClientDetailsContract.kt index 80fef6cf3..fcb33be4b 100644 --- a/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/ClientDetailsContract.kt +++ b/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/ClientDetailsContract.kt @@ -28,7 +28,7 @@ import androidx.annotation.DrawableRes data class ClientDetailsViewState( val name: String, - @DrawableRes val avatar: Int, + @field:DrawableRes val avatar: Int, val heading: String, val address: String?, val phoneNumber: String? diff --git a/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/edit/ClientDetailsEditViewState.kt b/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/edit/ClientDetailsEditViewState.kt index 696dee022..5ffadce53 100644 --- a/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/edit/ClientDetailsEditViewState.kt +++ b/Samples/Legacy/src/main/java/dev/testify/sample/clients/details/edit/ClientDetailsEditViewState.kt @@ -27,7 +27,7 @@ import androidx.annotation.DrawableRes data class ClientDetailsEditViewState( val name: String, - @DrawableRes val avatar: Int, + @field:DrawableRes val avatar: Int, val heading: String, val address: String?, val phoneNumber: String? diff --git a/bitrise.yml b/bitrise.yml index 8b32c122c..f10b87fb2 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -117,7 +117,7 @@ workflows: - git-clone@8: {} - set-java-version@1: inputs: - - set_java_version: '17' + - set_java_version: '21' - install-missing-android-tools@3: inputs: - gradlew_path: "$PROJECT_LOCATION/gradlew" diff --git a/build.gradle b/build.gradle index 6c4fc0579..72098d370 100644 --- a/build.gradle +++ b/build.gradle @@ -13,8 +13,8 @@ tasks.register('clean', Delete) { delete rootProject.buildDir } -allprojects { - configurations.configureEach { - resolutionStrategy.force 'org.objenesis:objenesis:2.6' - } -} +//allprojects { +// configurations.configureEach { +// resolutionStrategy.force 'org.objenesis:objenesis:2.6' +// } +//} diff --git a/gradle.properties b/gradle.properties index 127a78569..199095c06 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,6 @@ -android.enableJetifier=true android.useAndroidX=true org.gradle.jvmargs=-Xmx4096m -android.suppressUnsupportedCompileSdk=34 android.nonTransitiveRClass=false android.nonFinalResIds=false android.injected.androidTest.leaveApksInstalledAfterRun=true -testify_version=3.2.2 +testify_version=4.0.0 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24b62117d..8e00af0c3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,38 +1,38 @@ [versions] -compileSdk = "34" -minSdk = "21" -targetSdk = "34" -activityCompose = "1.7.1" -agp = "8.8.0" -appcompat = "1.6.1" +compileSdk = "36" +minSdk = "26" +targetSdk = "36" +activityCompose = "1.10.1" +agp = "8.12.2" +appcompat = "1.7.1" colormath = "1.4.1" -coreKtx = "1.4.0" -coreKtxVersion = "1.10.0" -dokka = "1.8.10" -espressoCore = "3.6.1" -gson = "2.9.0" -guava = "30.0-android" -hilt = "2.48" -junit = "1.1.5" -kotlin = "1.9.24" -kotlinPluginSerialization = "1.8.10" -kotlinxCoroutinesAndroid = "1.6.4" -lifecycleRuntimeKtx = "2.6.1" +coreKtx = "1.7.0" +coreKtxVersion = "1.17.0" +dokka = "2.0.0" +espressoCore = "3.7.0" +gson = "2.13.1" +guava = "33.4.8-android" +hilt = "2.57.1" +junit = "1.3.0" +kotlin = "2.2.10" +kotlinPluginSerialization = "2.2.10" +kotlinxCoroutinesAndroid = "1.10.2" +lifecycleRuntimeKtx = "2.9.3" mapsplatformSecrets = "2.0.1" -material = "1.9.0" -materialVersion = "1.4.3" -mockk = "1.13.16" -mockkAndroid = "1.13.16" -monitor = "1.6.1" +material = "1.12.0" +materialVersion = "1.9.0" +mockk = "1.14.5" +mockkAndroid = "1.14.5" +monitor = "1.8.0" multidex = "2.0.1" -rules = "1.5.0" -runner = "1.5.2" -slf4jJdk14 = "2.0.6" -testStorage = "1.5.0" -truth = "1.1.5" -uiTestJunit4 = "1.4.3" +rules = "1.7.0" +runner = "1.7.0" +slf4jJdk14 = "2.0.17" +testStorage = "1.6.0" +truth = "1.4.4" +uiTestJunit4 = "1.9.0" uiautomator = "2.3.0" -composeBom = "2024.05.00" +composeBom = "2025.08.01" [libraries] androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" } @@ -74,3 +74,4 @@ google-dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.re jetbrains-dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } jetbrains-kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinPluginSerialization" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72b8..37f853b1c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/ktlint.gradle b/ktlint.gradle index e41d9d433..9b66815a7 100644 --- a/ktlint.gradle +++ b/ktlint.gradle @@ -4,7 +4,7 @@ configurations { dependencies { //noinspection UseTomlInstead - ktlint "com.pinterest:ktlint:0.45.2" + ktlint "com.pinterest:ktlint:0.50.0" // additional 3rd party ruleset(s) can be specified here // just add them to the classpath (e.g. ktlint 'groupId:artifactId:version') and // ktlint will pick them up diff --git a/publish.build.gradle b/publish.build.gradle index 6cd81efb6..a428e5d88 100644 --- a/publish.build.gradle +++ b/publish.build.gradle @@ -1,6 +1,3 @@ -apply plugin: 'maven-publish' -apply plugin: 'signing' - dokkaJavadoc { dokkaSourceSets { configureEach {