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

Feature/66 unmerged tree cfg #75

Merged
merged 2 commits into from
Jul 4, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/android-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ jobs:
java-version: '17'

- name: Compile framework
run: ./gradlew compileDebugKotlin
run: ./gradlew compileDebugKotlin compileDebugKotlinAndroid compileKotlinDesktop compileKotlinJvm compileKotlinIosArm64 compileKotlinIosSimulatorArm64 compileKotlinJs compileKotlinWasmJs
61 changes: 61 additions & 0 deletions composeApp/src/commonTest/kotlin/BaseInteractionTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import com.atiurin.ultron.core.common.options.TextContainsOption
import com.atiurin.ultron.core.compose.config.UltronComposeConfig
import com.atiurin.ultron.core.compose.nodeinteraction.click
import com.atiurin.ultron.core.compose.runUltronUiTest
import com.atiurin.ultron.extensions.assertIsDisplayed
import com.atiurin.ultron.extensions.assertTextContains
import com.atiurin.ultron.extensions.isSuccess
import com.atiurin.ultron.extensions.withAssertion
import com.atiurin.ultron.extensions.withUseUnmergedTree
import kotlin.test.AfterTest
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue

@OptIn(ExperimentalTestApi::class)
class BaseInteractionTest {
@Test
fun test() = runUltronUiTest {
setContent {
App()
}
hasText("Click me!").withAssertion() {
hasTestTag("greeting")
.assertIsDisplayed()
.assertTextContains("Compose: Hello,", option = TextContainsOption(substring = true))
}.click()
}

@Test
fun useUnmergedTreeConfigTest() = runUltronUiTest {
val testTag = "element"
setContent {
Column {
Button(onClick = {}, modifier = Modifier.testTag(testTag)) {
Text("Text1")
Text("Text2")
}
}
}
UltronComposeConfig.params.useUnmergedTree = true
assertFalse("Ultron operation success should be false") {
hasTestTag(testTag).isSuccess { assertTextContains("Text1") }
}
assertTrue ("Ultron operation success should be true") {
hasTestTag(testTag).withUseUnmergedTree(false).isSuccess { assertTextContains("Text1") }
}
}

@AfterTest
fun disableUseUnmergedTree(){
UltronComposeConfig.params.useUnmergedTree = false
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import com.atiurin.ultron.core.common.options.TextContainsOption
import com.atiurin.ultron.core.compose.list.UltronComposeListItem
import com.atiurin.ultron.core.compose.list.composeList
import com.atiurin.ultron.core.compose.nodeinteraction.click
import com.atiurin.ultron.core.compose.runUltronUiTest
import com.atiurin.ultron.extensions.assertIsDisplayed
import com.atiurin.ultron.extensions.withAssertion
import com.atiurin.ultron.page.Screen
import repositories.ContactRepository
import kotlin.test.Test

@OptIn(ExperimentalTestApi::class)
class AppTest {
@Test
fun test() = runUltronUiTest {
setContent {
App()
}
hasText("Click me!").withAssertion() {
hasTestTag("greeting")
.assertIsDisplayed()
.assertTextContains("Compose: Hello,", option = TextContainsOption(substring = true))
}.click()
}
class ListTest {

@Test
fun testList() = runUltronUiTest {
Expand Down
3 changes: 3 additions & 0 deletions composeApp/src/jsMain/kotlin/Platform.js.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
actual fun getPlatform(): Platform {
TODO("Not yet implemented")
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ kotlin.mpp.enableCInteropCommonization=true

GROUP=com.atiurin
POM_ARTIFACT_ID=ultron
VERSION_NAME=2.5.0-alpha06
VERSION_NAME=2.5.0-alpha07
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class ComposeListTest : BaseTest() {
val contact = CONTACTS[index]
listWithMergedTree.visibleItem(index).printToLog("ULTRON")
.assertMatches(hasAnyDescendant(hasText(contact.name)))

}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ class UltronComposeList(
val listMatcher: SemanticsMatcher,
var useUnmergedTree: Boolean = true,
var positionPropertyKey: SemanticsPropertyKey<Int>? = null,
val itemsRegistrator: UltronComposeList.() -> Unit = {},
val initBlock: UltronComposeList.() -> Unit = {},
private val itemSearchLimit: Int = UltronComposeConfig.params.lazyColumnItemSearchLimit,
private var operationTimeoutMs: Long = UltronComposeConfig.params.lazyColumnOperationTimeoutMs
) {
private val itemChildInteractionProvider = getItemChildInteractionProvider()
val instancesMap = mutableMapOf<KClass<*>, () -> UltronComposeListItem>()
val itemInstancesMap = mutableMapOf<KClass<*>, () -> UltronComposeListItem>()
inline fun <reified T : UltronComposeListItem> registerItem(noinline creator: () -> T){
instancesMap[T::class] = creator
itemInstancesMap[T::class] = creator
}
init {
itemsRegistrator()
initBlock()
}

open fun withTimeout(timeoutMs: Long) =
Expand Down Expand Up @@ -224,15 +224,15 @@ class UltronComposeList(
fun scrollToNode(itemMatcher: SemanticsMatcher) = apply { getInteraction().scrollToNode(itemMatcher) }
fun scrollToIndex(index: Int) = apply { getInteraction().scrollToIndex(index) }
fun scrollToKey(key: Any) = apply { getInteraction().scrollToKey(key) }
fun assertIsDisplayed() = apply { getInteraction().withTimeout(getOperationTimeout()).assertIsDisplayed() }
fun assertIsNotDisplayed() = apply { getInteraction().withTimeout(getOperationTimeout()).assertIsNotDisplayed() }
fun assertExists() = apply { getInteraction().withTimeout(getOperationTimeout()).assertExists() }
fun assertDoesNotExist() = apply { getInteraction().withTimeout(getOperationTimeout()).assertDoesNotExist() }
fun assertContentDescriptionEquals(vararg expected: String) = apply { getInteraction().withTimeout(getOperationTimeout()).assertContentDescriptionEquals(*expected) }
fun assertIsDisplayed() = apply { getInteraction().assertIsDisplayed() }
fun assertIsNotDisplayed() = apply { getInteraction().assertIsNotDisplayed() }
fun assertExists() = apply { getInteraction().assertExists() }
fun assertDoesNotExist() = apply { getInteraction().assertDoesNotExist() }
fun assertContentDescriptionEquals(vararg expected: String) = apply { getInteraction().assertContentDescriptionEquals(*expected) }
fun assertContentDescriptionContains(expected: String, option: ContentDescriptionContainsOption? = null) =
apply { getInteraction().withTimeout(getOperationTimeout()).assertContentDescriptionContains(expected, option) }
apply { getInteraction().assertContentDescriptionContains(expected, option) }

fun assertMatches(matcher: SemanticsMatcher) = apply { getInteraction().withTimeout(getOperationTimeout()).assertMatches(matcher) }
fun assertMatches(matcher: SemanticsMatcher) = apply { getInteraction().assertMatches(matcher) }
fun assertNotEmpty() = apply {
AssertUtils.assertTrue(
{ getVisibleItemsCount() > 0 }, getOperationTimeout(),
Expand Down Expand Up @@ -261,7 +261,7 @@ class UltronComposeList(
* Otherwise, an exception will be thrown.
*/
fun assertItemDoesNotExist(itemMatcher: SemanticsMatcher) {
getInteraction().withTimeout(getOperationTimeout()).perform(
getInteraction().perform(
params = UltronComposeOperationParams(
operationName = "Assert item ${itemMatcher.description} doesn't exist in list ${getInteraction().elementInfo.name}",
operationDescription = "Assert item ${itemMatcher.description} doesn't exist in list ${getInteraction().elementInfo.name} during ${getOperationTimeout()}",
Expand All @@ -281,7 +281,7 @@ class UltronComposeList(
}

fun getVisibleItemsCount(): Int = getInteraction().execute { it.fetchSemanticsNode().children.size }
fun getInteraction() = UltronComposeSemanticsNodeInteraction(listMatcher, useUnmergedTree)
fun getInteraction() = UltronComposeSemanticsNodeInteraction(listMatcher, useUnmergedTree, operationTimeoutMs)

@Deprecated("Use getInteraction() instead", ReplaceWith("getInteraction()"))
fun getMatcher() = getInteraction()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ open class UltronComposeSemanticsNodeInteraction constructor(
) {
constructor(
matcher: SemanticsMatcher,
useUnmergedTree: Boolean = false,
useUnmergedTree: Boolean = UltronComposeConfig.params.useUnmergedTree,
timeoutMs: Long = UltronComposeConfig.params.operationTimeoutMs,
resultHandler: ((ComposeOperationResult<UltronComposeOperation>) -> Unit) = UltronComposeConfig.resultHandler,
assertion: OperationAssertion = EmptyOperationAssertion(),
elementInfo: ElementInfo = DefaultElementInfo()
) : this(SemanticsNodeInteractionProviderContainer.getProvider().onNode(matcher, useUnmergedTree), timeoutMs, resultHandler, assertion, elementInfo)

init {
if (elementInfo.name.isEmpty()) elementInfo.name = semanticsNodeInteraction.getSelectorDescription().toString()
if (elementInfo.name.isEmpty()) elementInfo.name = semanticsNodeInteraction.getSelectorDescription()
}

fun <T> isSuccess(action: UltronComposeSemanticsNodeInteraction.() -> T): Boolean = runCatching { action() }.isSuccess
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ actual inline fun <reified T : UltronComposeListItem> getComposeListItemInstance
ultronComposeList: UltronComposeList,
itemMatcher: SemanticsMatcher
): T {
val item = ultronComposeList.instancesMap[T::class]?.invoke()
val item = ultronComposeList.itemInstancesMap[T::class]?.invoke()
?: throw UltronException(
"""
|Item with ${T::class} not registered in compose list ${ultronComposeList.listMatcher.description}
Expand All @@ -28,7 +28,7 @@ actual inline fun <reified T : UltronComposeListItem> getComposeListItemInstance
position: Int,
isPositionPropertyConfigured: Boolean
): T {
val item = ultronComposeList.instancesMap[T::class]?.invoke()
val item = ultronComposeList.itemInstancesMap[T::class]?.invoke()
?: throw UltronException(
"""
|Item with ${T::class} not registered in compose list ${ultronComposeList.listMatcher.description}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ actual inline fun <reified T : UltronComposeListItem> getComposeListItemInstance
ultronComposeList: UltronComposeList,
itemMatcher: SemanticsMatcher
): T {
val item = ultronComposeList.instancesMap[T::class]?.invoke()
val item = ultronComposeList.itemInstancesMap[T::class]?.invoke()
?: throw UltronException(
"""
|Item with ${T::class} not registered in compose list ${ultronComposeList.listMatcher.description}
Expand All @@ -28,7 +28,7 @@ actual inline fun <reified T : UltronComposeListItem> getComposeListItemInstance
position: Int,
isPositionPropertyConfigured: Boolean
): T {
val item = ultronComposeList.instancesMap[T::class]?.invoke()
val item = ultronComposeList.itemInstancesMap[T::class]?.invoke()
?: throw UltronException(
"""
|Item with ${T::class} not registered in compose list ${ultronComposeList.listMatcher.description}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ actual inline fun <reified T : UltronComposeListItem> getComposeListItemInstance
ultronComposeList: UltronComposeList,
itemMatcher: SemanticsMatcher
): T {
val item = ultronComposeList.instancesMap[T::class]?.invoke()
val item = ultronComposeList.itemInstancesMap[T::class]?.invoke()
?: throw UltronException(
"""
|Item with ${T::class} not registered in compose list ${ultronComposeList.listMatcher.description}
Expand All @@ -28,7 +28,7 @@ actual inline fun <reified T : UltronComposeListItem> getComposeListItemInstance
position: Int,
isPositionPropertyConfigured: Boolean
): T {
val item = ultronComposeList.instancesMap[T::class]?.invoke()
val item = ultronComposeList.itemInstancesMap[T::class]?.invoke()
?: throw UltronException(
"""
|Item with ${T::class} not registered in compose list ${ultronComposeList.listMatcher.description}
Expand Down