Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved AssetTest and Assertions into an android testutils package #586

Merged
merged 8 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions android/testutils/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
load("@rules_kotlin//kotlin:android.bzl", "kt_android_library")
load("@rules_player//kotlin:defs.bzl", "lint")
load("@build_constants//:constants.bzl", "VERSION")
load("//jvm:defs.bzl", "distribution")
load(":deps.bzl", "main_deps")

kt_android_library(
name = "testutils_android",
srcs = glob(["src/main/java/**/*.kt"]),
custom_package = "com.intuit.playerui.android.testutils",
manifest = ":src/main/AndroidManifest.xml",
resource_files = glob(["src/main/res/**"]),
deps = main_deps,
)

android_library(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this wrap necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I need it for the specific maven coordinates?

name = "testutils",
custom_package = "com.intuit.playerui.android.testutils",
manifest = ":src/main/AndroidManifest.xml",
resource_files = glob(["src/main/res/**"]),
tags = ["maven_coordinates=com.intuit.playerui.android:testutils:aar:%s" % VERSION],
visibility = ["//visibility:public"],
exports = [":testutils_android"],
deps = main_deps,
)

distribution(
name = "testutils",
maven_coordinates = "com.intuit.playerui.android:testutils:%s" % VERSION,
)

lint(
name = "testutils",
srcs = glob(["src/main/**/*.kt"]),
lint_config = "//jvm:lint_config",
)
3 changes: 3 additions & 0 deletions android/testutils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Test Utilities

Along with some generic utilities, this module exposes some base test classes to provide some structure to similar Player integration tests or runtime tests. These are built on JUnit Jupiter and require the concrete tests to be written using the JUnit Jupiter API.
3 changes: 3 additions & 0 deletions android/testutils/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.intuit.playerui.android.testutils">
<uses-sdk android:minSdkVersion="14" />
</manifest>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.intuit.playerui.android.reference.assets.test
package com.intuit.playerui.android.testutils.asset

import android.view.View
import com.intuit.playerui.android.asset.RenderableAsset
Expand All @@ -10,7 +10,7 @@ import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract

