Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
.cxx
local.properties
/.idea/
.kotlin
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 0 additions & 10 deletions .idea/compiler.xml

This file was deleted.

35 changes: 0 additions & 35 deletions .idea/gradle.xml

This file was deleted.

9 changes: 0 additions & 9 deletions .idea/misc.xml

This file was deleted.

27 changes: 21 additions & 6 deletions buildSrc/src/main/kotlin/convention.android-base.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import com.android.build.gradle.BaseExtension
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.LibraryExtension
import io.github.kakaocup.withVersionCatalog

withVersionCatalog { libs ->
configure<BaseExtension> {
compileSdkVersion(libs.versions.compileSdk.get().toInt())
defaultConfig {
minSdk = libs.versions.minSdk.get().toInt()
multiDexEnabled = true
val compileSdkInt = libs.versions.compileSdk.get().toInt()
val minSdkInt = libs.versions.minSdk.get().toInt()

pluginManager.withPlugin("com.android.library") {
extensions.configure<LibraryExtension>("android") {
compileSdk = compileSdkInt
defaultConfig {
minSdk = minSdkInt
multiDexEnabled = true
}
}
}
pluginManager.withPlugin("com.android.application") {
extensions.configure<ApplicationExtension>("android") {
compileSdk = compileSdkInt
defaultConfig {
minSdk = minSdkInt
multiDexEnabled = true
}
}
}
}
3 changes: 1 addition & 2 deletions buildSrc/src/main/kotlin/convention.application.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import com.android.build.gradle.AppExtension
import io.github.kakaocup.withVersionCatalog

plugins {
Expand All @@ -8,7 +7,7 @@ plugins {
}

withVersionCatalog { libs ->
configure<AppExtension>() {
android {
defaultConfig {
targetSdk = libs.versions.targetSdk.get().toInt()
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down
7 changes: 2 additions & 5 deletions buildSrc/src/main/kotlin/convention.kotlin.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import io.github.kakaocup.withVersionCatalog

plugins {
kotlin("android")
}
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension

withVersionCatalog { libs ->
kotlin {
extensions.getByType(KotlinAndroidProjectExtension::class.java).apply {
jvmToolchain(libs.versions.jvmVersion.get().toInt())
}
}
4 changes: 0 additions & 4 deletions buildSrc/src/main/kotlin/convention.library.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,3 @@ plugins {
id("convention.android-base")
id("convention.kotlin")
}

kotlin {
jvmToolchain(8)
}
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/convention.publishing.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import com.android.build.gradle.LibraryExtension
import com.android.build.api.dsl.LibraryExtension
import io.github.kakaocup.Github
import java.net.URI

Expand Down
36 changes: 27 additions & 9 deletions compose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
plugins {
id("convention.library")
id("convention.publishing")
id("org.jetbrains.kotlin.multiplatform")
id("com.android.kotlin.multiplatform.library")
alias(libs.plugins.jetbrains.compose)
id("org.jetbrains.kotlin.plugin.compose")
}

android {
namespace = "io.github.kakaocup.compose"
}
kotlin {
jvmToolchain(libs.versions.jvmVersion.get().toInt())

android {
namespace = "io.github.kakaocup.compose"
compileSdk = libs.versions.compileSdk.get().toInt()
minSdk = libs.versions.minSdk.get().toInt()
}

dependencies {
implementation(libs.androidx.test.espresso.espressoCore)
implementation(libs.androidx.test.ext.junit)
iosX64()
iosArm64()
iosSimulatorArm64()

implementation(libs.androidx.compose.ui.uiTestJunit4)
sourceSets {
commonMain.dependencies {
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.foundation)
implementation(libs.jetbrains.compose.ui)
implementation(libs.jetbrains.compose.ui.test)
}
androidMain.dependencies {
implementation(libs.androidx.compose.ui.uiTestJunit4)
implementation(libs.androidx.test.ext.junit)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.github.kakaocup.compose.node.assertion

import androidx.annotation.StringRes
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.test.*
import io.github.kakaocup.compose.utilities.getResourceString

actual interface TextResourcesNodeAssertions : NodeAssertions {
fun assertContentDescriptionEquals(
@StringRes vararg values: Int
) {
assertContentDescriptionEquals(values = values.map(::getResourceString).toTypedArray())
}

fun assertContentDescriptionContains(
@StringRes value: Int,
substring: Boolean = false,
ignoreCase: Boolean = false
) {
assertContentDescriptionContains(getResourceString(value), substring, ignoreCase)
}

fun assertTextEquals(
@StringRes vararg values: Int,
includeEditableText: Boolean = true
) {
assertTextEquals(
values = values.map(::getResourceString).toTypedArray(),
includeEditableText = includeEditableText
)
}

fun assertTextContains(
@StringRes value: Int,
substring: Boolean = false,
ignoreCase: Boolean = false
) {
assertTextContains(getResourceString(value), substring, ignoreCase)
}

fun assertValueEquals(@StringRes value: Int) {
delegate.check(NodeAssertions.ComposeBaseAssertionType.ASSERT_VALUE_EQUALS) {
assertValueEquals(getResourceString(value))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.github.kakaocup.compose.node.core

import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import androidx.compose.ui.test.junit4.ComposeTestRule
import io.github.kakaocup.compose.node.builder.NodeMatcher

@PublishedApi
internal actual inline fun <reified N> createChildNode(
semanticsProvider: SemanticsNodeInteractionsProvider,
nodeMatcher: NodeMatcher,
parentNode: BaseNode<*>,
): N = N::class.java
.getConstructor(
SemanticsNodeInteractionsProvider::class.java,
NodeMatcher::class.java,
BaseNode::class.java,
)
.newInstance(semanticsProvider, nodeMatcher, parentNode)

/**
* Android-only `waitUntil` helper. Depends on JUnit4-flavoured [ComposeTestRule],
* which only exists on Android. iOS tests should use `ComposeUiTest.waitUntil` directly.
*/
fun BaseNode<*>.waitUntil(
composeTestRule: ComposeTestRule = semanticsProvider as ComposeTestRule,
timeoutMillis: Long = 1_000,
condition: SemanticsNodeInteraction.() -> Unit
) {
composeTestRule.waitUntil(timeoutMillis) {
try {
condition.invoke(this.delegate.interaction.semanticsNodeInteraction)
true
} catch (e: AssertionError) {
false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.kakaocup.compose.node.element

import androidx.compose.ui.test.SemanticsNodeInteractionsProvider

@PublishedApi
internal actual inline fun <reified T : ComposeScreen<T>> instantiateScreen(
semanticsProvider: SemanticsNodeInteractionsProvider,
): T = T::class.java
.getDeclaredConstructor(SemanticsNodeInteractionsProvider::class.java)
.newInstance(semanticsProvider)

@PublishedApi
internal actual inline fun <reified T : ComposeScreen<T>> instantiateScreen(): T =
T::class.java.getDeclaredConstructor().newInstance()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.kakaocup.compose.utilities

import androidx.annotation.StringRes
import androidx.test.platform.app.InstrumentationRegistry

actual fun getResourceString(@StringRes resId: Int): String =
InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(resId)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.github.kakaocup.compose

import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import io.github.kakaocup.compose.intercept.base.Interceptor
import io.github.kakaocup.compose.rule.KakaoComposeTestRule
import io.github.kakaocup.compose.intercept.interaction.ComposeInteraction
import io.github.kakaocup.compose.intercept.operation.ComposeAction
import io.github.kakaocup.compose.intercept.operation.ComposeAssertion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.github.kakaocup.compose.intercept.base

import androidx.test.espresso.ViewInteraction
import io.github.kakaocup.compose.intercept.base.Interceptor.Builder
import io.github.kakaocup.compose.intercept.interaction.ComposeInteraction
import io.github.kakaocup.compose.intercept.operation.ComposeAction
Expand Down Expand Up @@ -103,9 +102,9 @@ class Interceptor<INTERACTION, ASSERTION, ACTION>(
private var composeInterceptor: Interceptor<ComposeInteraction, ComposeAssertion, ComposeAction>? = null

/**
* Setups the interceptor for `check` and `perform` operations happening through [ViewInteraction]
* Setups the interceptor for `check` and `perform` operations happening through [ComposeInteraction]
*
* @param builder Builder of interceptor for [ViewInteraction]
* @param builder Builder of interceptor for [ComposeInteraction]
*/
fun onComposeInteraction(builder: Builder<ComposeInteraction, ComposeAssertion, ComposeAction>.() -> Unit) {
composeInterceptor = Builder<ComposeInteraction, ComposeAssertion, ComposeAction>().apply(builder).build()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.kakaocup.compose.node.assertion

/**
* Marker interface for resource-id based assertions. The actual methods are declared
* on the Android-specific `actual interface` (since iOS lacks `@StringRes` resource ids).
*
* On iOS this is an empty marker — instantiate screens directly and call the
* string-based [NodeAssertions] methods instead.
*/
expect interface TextResourcesNodeAssertions : NodeAssertions
Loading