adrielcafe / voyager

🛸 A pragmatic navigation library for Jetpack Compose
https://voyager.adriel.cafe
MIT License
2.27k stars 109 forks source link

UI Testing #349

Closed ismai117 closed 2 months ago

ismai117 commented 2 months ago

Hi, I'm currently testing the UI in my app, the test fails due to LocalNavigator.currentOrThrow


java.lang.IllegalStateException: CompositionLocal is null
    at cafe.adriel.voyager.navigator.NavigatorKt.getCurrentOrThrow(Navigator.kt:40)
    at starter.presentation.StarterScreen.Content(StarterScreen.kt:81)
    at starter.presentation.ComposableSingletons$StarterScreenTestKt$lambda-1$1.invoke(StarterScreenTest.kt:18)
    at starter.presentation.ComposableSingletons$StarterScreenTestKt$lambda-1$1.invoke(StarterScreenTest.kt:17)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
    at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:248)
    at androidx.compose.ui.scene.BaseComposeScene$setContent$1$2.invoke(BaseComposeScene.skiko.kt:139)
    at androidx.compose.ui.scene.BaseComposeScene$setContent$1$2.invoke(BaseComposeScene.skiko.kt:138)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
    at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
    at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:186)
    at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2$1.invoke(Wrapper.skiko.kt:49)
    at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2$1.invoke(Wrapper.skiko.kt:48)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
    at androidx.compose.ui.platform.Wrapper_skikoKt.provide(Wrapper.skiko.kt:64)
    at androidx.compose.ui.platform.Wrapper_skikoKt.access$provide(Wrapper.skiko.kt:1)
    at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2.invoke(Wrapper.skiko.kt:48)
    at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2.invoke(Wrapper.skiko.kt:47)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
    at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:33)
    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3303)
    at androidx.compose.runtime.ComposerImpl.composeContent$runtime(Composer.kt:3236)
    at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:725)
    at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1071)
    at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:633)
    at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:619)
    at androidx.compose.ui.platform.Wrapper_skikoKt.setContent(Wrapper.skiko.kt:47)
    at androidx.compose.ui.scene.MultiLayerComposeSceneImpl.createComposition(MultiLayerComposeScene.skiko.kt:203)
    at androidx.compose.ui.scene.BaseComposeScene.setContent(BaseComposeScene.skiko.kt:138)
    at androidx.compose.ui.test.SkikoComposeUiTest$setContent$1.invoke(ComposeUiTest.skikoMain.kt:283)
    at androidx.compose.ui.test.SkikoComposeUiTest$setContent$1.invoke(ComposeUiTest.skikoMain.kt:282)
    at androidx.compose.ui.test.DesktopSynchronization_desktopKt.runOnUiThread$lambda$0(DesktopSynchronization.desktop.kt:32)
    at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
    at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Syer10 commented 2 months ago

You shouldn't be testing the Screen itself, you should be extracting the Screen UI to its own outside composable that you can then call in the Screen.Content() and your test. Any CompositionLocals should be called in the Screen.Content() and lambas for different actions should be passed as parameters to the UI.