diff --git a/.editorconfig b/.editorconfig index 53ffa154f..e63e935eb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,6 @@ [*.{kt,kts}] -disabled_rules=import-ordering +ktlint_standard_trailing-comma-on-call-site = disabled +ktlint_standard_trailing-comma-on-declaration-site = disabled indent_size=4 insert_final_newline=true max_line_length=120 @@ -7,3 +8,4 @@ trim_trailing_whitespace=true end_of_line=lf ij_kotlin_name_count_to_use_star_import = 2147483647 ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 + diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aeead9ea..069dde550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## 4.0.0 + +- https://github.com/ndtp/android-testify/pull/266 Updated to Kotlin 2.2 +- https://github.com/ndtp/android-testify/pull/266 Major version updates to all core dependencies. This will require the following changes to your projects: + - Compose 2025.08.01 updates require: + - kotlinCompilerExtensionVersion --> 1.9.0 + - androidx.compose.material:material --> 1.9.0 + - androidx.compose.ui:ui-tooling-preview -> 1.9.0 + - androidx.compose.ui:ui --> 1.9.0 + - Java 21 requires you to update your app to use Java 21 + - Compile 35+ requires you to target 35+ + - Minimum SDK raised to 26 + +--- + # Testify Change Log ## 3.2.3 diff --git a/Ext/Accessibility/README.md b/Ext/Accessibility/README.md index cfe11c32f..c8b667c32 100644 --- a/Ext/Accessibility/README.md +++ b/Ext/Accessibility/README.md @@ -18,7 +18,7 @@ For more information about _Accessibility Checking_, please see https://develope ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` @@ -29,7 +29,7 @@ Ensure that `mavenCentral()` is available to both `pluginManagement` and `depend **Application build.gradle** ```groovy dependencies { - androidTestImplementation "dev.testify:testify-accessibility:3.2.3" + androidTestImplementation "dev.testify:testify-accessibility:4.0.0" } ``` diff --git a/Ext/Accessibility/build.gradle b/Ext/Accessibility/build.gradle index 81db4d568..2afb35f96 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 { @@ -92,5 +94,3 @@ android { afterEvaluate { apply from: "../../publish.build.gradle" } - -apply from: '../../ktlint.gradle' diff --git a/Ext/Accessibility/src/main/java/dev/testify/accessibility/internal/CheckResults.kt b/Ext/Accessibility/src/main/java/dev/testify/accessibility/internal/CheckResults.kt index 80ef096fe..262c5b2b2 100644 --- a/Ext/Accessibility/src/main/java/dev/testify/accessibility/internal/CheckResults.kt +++ b/Ext/Accessibility/src/main/java/dev/testify/accessibility/internal/CheckResults.kt @@ -56,14 +56,18 @@ internal class CheckResults(other: List) : ArrayList(o return if (this.any { it.type == type }) " * $type:\n${this.prettyPrint(type)}" else "" } - private fun List.prettyPrint(filter: String): String { - return if (this.isEmpty()) - " * - [NONE]" - else - filter { it.type == filter }.joinToString(separator = "\n * -", prefix = " * -") { - "${it.check}: [${it.elementClass}/${it.resourceName}] - ${it.message}" - } - } + private fun List.prettyPrint(filter: String) = + prettyPrintEmpty().takeIf { isEmpty() } ?: prettyPrintNotEmpty(filter) + + private fun prettyPrintEmpty() = " * - [NONE]" + + private fun List.prettyPrintNotEmpty(filter: String) = filter { it.type == filter } + .joinToString( + separator = "\n * -", + prefix = " * -" + ) { + "${it.check}: [${it.elementClass}/${it.resourceName}] - ${it.message}" + } companion object { fun fromJson(json: Reader): CheckResults { diff --git a/Ext/Compose/README.md b/Ext/Compose/README.md index dac17bc13..b5c0e1dbd 100644 --- a/Ext/Compose/README.md +++ b/Ext/Compose/README.md @@ -12,7 +12,7 @@ Easily create screenshot tests for `@Composable` functions. ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` @@ -24,7 +24,7 @@ Ensure that `mavenCentral()` is available to both `pluginManagement` and `depend **Application build.gradle** ```groovy dependencies { - androidTestImplementation "dev.testify:testify-compose:3.2.3" + androidTestImplementation "dev.testify:testify-compose:4.0.0" androidTestImplementation "androidx.test:rules:1.5.0" androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.4.3" } diff --git a/Ext/Compose/build.gradle b/Ext/Compose/build.gradle index 47a207ee5..1dbe2394e 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 { @@ -106,5 +112,3 @@ android { afterEvaluate { apply from: "../../publish.build.gradle" } - -apply from: '../../ktlint.gradle' diff --git a/Ext/Compose/src/main/java/dev/testify/ComposableScreenshotRule.kt b/Ext/Compose/src/main/java/dev/testify/ComposableScreenshotRule.kt index f97c1ad9e..16fb79402 100644 --- a/Ext/Compose/src/main/java/dev/testify/ComposableScreenshotRule.kt +++ b/Ext/Compose/src/main/java/dev/testify/ComposableScreenshotRule.kt @@ -185,11 +185,12 @@ open class ComposableScreenshotRule( */ override fun beforeScreenshot(activity: Activity) { val targetView = activity.findRootView(rootViewId).getChildAt(0) - if (targetView.width == 0 && targetView.height == 0) + if (targetView.width == 0 && targetView.height == 0) { throw IllegalStateException( "Target view has 0 size. " + "Verify if you have provided a ComposeTestRule instance to ComposableScreenshotRule." ) + } super.beforeScreenshot(activity) } diff --git a/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt b/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt index 816145827..f7eec9f49 100644 --- a/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt +++ b/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Ext/Compose/src/main/java/dev/testify/compose/scenario/ComposableScreenshotScenarioRule.kt b/Ext/Compose/src/main/java/dev/testify/compose/scenario/ComposableScreenshotScenarioRule.kt index 98a64bc3a..a60bccdcc 100644 --- a/Ext/Compose/src/main/java/dev/testify/compose/scenario/ComposableScreenshotScenarioRule.kt +++ b/Ext/Compose/src/main/java/dev/testify/compose/scenario/ComposableScreenshotScenarioRule.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -206,12 +206,12 @@ open class ComposableScreenshotScenarioRule( */ override fun beforeScreenshot(activity: Activity) { val targetView = activity.findRootView(rootViewId).getChildAt(0) - if (targetView.width == 0 && targetView.height == 0) + if (targetView.width == 0 && targetView.height == 0) { throw IllegalStateException( - "Target view has 0 size. " + + "Target view has 0 size." + "Verify if you have provided a ComposeTestRule instance to ComposableScreenshotRule." ) - + } super.beforeScreenshot(activity) } diff --git a/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt b/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt index 1ef8834d3..12cc21633 100644 --- a/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt +++ b/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Ext/Fullscreen/README.md b/Ext/Fullscreen/README.md index f19e89d94..54ea8cc99 100644 --- a/Ext/Fullscreen/README.md +++ b/Ext/Fullscreen/README.md @@ -20,7 +20,7 @@ You can set a comparison tolerance using [ScreenshotRule.setExactness](../../Lib ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` @@ -31,7 +31,7 @@ Ensure that `mavenCentral()` is available to both `pluginManagement` and `depend **Application build.gradle** ```groovy dependencies { - androidTestImplementation "dev.testify:testify-fullscreen:3.2.3" + androidTestImplementation "dev.testify:testify-fullscreen:4.0.0" } ``` diff --git a/Ext/Fullscreen/build.gradle b/Ext/Fullscreen/build.gradle index a0e81200b..a9b51750d 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 { @@ -90,5 +92,3 @@ android { afterEvaluate { apply from: "../../publish.build.gradle" } - -apply from: '../../ktlint.gradle' diff --git a/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt b/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt index 35a531112..4ed10e69b 100644 --- a/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt +++ b/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt @@ -67,7 +67,6 @@ import dev.testify.testDescription */ @Suppress("UNUSED_PARAMETER") fun fullscreenCapture(activity: Activity, targetView: View?): Bitmap { - val instrumentation = getInstrumentation() val fileName = getFileName(instrumentation.context) val destination = getDestination(activity, fileName) diff --git a/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/provider/RealDisplaySize.kt b/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/provider/RealDisplaySize.kt index 088cd0dca..b8a4436c7 100644 --- a/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/provider/RealDisplaySize.kt +++ b/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/provider/RealDisplaySize.kt @@ -48,8 +48,9 @@ val Context.realDisplaySize: Size } else { (getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay }?.getRealSize(screenSize) - return if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) + return if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { Size(screenSize.x, screenSize.y) - else + } else { Size(screenSize.y, screenSize.x) + } } diff --git a/Library/build.gradle b/Library/build.gradle index d5d95d7ef..1cd1e2024 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") + } } } @@ -120,8 +124,6 @@ afterEvaluate { apply from: "../publish.build.gradle" } -apply from: '../ktlint.gradle' - tasks.withType(Test) { jacoco.includeNoLocationClasses = true jacoco.excludes = ['jdk.internal.*'] @@ -156,4 +158,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/AssertExpectedDeviceTest.kt b/Library/src/androidTest/java/dev/testify/AssertExpectedDeviceTest.kt index 3c5138bc5..775c17adb 100644 --- a/Library/src/androidTest/java/dev/testify/AssertExpectedDeviceTest.kt +++ b/Library/src/androidTest/java/dev/testify/AssertExpectedDeviceTest.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights 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/androidTest/java/dev/testify/RuleLifecycleTest.kt b/Library/src/androidTest/java/dev/testify/RuleLifecycleTest.kt index 05b8877ae..08289177b 100644 --- a/Library/src/androidTest/java/dev/testify/RuleLifecycleTest.kt +++ b/Library/src/androidTest/java/dev/testify/RuleLifecycleTest.kt @@ -73,7 +73,8 @@ class RuleLifecycleTest { } @Suppress("DEPRECATION") - @get:Rule val thrown: ExpectedException = ExpectedException.none() + @get:Rule + val thrown: ExpectedException = ExpectedException.none() @ScreenshotInstrumentation @Test diff --git a/Library/src/androidTest/java/dev/testify/core/processor/BitmapExtensionsTest.kt b/Library/src/androidTest/java/dev/testify/core/processor/BitmapExtensionsTest.kt index 8608f6185..d5369dfd9 100644 --- a/Library/src/androidTest/java/dev/testify/core/processor/BitmapExtensionsTest.kt +++ b/Library/src/androidTest/java/dev/testify/core/processor/BitmapExtensionsTest.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/androidTest/java/dev/testify/core/processor/ImageBufferTest.kt b/Library/src/androidTest/java/dev/testify/core/processor/ImageBufferTest.kt index 73183b260..c3cb31f67 100644 --- a/Library/src/androidTest/java/dev/testify/core/processor/ImageBufferTest.kt +++ b/Library/src/androidTest/java/dev/testify/core/processor/ImageBufferTest.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt index d716921da..4f5892ac9 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt @@ -85,7 +85,8 @@ class ScenarioTestRuleLifecycleTest { } @Suppress("DEPRECATION") - @get:Rule val thrown: ExpectedException = ExpectedException.none() + @get:Rule + val thrown: ExpectedException = ExpectedException.none() @ScreenshotInstrumentation @Test diff --git a/Library/src/debug/AndroidManifest.xml b/Library/src/debug/AndroidManifest.xml index b6476ae75..31e0baf07 100644 --- a/Library/src/debug/AndroidManifest.xml +++ b/Library/src/debug/AndroidManifest.xml @@ -1,7 +1,7 @@ - + diff --git a/Library/src/main/java/dev/testify/ExtrasProvider.kt b/Library/src/main/java/dev/testify/ExtrasProvider.kt index 6728c4fd6..915a885b1 100644 --- a/Library/src/main/java/dev/testify/ExtrasProvider.kt +++ b/Library/src/main/java/dev/testify/ExtrasProvider.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/ScreenshotRule.kt b/Library/src/main/java/dev/testify/ScreenshotRule.kt index c0f6e48dd..1951467d8 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() @@ -127,10 +127,11 @@ open class ScreenshotRule @JvmOverloads constructor( * @deprecated Use ScreenshotRule(activityClass, rootViewId, initialTouchMode, enableReporter, configuration) * Provided for backwards compatibility with the Testify 1.* architecture */ + @Suppress("ktlint:standard:max-line-length", "ktlint:standard:argument-list-wrapping") @ExcludeFromJacocoGeneratedReport @Deprecated( message = "Parameter launchActivity is deprecated and no longer required", - replaceWith = ReplaceWith("ScreenshotRule(activityClass = activityClass, rootViewId = rootViewId, initialTouchMode = initialTouchMode, enableReporter = enableReporter, configuration = TestifyConfiguration())") // ktlint-disable max-line-length + replaceWith = ReplaceWith("ScreenshotRule(activityClass = activityClass, rootViewId = rootViewId, initialTouchMode = initialTouchMode, enableReporter = enableReporter, configuration = TestifyConfiguration())") ) constructor( activityClass: Class, @@ -496,11 +497,12 @@ open class ScreenshotRule @JvmOverloads constructor( methodAnnotations ) - if (annotation == null) + if (annotation == null) { this.throwable = MissingScreenshotInstrumentationAnnotationException( annotationName = getScreenshotAnnotationName(), methodName = methodName ) + } } /** @@ -685,10 +687,11 @@ open class ScreenshotRule @JvmOverloads constructor( * Called by the [ScreenshotStatement] when a test method throws an exception. */ protected fun handleTestException(throwable: Throwable) { - if (throwable is ScreenshotTestIgnoredException || throwable is AssumptionViolatedException) + if (throwable is ScreenshotTestIgnoredException || throwable is AssumptionViolatedException) { reporter?.skip() - else + } else { reporter?.fail(throwable) + } throw throwable } } 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/TestDescription.kt b/Library/src/main/java/dev/testify/TestDescription.kt index bcfd42a24..145193303 100644 --- a/Library/src/main/java/dev/testify/TestDescription.kt +++ b/Library/src/main/java/dev/testify/TestDescription.kt @@ -89,6 +89,7 @@ var Instrumentation.testDescription: TestDescription TestDescription.hashCode = this.hashCode() TestDescription.current = value } + /** * Get the current [TestDescription] for the currently executing test. * @@ -96,8 +97,9 @@ var Instrumentation.testDescription: TestDescription * @throws UninitializedPropertyAccessException if the current [TestDescription] is not initialized. */ get() { - if (TestDescription.hashCode != this.hashCode()) + if (TestDescription.hashCode != this.hashCode()) { throw IllegalStateException("TestDescription is not initialized for $this") + } return TestDescription.current ?: throw UninitializedPropertyAccessException("TestDescription is not initialized") } diff --git a/Library/src/main/java/dev/testify/ViewModification.kt b/Library/src/main/java/dev/testify/ViewModification.kt index 1289e6430..39b4137f5 100644 --- a/Library/src/main/java/dev/testify/ViewModification.kt +++ b/Library/src/main/java/dev/testify/ViewModification.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/ViewProvider.kt b/Library/src/main/java/dev/testify/ViewProvider.kt index d52d8c65c..46fd8a2eb 100644 --- a/Library/src/main/java/dev/testify/ViewProvider.kt +++ b/Library/src/main/java/dev/testify/ViewProvider.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/core/AssertExpectedDevice.kt b/Library/src/main/java/dev/testify/core/AssertExpectedDevice.kt index b8f927261..b0c909d32 100644 --- a/Library/src/main/java/dev/testify/core/AssertExpectedDevice.kt +++ b/Library/src/main/java/dev/testify/core/AssertExpectedDevice.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/core/ConfigurationBuilder.kt b/Library/src/main/java/dev/testify/core/ConfigurationBuilder.kt index 36584884f..4f40891bd 100644 --- a/Library/src/main/java/dev/testify/core/ConfigurationBuilder.kt +++ b/Library/src/main/java/dev/testify/core/ConfigurationBuilder.kt @@ -73,10 +73,11 @@ class ConfigurationBuilder internal constructor(private val rule: enabled: Boolean = true, @IdRes focusTargetId: Int = android.R.id.content ): ConfigurationBuilder { - if (enabled) + if (enabled) { innerConfiguration.focusTargetId = focusTargetId - else + } else { innerConfiguration.focusTargetId = View.NO_ID + } return this } diff --git a/Library/src/main/java/dev/testify/core/DeviceIdentifier.kt b/Library/src/main/java/dev/testify/core/DeviceIdentifier.kt index 4253aaf17..16be0b3da 100644 --- a/Library/src/main/java/dev/testify/core/DeviceIdentifier.kt +++ b/Library/src/main/java/dev/testify/core/DeviceIdentifier.kt @@ -91,7 +91,6 @@ fun getDeviceDescription(targetContext: Context): String { * @return String - The formatted device description string */ fun formatDeviceString(formatter: DeviceStringFormatter, format: String): String { - val a = formatter.androidVersion val w = formatter.deviceWidth val h = formatter.deviceHeight 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/core/exception/LowMemoryException.kt b/Library/src/main/java/dev/testify/core/exception/LowMemoryException.kt index 9c496baad..80b837930 100644 --- a/Library/src/main/java/dev/testify/core/exception/LowMemoryException.kt +++ b/Library/src/main/java/dev/testify/core/exception/LowMemoryException.kt @@ -47,6 +47,7 @@ import dev.testify.core.formatDeviceString * @param memoryInfo - a string log of the device's current memory state. * @param cause - The OutOfMemoryError exception originally thrown */ +@Suppress("ktlint:standard:argument-list-wrapping") class LowMemoryException( targetContext: Context, requestedAllocation: Int, diff --git a/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt b/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt index ad3e9fcf2..3232d37ff 100644 --- a/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt +++ b/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/core/logic/AssertSame.kt b/Library/src/main/java/dev/testify/core/logic/AssertSame.kt index dc4cf3566..4db5bb5b7 100644 --- a/Library/src/main/java/dev/testify/core/logic/AssertSame.kt +++ b/Library/src/main/java/dev/testify/core/logic/AssertSame.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023-2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -133,8 +133,9 @@ internal fun assertSame( screenshotLifecycleHost.notifyObservers { it.afterScreenshot(activity, currentBitmap) } - if (configuration.pauseForInspection) + if (configuration.pauseForInspection) { pauseForInspection() + } val isRecordMode = isRecordMode() @@ -156,8 +157,9 @@ internal fun assertSame( TestInstrumentationRegistry.instrumentationPrintln( "\n\t✓ " + "Recording baseline for ${description.name}".cyan() ) - if (!destination.finalize()) + if (!destination.finalize()) { throw FinalizeDestinationException(destination.description) + } return } else { throw ScreenshotBaselineNotDefinedException( @@ -180,8 +182,9 @@ internal fun assertSame( deleteBitmap(destination) ) } else { - if (!destination.finalize()) + if (!destination.finalize()) { throw FinalizeDestinationException(destination.description) + } if (TestifyFeatures.GenerateDiffs.isEnabled(activity)) { HighContrastDiff diff --git a/Library/src/main/java/dev/testify/core/logic/AssertionState.kt b/Library/src/main/java/dev/testify/core/logic/AssertionState.kt index 5b4bf2cc1..4a155c110 100644 --- a/Library/src/main/java/dev/testify/core/logic/AssertionState.kt +++ b/Library/src/main/java/dev/testify/core/logic/AssertionState.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/core/logic/InitiliazeView.kt b/Library/src/main/java/dev/testify/core/logic/InitiliazeView.kt index 93444380e..d3ed671d4 100644 --- a/Library/src/main/java/dev/testify/core/logic/InitiliazeView.kt +++ b/Library/src/main/java/dev/testify/core/logic/InitiliazeView.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/core/logic/ScreenshotLifecycleHost.kt b/Library/src/main/java/dev/testify/core/logic/ScreenshotLifecycleHost.kt index aea336974..1f904e7e6 100644 --- a/Library/src/main/java/dev/testify/core/logic/ScreenshotLifecycleHost.kt +++ b/Library/src/main/java/dev/testify/core/logic/ScreenshotLifecycleHost.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/core/processor/ImageBuffer.kt b/Library/src/main/java/dev/testify/core/processor/ImageBuffer.kt index b22c1e2d4..17d8477e1 100644 --- a/Library/src/main/java/dev/testify/core/processor/ImageBuffer.kt +++ b/Library/src/main/java/dev/testify/core/processor/ImageBuffer.kt @@ -90,9 +90,9 @@ internal data class ImageBuffers( height = height, allocateDiffBuffer = allocateDiffBuffer ).apply { - if ((width.toLong() * height.toLong()) > Int.MAX_VALUE.toLong()) throw IllegalArgumentException( - "Requested size of $width x $height exceeds maximum buffer size" - ) + if ((width.toLong() * height.toLong()) > Int.MAX_VALUE.toLong()) { + throw IllegalArgumentException("Requested size of $width x $height exceeds maximum buffer size") + } val capacity = width * height if (capacity == 0) throw IllegalArgumentException("$width and $height must be positive integers") diff --git a/Library/src/main/java/dev/testify/core/processor/compare/FuzzyCompare.kt b/Library/src/main/java/dev/testify/core/processor/compare/FuzzyCompare.kt index 52e335940..04804d805 100644 --- a/Library/src/main/java/dev/testify/core/processor/compare/FuzzyCompare.kt +++ b/Library/src/main/java/dev/testify/core/processor/compare/FuzzyCompare.kt @@ -43,6 +43,7 @@ import dev.testify.core.processor.compare.colorspace.calculateDeltaE * @param configuration - The configuration to use for the comparison. * @param parallelProcessorConfiguration - The configuration for the [ParallelPixelProcessor]. */ +@Suppress("ktlint:standard:multiline-if-else") internal class FuzzyCompare( configuration: TestifyConfiguration, private val parallelProcessorConfiguration: ParallelProcessorConfiguration = ParallelProcessorConfiguration() diff --git a/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt b/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt index 006be1498..0f6f0eb70 100644 --- a/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt +++ b/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt @@ -68,8 +68,9 @@ class EspressoHelper(private val configuration: TestifyConfiguration) : Screensh syncUiThread() - if (configuration.hideSoftKeyboard) + if (configuration.hideSoftKeyboard) { closeSoftKeyboard() + } } /** diff --git a/Library/src/main/java/dev/testify/internal/helpers/IsRunningOnUiThread.kt b/Library/src/main/java/dev/testify/internal/helpers/IsRunningOnUiThread.kt index d397ec4a8..12008b786 100644 --- a/Library/src/main/java/dev/testify/internal/helpers/IsRunningOnUiThread.kt +++ b/Library/src/main/java/dev/testify/internal/helpers/IsRunningOnUiThread.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/internal/helpers/OutputFileName.kt b/Library/src/main/java/dev/testify/internal/helpers/OutputFileName.kt index a8e50cf25..78bf822c2 100644 --- a/Library/src/main/java/dev/testify/internal/helpers/OutputFileName.kt +++ b/Library/src/main/java/dev/testify/internal/helpers/OutputFileName.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt b/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt index ec3979402..e8b8f045b 100644 --- a/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt +++ b/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt @@ -206,15 +206,18 @@ object ResourceWrapper { * @param fontScale The font scale to override. If null, the font scale will not be overridden. * @param locale The locale to override. If null, the locale will not be overridden. */ +@Suppress("ktlint:standard:annotation") fun <@Suppress("unused") A : Activity> overrideResourceConfiguration( fontScale: Float? = null, locale: Locale? = null ) { - if (fontScale != null) + if (fontScale != null) { ResourceWrapper.addOverride(WrappedFontScale(fontScale)) + } - if (locale != null) + if (locale != null) { ResourceWrapper.addOverride(WrappedLocale(locale)) + } ResourceWrapper.beforeActivityLaunched() } 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/output/Destination.kt b/Library/src/main/java/dev/testify/output/Destination.kt index 4c5ad0dd4..3eca77a99 100644 --- a/Library/src/main/java/dev/testify/output/Destination.kt +++ b/Library/src/main/java/dev/testify/output/Destination.kt @@ -112,7 +112,6 @@ fun getDestination( customKey: String? = null, root: String? = null ): Destination { - /** * Get the value of the manifest placeholder for the destination */ diff --git a/Library/src/main/java/dev/testify/output/TestStorageDestination.kt b/Library/src/main/java/dev/testify/output/TestStorageDestination.kt index 7805b0517..a77331b0f 100644 --- a/Library/src/main/java/dev/testify/output/TestStorageDestination.kt +++ b/Library/src/main/java/dev/testify/output/TestStorageDestination.kt @@ -56,9 +56,7 @@ class TestStorageDestination( private val extension: String, key: String?, root: String? = null -) : DataDirectoryDestination( - context, fileName, extension, key, root -) { +) : DataDirectoryDestination(context, fileName, extension, key, root) { override val LOG_TAG: String = "TestStorageDestination" /** @@ -89,10 +87,11 @@ class TestStorageDestination( * Get the exception to throw when the destination is not found. */ override fun getScreenshotDestinationNotFoundException(): Exception { - return if (isTestStorageEnabled()) + return if (isTestStorageEnabled()) { super.getScreenshotDestinationNotFoundException() - else + } else { TestStorageNotFoundException() + } } /** @@ -108,8 +107,9 @@ class TestStorageDestination( if (outputStream == null) return false val buffer = ByteArray(1024) var length: Int - while (inputStream.read(buffer).also { length = it } > 0) + while (inputStream.read(buffer).also { length = it } > 0) { outputStream.write(buffer, 0, length) + } } } return true 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/report/TestStatus.kt b/Library/src/main/java/dev/testify/report/TestStatus.kt index 772199c3d..ed4911559 100644 --- a/Library/src/main/java/dev/testify/report/TestStatus.kt +++ b/Library/src/main/java/dev/testify/report/TestStatus.kt @@ -42,5 +42,5 @@ enum class TestStatus { /** * Test failed */ - FAIL; + FAIL } diff --git a/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt b/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt index 650060a39..05161ee88 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(), @@ -301,19 +301,21 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( scenario?.onActivity { activity = it } if (activity != null) { - if (configuration.fontScale != null) + if (configuration.fontScale != null) { throw NoResourceConfigurationOnScenarioException( cause = "fontScale", value = configuration.fontScale.toString(), activity = activity?.javaClass?.simpleName.orEmpty() ) + } - if (configuration.locale != null) + if (configuration.locale != null) { throw NoResourceConfigurationOnScenarioException( cause = "locale", value = configuration.locale.toString(), activity = activity?.javaClass?.simpleName.orEmpty() ) + } } return this @@ -430,11 +432,12 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( methodAnnotations ) - if (annotation == null) + if (annotation == null) { this.throwable = MissingScreenshotInstrumentationAnnotationException( annotationName = getScreenshotAnnotationName(), methodName = methodName ) + } } /** @@ -447,8 +450,9 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( getInstrumentation().waitForIdleSync() - if (configuration.hideSoftKeyboard) + if (configuration.hideSoftKeyboard) { closeSoftKeyboard() + } } /** @@ -501,10 +505,10 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( } ?: throw ScenarioRequiredException() } - context (ActivityScenario<*>) @JvmName("assertSameContext") + context (scenario: ActivityScenario<*>) 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/Library/src/test/java/dev/testify/report/ReporterTest.kt b/Library/src/test/java/dev/testify/report/ReporterTest.kt index 286873d8b..aad1931f4 100644 --- a/Library/src/test/java/dev/testify/report/ReporterTest.kt +++ b/Library/src/test/java/dev/testify/report/ReporterTest.kt @@ -159,7 +159,6 @@ internal open class ReporterTest { @Test fun `endTest() produces the expected yaml for an existing session`() { - reporter.endTest() assertEquals( diff --git a/Plugins/Gradle/README.md b/Plugins/Gradle/README.md index 7847b88cb..d38b3bafa 100644 --- a/Plugins/Gradle/README.md +++ b/Plugins/Gradle/README.md @@ -14,7 +14,7 @@ To set a dependency reference to the Testify plugin: ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` diff --git a/Plugins/Gradle/build.gradle b/Plugins/Gradle/build.gradle index 94f51d7b1..911db54bd 100644 --- a/Plugins/Gradle/build.gradle +++ b/Plugins/Gradle/build.gradle @@ -7,6 +7,9 @@ plugins { id 'org.jetbrains.kotlin.jvm' id 'org.jetbrains.dokka' id 'jacoco' + id 'maven-publish' + id 'signing' + id 'org.jlleitschuh.gradle.ktlint' version '13.1.0' } def gradleProperties = new Properties() @@ -100,7 +103,6 @@ tasks.register('javadocJar', Jar) { } apply from: "../../publish.build.gradle" -apply from: '../../ktlint.gradle' jacoco { toolVersion = "0.8.12" @@ -115,3 +117,17 @@ jacocoTestReport { html.outputLocation = layout.buildDirectory.dir('jacocoHtml') } } + +ktlint { + version.set("1.7.1") + additionalEditorconfig.set([ + "ktlint_code_style" : "android_studio", // Use Android Studio code style defaults + "ktlint_standard_class-signature" : "disabled", // Disable class signature wrapping enforcement + "ktlint_standard_function-expression-body" : "disabled", // Function body should be replaced with body expression + "ktlint_standard_function-signature" : "disabled", // Disable function signature wrapping enforcement + "ktlint_standard_import-ordering" : "disabled", // Disable import ordering rule + "ktlint_standard_no-unused-imports" : "enabled", // Enable unused-imports rule + "ktlint_standard_property-naming" : "disabled", // Disable property naming convention checks + "max_line_length" : "200" // Max line length before ktlint enforces wrapping + ]) +} diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/internal/Adb.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/internal/Adb.kt index e16cf76f7..fd7d0e4dc 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/internal/Adb.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/internal/Adb.kt @@ -71,8 +71,9 @@ class Adb { arguments("--user", "$forcedUser") } else { val user = Device.user - if (user.isNotEmpty() && (user.toIntOrNull() ?: 0) > 0) + if (user.isNotEmpty() && (user.toIntOrNull() ?: 0) > 0) { arguments("--user", user) + } } return this } @@ -111,7 +112,6 @@ class Adb { } fun testOptions(testOptionsBuilder: TestOptionsBuilder): Adb { - testOptionsBuilder.resolved.forEach { arguments.add(TestOptionsBuilder.TEST_OPTIONS_FLAG) arguments.add(it) diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/internal/DeviceUtilities.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/internal/DeviceUtilities.kt index 093f3f2c2..4ed98205c 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/internal/DeviceUtilities.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/internal/DeviceUtilities.kt @@ -33,16 +33,18 @@ import java.io.File internal val Project.root: String @Suppress("SdCardPath") - get() = testifySettings.rootDestinationDirectory ?: if (testifySettings.useSdCard) + get() = testifySettings.rootDestinationDirectory ?: if (testifySettings.useSdCard) { "/sdcard/Android/data/${testifySettings.targetPackageId}/files/testify_" - else + } else { "./app_" + } internal val Project.screenshotDirectory: String - get() = if (testifySettings.useSdCard) + get() = if (testifySettings.useSdCard) { "${root}images/" - else + } else { "${root}images/$SCREENSHOT_DIR" + } internal fun Adb.listFiles(path: String): List { val log = this diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/ReportTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/ReportTask.kt index 30d856faf..2896902fa 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/ReportTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/ReportTask.kt @@ -30,8 +30,11 @@ import org.gradle.api.tasks.Internal abstract class ReportTask : TestifyDefaultTask() { - @get:Input lateinit var reportFileName: String - @get:Input lateinit var reportPath: String + @get:Input + lateinit var reportFileName: String + + @get:Input + lateinit var reportPath: String override fun getGroup() = "Testify reports" diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/TestifyDefaultTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/TestifyDefaultTask.kt index 3679f8532..96550e6b4 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/TestifyDefaultTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/internal/TestifyDefaultTask.kt @@ -61,9 +61,11 @@ abstract class TestifyDefaultTask : DefaultTask() { internal open fun provideInput(project: Project) {} protected open fun beforeAction() { - if (isDeviceRequired && Device.isEmpty) throw GradleException( - "No Android Virtual Device found. Please start an emulator prior to running Testify tasks." - ) + if (isDeviceRequired && Device.isEmpty) { + throw GradleException( + "No Android Virtual Device found. Please start an emulator prior to running Testify tasks." + ) + } } @TaskAction diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotClearTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotClearTask.kt index dae1ab729..c87846a7a 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotClearTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotClearTask.kt @@ -41,9 +41,14 @@ import java.io.File open class ScreenshotClearTask : TestifyDefaultTask() { - @get:Input lateinit var screenshotDirectory: String - @get:Input lateinit var targetPackageId: String - @get:Input var isVerbose: Boolean = false + @get:Input + lateinit var screenshotDirectory: String + + @get:Input + lateinit var targetPackageId: String + + @get:Input + var isVerbose: Boolean = false override fun getDescription() = "Remove any existing screenshot test images from the device" diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotPullTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotPullTask.kt index c1a67d218..086984924 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotPullTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotPullTask.kt @@ -46,11 +46,20 @@ import java.io.FileOutputStream open class ScreenshotPullTask : TestifyDefaultTask() { - @get:Input lateinit var screenshotDirectory: String - @get:Input lateinit var destinationImageDirectory: String - @get:Input lateinit var targetPackageId: String - @get:Input var isVerbose: Boolean = false - @get:Input var pullWaitTime: Long = 0L + @get:Input + lateinit var screenshotDirectory: String + + @get:Input + lateinit var destinationImageDirectory: String + + @get:Input + lateinit var targetPackageId: String + + @get:Input + var isVerbose: Boolean = false + + @get:Input + var pullWaitTime: Long = 0L override fun getDescription() = "Pull screenshots from the device and wait for all files to be committed to disk" @@ -108,7 +117,6 @@ open class ScreenshotPullTask : TestifyDefaultTask() { ) failedScreenshots.forEach { - val localPath = it.toLocalPath() if (isVerbose) { diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotTestTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotTestTask.kt index 6aa6d0393..813f38cf4 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotTestTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/main/ScreenshotTestTask.kt @@ -47,16 +47,41 @@ import org.gradle.api.tasks.Optional open class ScreenshotTestTask : TestifyDefaultTask() { - @Optional @get:Input var moduleName: String? = null - @Optional @get:Input var outputFormat: String? = null - @Optional @get:Input var shardCount: Int? = null - @Optional @get:Input var shardIndex: Int? = null - @Optional @get:Input var testClass: String? = null - @Optional @get:Input var testName: String? = null - @get:Input lateinit var screenshotAnnotation: String - @get:Input lateinit var testPackageId: String - @get:Input lateinit var testRunner: String - @get:Input var useSdCard: Boolean = false + @Optional + @get:Input + var moduleName: String? = null + + @Optional + @get:Input + var outputFormat: String? = null + + @Optional + @get:Input + var shardCount: Int? = null + + @Optional + @get:Input + var shardIndex: Int? = null + + @Optional + @get:Input + var testClass: String? = null + + @Optional + @get:Input + var testName: String? = null + + @get:Input + lateinit var screenshotAnnotation: String + + @get:Input + lateinit var testPackageId: String + + @get:Input + lateinit var testRunner: String + + @get:Input + var useSdCard: Boolean = false override fun getDescription() = "Run the Testify screenshot tests" @@ -84,8 +109,9 @@ open class ScreenshotTestTask : TestifyDefaultTask() { protected open fun getRuntimeParams(): List { val params = ArrayList() - if (useSdCard) + if (useSdCard) { params.add(AdbParam("useSdCard", "true")) + } outputFormat.letNotEmpty { params.add(AdbParam("outputFileNameFormat", it)) diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportPullTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportPullTask.kt index 97d18dee9..66df22cad 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportPullTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportPullTask.kt @@ -47,10 +47,17 @@ import java.io.FileOutputStream open class ReportPullTask : ReportTask() { - @get:Input lateinit var reportFilePath: String - @get:Input lateinit var targetPackageId: String - @get:Input var isVerbose: Boolean = false - @get:Input var pullWaitTime: Long = 0L + @get:Input + lateinit var reportFilePath: String + + @get:Input + lateinit var targetPackageId: String + + @get:Input + var isVerbose: Boolean = false + + @get:Input + var pullWaitTime: Long = 0L override fun getDescription() = "Pull $DEFAULT_REPORT_FILE_NAME from the device and wait for it to be committed to disk" @@ -92,7 +99,6 @@ open class ReportPullTask : ReportTask() { } private fun pull(sourceFilePath: String, destinationPath: String) { - File(destinationPath).assurePath() val destinationFile = File(destinationPath, reportName) diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportShowTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportShowTask.kt index cce3e97ec..044445c4e 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportShowTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/report/ReportShowTask.kt @@ -40,8 +40,11 @@ import org.gradle.api.tasks.Input open class ReportShowTask : ReportTask() { - @get:Input lateinit var reportFilePath: String - @get:Input lateinit var targetPackageId: String + @get:Input + lateinit var reportFilePath: String + + @get:Input + lateinit var targetPackageId: String override fun getDescription() = "Print the test result report to the console" diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/DisableSoftKeyboardTask.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/DisableSoftKeyboardTask.kt index dde0aaa61..e92fab0ea 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/DisableSoftKeyboardTask.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/DisableSoftKeyboardTask.kt @@ -34,7 +34,6 @@ open class DisableSoftKeyboardTask : TestifyUtilityTask() { override fun getDescription() = "Disables the soft keyboard on the device" override fun taskAction() { - Adb().arguments( "shell", "settings", diff --git a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/HidePasswordsTasks.kt b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/HidePasswordsTasks.kt index bdb0e87c1..b8bbb6957 100644 --- a/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/HidePasswordsTasks.kt +++ b/Plugins/Gradle/src/main/kotlin/dev/testify/tasks/utility/HidePasswordsTasks.kt @@ -34,7 +34,6 @@ open class HidePasswordsTasks : TestifyUtilityTask() { override fun getDescription() = "Hides passwords fully on the device" override fun taskAction() { - Adb().arguments( "shell", "settings", diff --git a/Plugins/Gradle/src/test/kotlin/dev/testify/internal/AdbTest.kt b/Plugins/Gradle/src/test/kotlin/dev/testify/internal/AdbTest.kt index d2205516b..4d4380ce4 100644 --- a/Plugins/Gradle/src/test/kotlin/dev/testify/internal/AdbTest.kt +++ b/Plugins/Gradle/src/test/kotlin/dev/testify/internal/AdbTest.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023-2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -41,7 +41,6 @@ import org.junit.jupiter.api.assertThrows import java.io.File class AdbTest : BaseTest() { - @RelaxedMockK lateinit var project: Project @@ -53,10 +52,11 @@ class AdbTest : BaseTest() { private var processLog = mutableListOf() - private val defaultResultMap = mapOf( - "devices" to "emulator-5554\tdevice", - "get-current-user" to "0" - ) + private val defaultResultMap = + mapOf( + "devices" to "emulator-5554\tdevice", + "get-current-user" to "0" + ) private lateinit var subject: Adb diff --git a/Plugins/Gradle/src/test/kotlin/dev/testify/internal/TestOptionsBuilderTest.kt b/Plugins/Gradle/src/test/kotlin/dev/testify/internal/TestOptionsBuilderTest.kt index 3d1ec4543..c87095637 100644 --- a/Plugins/Gradle/src/test/kotlin/dev/testify/internal/TestOptionsBuilderTest.kt +++ b/Plugins/Gradle/src/test/kotlin/dev/testify/internal/TestOptionsBuilderTest.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023-2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -27,7 +27,6 @@ import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Test class TestOptionsBuilderTest { - private val subject: TestOptionsBuilder = TestOptionsBuilder() @Test diff --git a/Plugins/Gradle/src/test/kotlin/dev/testify/tasks/ConfigurationCacheTest.kt b/Plugins/Gradle/src/test/kotlin/dev/testify/tasks/ConfigurationCacheTest.kt index 3d7bf7cf0..54561b4b0 100644 --- a/Plugins/Gradle/src/test/kotlin/dev/testify/tasks/ConfigurationCacheTest.kt +++ b/Plugins/Gradle/src/test/kotlin/dev/testify/tasks/ConfigurationCacheTest.kt @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2024 ndtp - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -34,9 +34,7 @@ import org.junit.jupiter.params.provider.ValueSource import java.io.File class ConfigurationCacheTest { - companion object { - @field:TempDir @JvmField var testProjectDir: File? = null @@ -44,11 +42,15 @@ class ConfigurationCacheTest { private var settingsFile: File? = null private var buildFile: File? = null + @Suppress("ktlint") @BeforeAll @JvmStatic fun setup() { settingsFile = File(testProjectDir, "settings.gradle") - buildFile = File(testProjectDir, "build.gradle").apply { + buildFile = File( + testProjectDir, + "build.gradle" + ).apply { writeText("plugins { id 'dev.testify' }") } } @@ -62,24 +64,26 @@ class ConfigurationCacheTest { "--configuration-cache", ":LegacySample:$taskName", "-PtestClass=dev.testify.sample.MainActivityScreenshotTest#default" - ) - .build() + ).build() private fun assertCacheReused(result: BuildResult) = assertThat(result.output).contains("Configuration cache entry reused.") - private fun assumeDevice(isDeviceRequired: Boolean, exactly: Int = 1) { + private fun assumeDevice( + isDeviceRequired: Boolean, + exactly: Int = 1 + ) { if (isDeviceRequired) { - assume().that( - GradleRunner - .create() - .withProjectDir(File("../..")) - .withArguments( - ":LegacySample:testifyDevices", - ) - .build() - .output - ).contains("Connected devices = $exactly") + assume() + .that( + GradleRunner + .create() + .withProjectDir(File("../..")) + .withArguments( + ":LegacySample:testifyDevices", + ).build() + .output + ).contains("Connected devices = $exactly") } } diff --git a/Plugins/Gradle/src/test/kotlin/dev/testify/test/BaseTest.kt b/Plugins/Gradle/src/test/kotlin/dev/testify/test/BaseTest.kt index c9080da82..90181bb60 100644 --- a/Plugins/Gradle/src/test/kotlin/dev/testify/test/BaseTest.kt +++ b/Plugins/Gradle/src/test/kotlin/dev/testify/test/BaseTest.kt @@ -7,14 +7,12 @@ import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach abstract class BaseTest { - @BeforeEach open fun setUp() { MockKAnnotations.init(this) } companion object { - @AfterAll @JvmStatic fun tearDown() { diff --git a/README.md b/README.md index 8b28d1c5f..e0fb36a42 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Testify plugin: ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` 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/androidTest/java/dev/testify/samples/flix/test/TestImageLoader.kt b/Samples/Flix/FlixLibrary/src/androidTest/java/dev/testify/samples/flix/test/TestImageLoader.kt index 34fad35a2..13c0b81ed 100644 --- a/Samples/Flix/FlixLibrary/src/androidTest/java/dev/testify/samples/flix/test/TestImageLoader.kt +++ b/Samples/Flix/FlixLibrary/src/androidTest/java/dev/testify/samples/flix/test/TestImageLoader.kt @@ -49,4 +49,3 @@ fun setSynchronousImageLoader() { val imageLoader = ImageLoader.Builder(context).dispatcher(synchronousDispatcher()).build() Coil.setImageLoader(imageLoader) } - 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..c1e0fe96e 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,39 @@ 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-logging:3.2.3") + implementation("io.ktor:ktor-client-content-negotiation:3.2.3") + implementation("io.ktor:ktor-serialization-kotlinx-json:3.2.3") // Test Support testImplementation 'junit:junit:4.13.2' @@ -123,9 +130,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..2fb37b78a 100644 --- a/Samples/Legacy/build.gradle +++ b/Samples/Legacy/build.gradle @@ -2,10 +2,9 @@ buildscript { ext { versions = [ 'compose': [ - 'compilerExt': '1.5.14', - 'core' : '1.5.14', - 'material' : '1.6.7', - 'ui' : '1.6.7', + 'compilerExt': '1.9.0', + 'material' : '1.9.0', + 'ui' : '1.9.0', ] ] } @@ -15,24 +14,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/assets/screenshots/29-1080x2220@440dp-en_US/ComposableScreenshotTest_dropdownMenu.png b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposableScreenshotTest_dropdownMenu.png index e003c45e5..794ccde19 100644 Binary files a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposableScreenshotTest_dropdownMenu.png and b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposableScreenshotTest_dropdownMenu.png differ diff --git a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeActivityScreenshotTest_default.png b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeActivityScreenshotTest_default.png index 1fc7bccef..0370d7c9d 100644 Binary files a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeActivityScreenshotTest_default.png and b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeActivityScreenshotTest_default.png differ diff --git a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeRuleInteropScreenshotTest_default.png b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeRuleInteropScreenshotTest_default.png index 57da7bc90..059a38d5f 100644 Binary files a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeRuleInteropScreenshotTest_default.png and b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ComposeRuleInteropScreenshotTest_default.png differ diff --git a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposableScreenshotTest_dropdownMenu.png b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposableScreenshotTest_dropdownMenu.png index 4d10a130c..794ccde19 100644 Binary files a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposableScreenshotTest_dropdownMenu.png and b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposableScreenshotTest_dropdownMenu.png differ diff --git a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeActivityScreenshotTest_default.png b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeActivityScreenshotTest_default.png index 1fc7bccef..0370d7c9d 100644 Binary files a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeActivityScreenshotTest_default.png and b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeActivityScreenshotTest_default.png differ diff --git a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeRuleInteropScreenshotTest_default.png b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeRuleInteropScreenshotTest_default.png index 57da7bc90..059a38d5f 100644 Binary files a/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeRuleInteropScreenshotTest_default.png and b/Samples/Legacy/src/androidTest/assets/screenshots/29-1080x2220@440dp-en_US/ScenarioComposeRuleInteropScreenshotTest_default.png differ 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 b06c246d0..8252cfd07 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" @@ -178,7 +178,7 @@ workflows: - gradle-runner@2: inputs: - gradlew_path: "./gradlew" - - gradle_task: Library:ktlint + - gradle_task: Library:ktlintCheck title: KtLint - android-unit-test@1: inputs: @@ -213,7 +213,7 @@ workflows: - gradle-runner@2: inputs: - gradlew_path: "./gradlew" - - gradle_task: Plugin:ktlint + - gradle_task: Plugin:ktlintCheck title: KtLint - gradle-unit-test@1: inputs: @@ -241,7 +241,7 @@ workflows: - gradle-runner@2: inputs: - gradlew_path: "./gradlew" - - gradle_task: Accessibility:ktlint + - gradle_task: Accessibility:ktlintCheck title: KtLint - gradle-runner@2: inputs: @@ -266,7 +266,7 @@ workflows: - gradle-runner@2: inputs: - gradlew_path: "./gradlew" - - gradle_task: ComposeExtensions:ktlint + - gradle_task: ComposeExtensions:ktlintCheck title: KtLint - gradle-runner@2: inputs: @@ -291,7 +291,7 @@ workflows: - gradle-runner@2: inputs: - gradlew_path: "./gradlew" - - gradle_task: FullscreenCaptureMethod:ktlint + - gradle_task: FullscreenCaptureMethod:ktlintCheck title: KtLint - gradle-runner@2: inputs: diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 6c4fc0579..000000000 --- a/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -plugins { - alias(libs.plugins.android.application) apply false - alias(libs.plugins.android.library) apply false - alias(libs.plugins.google.android.libraries.mapsplatform.secrets) apply false - alias(libs.plugins.google.dagger.hilt.android) apply false - alias(libs.plugins.jetbrains.dokka) apply false - alias(libs.plugins.jetbrains.kotlin.android) apply false - alias(libs.plugins.jetbrains.kotlin.plugin.serialization) apply false - id "dev.testify" apply false -} - -tasks.register('clean', Delete) { - delete rootProject.buildDir -} - -allprojects { - configurations.configureEach { - resolutionStrategy.force 'org.objenesis:objenesis:2.6' - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..be2055974 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.google.android.libraries.mapsplatform.secrets) apply false + alias(libs.plugins.google.dagger.hilt.android) apply false + alias(libs.plugins.jetbrains.dokka) apply false + alias(libs.plugins.jetbrains.kotlin.android) apply false + alias(libs.plugins.jetbrains.kotlin.plugin.serialization) apply false + alias(libs.plugins.ktlint) + id("dev.testify") apply false +} + +allprojects { + apply(plugin = rootProject.libs.plugins.ktlint.get().pluginId) + ktlint { + version.set("1.7.1") + additionalEditorconfig.set( + mapOf( + "ktlint_code_style" to "android_studio", // Use Android Studio code style defaults + "ktlint_standard_class-signature" to "disabled", // Disable class signature wrapping enforcement + "ktlint_standard_function-expression-body" to "disabled", // Function body should be replaced with body expression + "ktlint_standard_function-signature" to "disabled", // Disable function signature wrapping enforcement + "ktlint_standard_import-ordering" to "disabled", // Disable import ordering rule + "ktlint_standard_no-unused-imports" to "enabled", // Enable unused-imports rule + "ktlint_standard_property-naming" to "disabled", // Disable property naming convention checks + "max_line_length" to "200", // Max line length before ktlint enforces wrapping + ) + + ) + filter { + exclude { + it.file.path.startsWith("${layout.buildDirectory.get()}/generated/") + } + } + } +} diff --git a/docs/docs/extensions/accessibility/1-setup.md b/docs/docs/extensions/accessibility/1-setup.md index 521eb65e0..5b3e836ae 100644 --- a/docs/docs/extensions/accessibility/1-setup.md +++ b/docs/docs/extensions/accessibility/1-setup.md @@ -10,7 +10,7 @@ In order to use the Android Testify Accessibility Checks extension, you must fir ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` @@ -25,6 +25,6 @@ The Android Testify Accessibility Checks extension is packaged as a separate art **Application build.gradle** ```groovy dependencies { - androidTestImplementation "dev.testify:testify-accessibility:3.2.3" + androidTestImplementation "dev.testify:testify-accessibility:4.0.0" } ``` diff --git a/docs/docs/extensions/compose/1-setup.md b/docs/docs/extensions/compose/1-setup.md index c1079d574..a04c1a2c6 100644 --- a/docs/docs/extensions/compose/1-setup.md +++ b/docs/docs/extensions/compose/1-setup.md @@ -10,7 +10,7 @@ In order to use the Android Testify Compose extension, you must first configure ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` @@ -26,7 +26,7 @@ The Android Testify Compose extension is packaged as a separate artifact. You mu **Application build.gradle** ```groovy dependencies { - androidTestImplementation "dev.testify:testify-compose:3.2.3" + androidTestImplementation "dev.testify:testify-compose:4.0.0" androidTestImplementation "androidx.test:rules:1.10.0" androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.4.3" } diff --git a/docs/docs/extensions/fullscreen/1-setup.md b/docs/docs/extensions/fullscreen/1-setup.md index 3cb421f42..945feee07 100644 --- a/docs/docs/extensions/fullscreen/1-setup.md +++ b/docs/docs/extensions/fullscreen/1-setup.md @@ -10,7 +10,7 @@ In order to use the Android Testify Fullscreen Capture Method extension, you mus ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` @@ -26,6 +26,6 @@ The Android Testify Fullscreen Capture Method extension is packaged as a separat **Application build.gradle** ```groovy dependencies { - androidTestImplementation "dev.testify:testify-fullscreen:3.2.3" + androidTestImplementation "dev.testify:testify-fullscreen:4.0.0" } ``` diff --git a/docs/docs/get-started/1-setup.md b/docs/docs/get-started/1-setup.md index 0fcc85507..81294046d 100644 --- a/docs/docs/get-started/1-setup.md +++ b/docs/docs/get-started/1-setup.md @@ -6,7 +6,7 @@ Before building your screenshot test with Testify, make sure to set a dependency ```groovy plugins { - id("dev.testify") version "3.2.3" apply false + id("dev.testify") version "4.0.0" apply false } ``` diff --git a/gradle.properties b/gradle.properties index 49cce9e1d..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.3 +testify_version=4.0.0 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4487e553a..b40c7e2a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,38 +1,39 @@ [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.13.0" +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.1.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" +ktlint = "13.1.0" +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" +rules = "1.7.0" +runner = "1.7.0" +slf4jJdk14 = "2.0.17" testStorage = "1.6.0" -truth = "1.1.5" -uiTestJunit4 = "1.4.3" +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" } @@ -69,8 +70,10 @@ truth = { module = "com.google.truth:truth", version.ref = "truth" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } google-android-libraries-mapsplatform-secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "mapsplatformSecrets" } google-dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } 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" } +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint"} 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..4f19d1247 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:1.7.1" // 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 c4bc6ab60..532a35ff1 100644 --- a/publish.build.gradle +++ b/publish.build.gradle @@ -1,6 +1,3 @@ -apply plugin: 'maven-publish' -apply plugin: 'signing' - dokkaJavadoc { dokkaSourceSets { configureEach { diff --git a/update_version.sh b/update_version.sh new file mode 100755 index 000000000..000b7aacc --- /dev/null +++ b/update_version.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: ./update_version.sh +# Example: ./update_version.sh 3.2.2 4.0.0 + +OLD_VERSION="$1" +NEW_VERSION="$2" + +echo "Updating Testify version: $OLD_VERSION → $NEW_VERSION" +echo "" + +# 1. Update plugin version and dependency references +echo "Updating Markdown files..." + +find . -type f -name "*.md" ! -path "*/docs/node_modules/*" | while read -r file; do + updated=false + + # Update plugin block: id("dev.testify") version "x.y.z" + if grep -q 'id("dev.testify")' "$file"; then + sed -i.bak -E \ + "s/(id\\(\"dev\\.testify\"\\) version \")${OLD_VERSION}(\" apply false)/\\1${NEW_VERSION}\\2/g" \ + "$file" + updated=true + fi + + # Update dependency lines: androidTestImplementation "dev.testify::x.y.z" + if grep -q 'dev.testify:' "$file"; then + sed -i.bak -E \ + "s/(dev\\.testify:[^\":]+:)${OLD_VERSION}/\\1${NEW_VERSION}/g" \ + "$file" + updated=true + fi + + if [ "$updated" = true ]; then + rm -f "${file}.bak" + echo " Updated $file" + else + rm -f "${file}.bak" 2>/dev/null || true + fi +done + +# 2. Update CHANGELOG.md files +echo "" +echo "Updating CHANGELOG entries..." + +find . -type f -name "CHANGELOG.md" ! -path "*/docs/node_modules/*" | while read -r changelog; do + if ! grep -q "## ${NEW_VERSION}" "$changelog"; then + tmpfile=$(mktemp) + { + echo "## ${NEW_VERSION}" + echo "" + echo "- TODO: Add changes here" + echo "" + echo "---" + echo "" + cat "$changelog" + } > "$tmpfile" + mv "$tmpfile" "$changelog" + echo " Added entry to $changelog" + else + echo " Skipped $changelog (entry already exists)" + fi +done + +echo "" +echo "✅ All done!"