-
Notifications
You must be signed in to change notification settings - Fork 0
Compose Multiplatform UI 測試環境設定與疑難排解
Yu-Chan (Henry) Huang edited this page May 23, 2026
·
3 revisions
在重構 OmniHub 專案並導入 runComposeUiTest 時,我們在 WasmJS 與 Android Host Test 平台上遇到了一些環境配置導致的測試失敗。本文件記錄了這些問題的原因與修復方法。
WasmJS 平台在執行測試時,會透過 Webpack 進行打包。由於 Compose 的圖形引擎 (Skiko) 使用了動態依賴載入,導致 Webpack 無法進行靜態分析並噴出警告。此外,Kotlin 2.0+ 對於 WasmJS 的互操作性 (Interop) 有更嚴格的實驗性 API 限制。
Critical dependency: the request of a dependency is an expressionThis declaration needs opt-in. Its usage should be marked with '@kotlin.js.ExperimentalWasmJsInterop'
- 忽略 Webpack 警告: 在 shared/src/wasmJsMain/resources/webpack.config.d/config.js 加入腳本,強制 Webpack 忽略 Skiko 引起的動態依賴警告。
- 開啟編譯器許可: 在 shared/build.gradle.kts 的
wasmJs區塊中加入編譯參數:
wasmJs {
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.js.ExperimentalWasmJsInterop")
}
}當 UI 測試寫在 commonTest 並在 Android Target 上執行時,如果是在電腦的 JVM 上跑(而非實體機),這被稱為 Host Test。純 JVM 並不具備 Android 的系統屬性與 Activity 執行環境。
- NPE:
Cannot invoke "String.toLowerCase()" because "android.os.Build.FINGERPRINT" is null- 原因:runComposeUiTest 試圖讀取 Android 系統資訊,但純 JVM 環境沒有這些資料。
- RuntimeException:
Unable to resolve activity for Intent { ... ComponentActivity }- 原因:測試環境找不到可以承載 UI 的 Activity 宣告。
步驟 A:引入 Robolectric 與 Base Class 模式
- 由於 JUnit 4 不支援透過自定義註解傳遞
@RunWith,我們採用expect/actual建立BaseComposeTest抽象類別: Android 端 (actual): 標註@RunWith(RobolectricTestRunner::class),強制在模擬的 Android 環境下執行。 - 其餘平台 (
actual): 保持為空的實作。
步驟 B:補齊 Activity 宣告
-
依賴:加入
androidx.compose.ui:ui-test-manifest。 -
Manifest:在 shared/src/androidDebug/AndroidManifest.xml 中手動宣告
androidx.activity.ComponentActivity。 -
配置:在測試基底類別中指定
packageName:
@Config(sdk = [35], packageName = "io.lackstudio.omnihub.shared")
actual abstract class BaseComposeTest如果你在新增 UI 測試時遇到類似錯誤,請檢查以下設定:
| 平台 | 必要設定 |
|---|---|
| Android | 繼承 BaseComposeTes (Robolectric), 確保 androidDebug 有 Manifest |
| WasmJS | webpack.config.d 腳本, ExperimentalWasmJsInterop opt-in |
| iOS / JVM | 直接繼承 BaseComposeTest 即可運作 |