@OptIn(ExperimentalContracts::class)
inline fun <reified T : RenderableAsset> Any?.shouldBeAsset(
public inline fun <reified T : RenderableAsset> Any?.shouldBeAsset(
block: T.() -> Unit = {},
): T {
shouldBeInstanceOf<T>(this)
Expand All @@ -19,7 +19,7 @@ inline fun <reified T : RenderableAsset> Any?.shouldBeAsset(
}

@OptIn(ExperimentalContracts::class)
inline fun <reified T : View> Any?.shouldBeView(assertions: T.() -> Unit = {}): T {
public inline fun <reified T : View> Any?.shouldBeView(assertions: T.() -> Unit = {}): T {
val view = if (T::class != SuspendableAsset.AsyncViewStub::class && this is SuspendableAsset.AsyncViewStub) {
runBlocking {
awaitView()
Expand All @@ -33,14 +33,14 @@ inline fun <reified T : View> Any?.shouldBeView(assertions: T.() -> Unit = {}):
}

@OptIn(ExperimentalContracts::class)
inline fun <reified T : PlayerFlowState> PlayerFlowState?.shouldBePlayerState(assertions: T.() -> Unit = {}): T {
public inline fun <reified T : PlayerFlowState> PlayerFlowState?.shouldBePlayerState(assertions: T.() -> Unit = {}): T {
shouldBeInstanceOf<T>(this)
assertions()
return this
}

@ExperimentalContracts
inline fun <reified T> shouldBeInstanceOf(
public inline fun <reified T> shouldBeInstanceOf(
`this`: Any?,
) {
contract {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.intuit.playerui.android.reference.assets.test
package com.intuit.playerui.android.testutils.asset

import android.content.Context
import android.view.View
Expand Down Expand Up @@ -46,16 +46,16 @@ import org.robolectric.annotation.Config
@RunWith(AndroidJUnit4::class)
@Config(sdk = [28])
@OptIn(ExperimentalCoroutinesApi::class)
abstract class AssetTest(val group: String? = null) {
public abstract class AssetTest(private val group: String? = null) {

@get:Rule
val name = TestName()
public val name: TestName = TestName()

open val plugins: List<Plugin> by lazy { listOf(ReferenceAssetsPlugin(), CommonTypesPlugin(), PendingTransactionPlugin()) }
protected open val plugins: List<Plugin> by lazy { listOf(ReferenceAssetsPlugin(), CommonTypesPlugin(), PendingTransactionPlugin()) }

val context: Context get() = ApplicationProvider.getApplicationContext()
protected val context: Context get() = ApplicationProvider.getApplicationContext()

val player by lazy {
protected val player: AndroidPlayer by lazy {
AndroidPlayer(plugins)
}

Expand All @@ -75,7 +75,7 @@ abstract class AssetTest(val group: String? = null) {
throw AssertionError("Expected view to update, but it did not.", exception)
}

var currentAssetTree: RenderableAsset? = null; private set(value) {
protected var currentAssetTree: RenderableAsset? = null; private set(value) {
// reset view on new asset
currentView = null

Expand All @@ -89,7 +89,7 @@ abstract class AssetTest(val group: String? = null) {
}
}

var currentView: View? = null; get() = field ?: blockUntilRendered()
protected var currentView: View? = null; get() = field ?: blockUntilRendered()
set(value) {
field = value.also {
// reset replay cache to clear value if the current value is set to null
Expand All @@ -99,14 +99,14 @@ abstract class AssetTest(val group: String? = null) {

protected val currentState: PlayerFlowState get() = player.state

protected val mocks get() = ClassLoaderMocksReader(context.classLoader).mocks.filter {
protected val mocks: List<ClassLoaderMock> get() = ClassLoaderMocksReader(context.classLoader).mocks.filter {
group == null || group == it.group
}

private val emptyView = View(context)

@Before
fun beforeEach() {
public fun beforeEach() {
Dispatchers.setMain(TestCoroutineDispatcher())
player.onUpdate { asset, _ -> currentAssetTree = asset }
player.hooks.state.tap { state ->
Expand All @@ -118,34 +118,34 @@ abstract class AssetTest(val group: String? = null) {
}

@After
fun afterEach() {
public fun afterEach() {
Dispatchers.resetMain()
}

fun launchMock() = launchMock(name.methodName)
protected fun launchMock(): Unit = launchMock(name.methodName)

fun launchMock(name: String) = launchMock(
protected fun launchMock(name: String): Unit = launchMock(
mocks.find { it.name == name || it.name == "$group-$name" }
?: throw IllegalArgumentException("$name not found in mocks: ${mocks.map { "${it.group}/${it.name}" }}"),
)

fun launchMock(mock: Mock<*>) = launchJson(
protected fun launchMock(mock: Mock<*>): Unit = launchJson(
when (mock) {
is ClassLoaderMock -> mock.getFlow(context.classLoader)
else -> throw IllegalArgumentException("mock of type ${mock::class.java.simpleName} not supported")
},
)

fun launchJson(json: JsonElement) = launchJson(Json.encodeToString(json))
protected fun launchJson(json: JsonElement): Unit = launchJson(Json.encodeToString(json))

fun launchJson(json: String) = player.start(makeFlow(json)).onComplete {
protected fun launchJson(json: String): Unit = player.start(makeFlow(json)).onComplete {
it.exceptionOrNull()?.printStackTrace()
}

/** Suspend until we have a [View] representation of [currentAssetTree] that is _completely_ hydrated */
suspend fun awaitRendered(timeout: Long = 5_000): View = consumeLatestView(timeout)
protected suspend fun awaitRendered(timeout: Long = 5_000): View = consumeLatestView(timeout)

fun blockUntilRendered(timeout: Long = 5_000) = runBlocking {
protected fun blockUntilRendered(timeout: Long = 5_000): View = runBlocking {
awaitRendered(timeout)
}

Expand Down
2 changes: 1 addition & 1 deletion plugins/reference-assets/android/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def kt_asset_test(
test_class = test_class,
deps = deps + [
"//tools/mocks:jar",
"//plugins/reference-assets/android/src/androidTest/java/com/intuit/playerui/android/reference/assets/test",
"//android/testutils",
"//jvm/j2v8:j2v8-all",
],
resources = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import android.widget.Button
import android.widget.LinearLayout
import androidx.core.view.get
import com.intuit.playerui.android.reference.assets.R
import com.intuit.playerui.android.reference.assets.test.AssetTest
import com.intuit.playerui.android.reference.assets.test.shouldBeAsset
import com.intuit.playerui.android.reference.assets.test.shouldBePlayerState
import com.intuit.playerui.android.reference.assets.test.shouldBeView
import com.intuit.playerui.android.reference.assets.text.Text
import com.intuit.playerui.android.testutils.asset.AssetTest
import com.intuit.playerui.android.testutils.asset.shouldBeAsset
import com.intuit.playerui.android.testutils.asset.shouldBePlayerState
import com.intuit.playerui.android.testutils.asset.shouldBeView
import com.intuit.playerui.core.player.state.CompletedState
import com.intuit.playerui.core.player.state.ErrorState
import com.intuit.playerui.core.player.state.InProgressState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.get
import com.intuit.playerui.android.reference.assets.R
import com.intuit.playerui.android.reference.assets.test.AssetTest
import com.intuit.playerui.android.reference.assets.test.shouldBePlayerState
import com.intuit.playerui.android.reference.assets.test.shouldBeView
import com.intuit.playerui.android.testutils.asset.AssetTest
import com.intuit.playerui.android.testutils.asset.shouldBePlayerState
import com.intuit.playerui.android.testutils.asset.shouldBeView
import com.intuit.playerui.core.player.state.InProgressState
import org.junit.Assert.assertEquals
import org.junit.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.get
import com.intuit.playerui.android.reference.assets.R
import com.intuit.playerui.android.reference.assets.test.AssetTest
import com.intuit.playerui.android.reference.assets.test.shouldBePlayerState
import com.intuit.playerui.android.reference.assets.test.shouldBeView
import com.intuit.playerui.android.testutils.asset.AssetTest
import com.intuit.playerui.android.testutils.asset.shouldBePlayerState
import com.intuit.playerui.android.testutils.asset.shouldBeView
import com.intuit.playerui.core.player.state.InProgressState
import org.junit.Assert.assertEquals
import org.junit.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.get
import com.intuit.playerui.android.reference.assets.R
import com.intuit.playerui.android.reference.assets.test.AssetTest
import com.intuit.playerui.android.reference.assets.test.shouldBePlayerState
import com.intuit.playerui.android.reference.assets.test.shouldBeView
import com.intuit.playerui.android.testutils.asset.AssetTest
import com.intuit.playerui.android.testutils.asset.shouldBePlayerState
import com.intuit.playerui.android.testutils.asset.shouldBeView
import com.intuit.playerui.core.player.state.InProgressState
import com.intuit.playerui.core.player.state.dataModel
import org.junit.Assert.assertEquals
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.get
import com.intuit.playerui.android.reference.assets.R
import com.intuit.playerui.android.reference.assets.test.AssetTest
import com.intuit.playerui.android.reference.assets.test.shouldBeView
import com.intuit.playerui.android.testutils.asset.AssetTest
import com.intuit.playerui.android.testutils.asset.shouldBeView
import org.junit.Assert.assertEquals
import org.junit.Test

Expand Down