Skip to content

Launch SimpleTest from sample in iOS#129

Open
phansier wants to merge 7 commits into
KakaoCup:masterfrom
phansier:ios
Open

Launch SimpleTest from sample in iOS#129
phansier wants to merge 7 commits into
KakaoCup:masterfrom
phansier:ios

Conversation

@phansier
Copy link
Copy Markdown

This is proof of concept for adopting Kakao Compose for Compose Multiplatform projects. Mostly - iOS target.

The idea is to have single codebase & save compatibility with projects using only Jetpack Compose.

For that:

  • sample kept using Jetpack Compose
  • new sample-kmp using Compose Multiplatform (aka Jetbrains Compose)
  • compose adopted KMP structure & Compose Multiplatform dependencies. That should be safe as afaik in Android Compose Multiplatform still uses Jetpack Compose.

Also I updated Gradle, AGP, Kotlin versions to more actual (just for reducing local size of Gradle, Konan dependencies) - can be rollbacked if needed. Ignored .idea/ & .kotlin/ local files.

phansier added 7 commits May 13, 2026 17:12
Migrate `:compose` from `com.android.library` to
`com.android.kotlin.multiplatform.library` so the test DSL compiles for
iOS in addition to Android. Sources reorganise into commonMain /
androidMain / iosMain source sets; reflection- and JUnit4-specific code
moves to androidMain, with iosMain providing stub actuals that throw if
called.

Key changes:
- compose/build.gradle.kts rewritten as a KMP library with iosX64,
  iosArm64, iosSimulatorArm64 targets. Uses compose.uiTest from
  Compose Multiplatform 1.10.0.
- Most sources move 1:1 to commonMain.
- KakaoComposeTestRule, ContextUtils, list/, lazylist/, ListNodeAssertions
  and LazyListNodeAssertions move to androidMain (JUnit4 / reflection /
  InstrumentationRegistry deps).
- Reflective `BaseNode.child<N>` and `ComposeScreen.onComposeScreen<T>`
  preserved as commonMain inline members backed by `internal expect`
  helpers. androidMain actuals use Java reflection; iosMain actuals
  throw UnsupportedOperationException with guidance to construct nodes
  directly.
- `TextResourcesNodeAssertions` becomes an `expect interface`; Android
  actual keeps the @stringres methods, iOS actual is an empty marker.
- `waitUntil` becomes an androidMain extension on BaseNode (depends on
  JUnit4 ComposeTestRule). WaitForTest gains one import line.
- ViewBuilder @stringres overloads move into common code and route
  through an `expect fun getResourceString(Int): String`. iOS actual
  throws if called.
- `Interceptor` drops the orphaned `androidx.test.espresso.ViewInteraction`
  import and the KDoc reference.

settings.gradle.kts adds the JetBrains Compose dev maven repo; the
version catalog adds kotlin.multiplatform / jetbrains.compose plugin
aliases plus `composeMultiplatform = "1.10.0"`.
Creates a new module separate from the existing Android-only :sample.
The KMP module exposes a shared MainScreen composable consumable from
both Android and iOS, plus a MainViewController factory for iOS hosts.

- settings.gradle.kts registers :sample-kmp
- sample-kmp/build.gradle.kts: com.android.kotlin.multiplatform.library
  + iosX64/iosArm64/iosSimulatorArm64 static frameworks (baseName
  "SampleKit"); commonTest pulls in compose.uiTest and :compose
- commonMain MainScreen.kt: the same UI tree as :sample's MainActivity
  (two texts, two buttons with testTags), but with the R.string lookup
  replaced by a string literal so it lives in commonMain
- iosMain MainViewController(): ComposeUIViewController { MainScreen() }
  for consumption from an iosApp Xcode project (optional, not in repo)
- empty androidMain AndroidManifest.xml — required by AGP for the
  android target

Existing :sample (Android+JetpackCompose) is left untouched.
Adds the multiplatform SimpleTest that mirrors the Android original
(sample/src/androidTest/.../test/SimpleTest.kt) but uses
`runComposeUiTest { setContent { MainScreen() } }` instead of an
Android-specific compose rule, and instantiates MainActivityScreen
directly (since iOS has no reflection-based screen factory).

- commonTest/screen/MainActivityScreen.kt: the existing page object
  shape, but without the dropped @stringres hasText overload (iOS has
  no resource ids — string literal "Button 1" is asserted instead).
- commonTest/test/SimpleTest.kt: identical assertions to the Android
  SimpleTest, wrapped in runComposeUiTest.
- compose/src/iosMain/.../BaseNodeIos.kt: replace the throwing stub of
  `createChildNode` with one that instantiates KNode and relies on the
  reified cast at the call site. This makes `val x: KNode = child { … }`
  work on iOS for the common case (custom BaseNode subclasses on iOS
  still hit ClassCastException, with an explanatory KDoc).

Verified: `./gradlew :sample-kmp:iosSimulatorArm64Test` passes.
Three deprecations surfaced in the IDE for the KMP build scripts:
- 'val runtime: String' is deprecated (and the other compose.* accessors)
- '@ExperimentalComposeLibrary' is deprecated (only needed to opt into
  compose.uiTest)
- 'androidLibrary' block is deprecated; use 'android' instead

Resolutions:
- Add jetbrains-compose-{runtime,foundation,material,ui,ui-test} library
  entries to the version catalog and depend on them via `libs.*` from
  both build scripts. Drops the compose plugin's deprecated DSL
  accessors and the @OptIn(ExperimentalComposeLibrary::class) annotation.
- Rename `androidLibrary { … }` → `android { … }` inside the `kotlin {}`
  block in both modules.

Verified: ./gradlew :compose:assemble :sample-kmp:assemble
          :sample-kmp:iosSimulatorArm64Test passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant