Skip to content

Commit

Permalink
Add setContent variant which returns initial snapshot (#665)
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWharton authored Jan 26, 2025
1 parent 7a52066 commit 9f63a35
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[Unreleased]: https://github.com/JakeWharton/mosaic/compare/0.15.0...HEAD

New:
- Nothing yet!
- Add `setContentAndSnapshot` to 'mosaic-testing' which returns the initial composition snapshot. This avoids a potential problem with calling `setContent` and then `awaitSnapshot` since the latter will trigger a subsequent recomposition (if needed), preventing observation of the initial state.

Changed:
- Nothing yet!
Expand Down
1 change: 1 addition & 0 deletions mosaic-testing/api/mosaic-testing.api
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public abstract interface class com/jakewharton/mosaic/testing/SnapshotStrategy
public abstract interface class com/jakewharton/mosaic/testing/TestMosaic : com/jakewharton/mosaic/Mosaic {
public abstract fun awaitSnapshot-VtjQ1oo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun awaitSnapshot-VtjQ1oo$default (Lcom/jakewharton/mosaic/testing/TestMosaic;JLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public abstract fun setContentAndSnapshot (Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
}

public final class com/jakewharton/mosaic/testing/TestMosaicKt {
Expand Down
1 change: 1 addition & 0 deletions mosaic-testing/api/mosaic-testing.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ abstract fun interface <#A: kotlin/Any?> com.jakewharton.mosaic.testing/Snapshot
}

abstract interface <#A: kotlin/Any?> com.jakewharton.mosaic.testing/TestMosaic : com.jakewharton.mosaic/Mosaic { // com.jakewharton.mosaic.testing/TestMosaic|null[0]
abstract fun setContentAndSnapshot(kotlin/Function2<androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>): #A // com.jakewharton.mosaic.testing/TestMosaic.setContentAndSnapshot|setContentAndSnapshot(kotlin.Function2<androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>){}[0]
abstract suspend fun awaitSnapshot(kotlin.time/Duration = ...): #A // com.jakewharton.mosaic.testing/TestMosaic.awaitSnapshot|awaitSnapshot(kotlin.time.Duration){}[0]
}

Expand Down
7 changes: 7 additions & 0 deletions mosaic-testing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ kotlin {
implementation libs.compose.collection
}
}
commonTest {
dependencies {
implementation libs.kotlin.test
implementation libs.kotlinx.coroutines.test
implementation libs.assertk
}
}
}

compilerOptions.freeCompilerArgs.add('-Xexpect-actual-classes')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public suspend fun <T, R> runMosaicTest(
}

public interface TestMosaic<T> : Mosaic {
public fun setContentAndSnapshot(content: @Composable () -> Unit): T
public suspend fun awaitSnapshot(duration: Duration = 1.seconds): T
}

Expand All @@ -64,6 +65,13 @@ private class RealTestMosaic<T>(
mosaic.setContent(content)
}

override fun setContentAndSnapshot(content: @Composable (() -> Unit)): T {
setContent(content)
check(hasChanges)
hasChanges = false
return snapshotStrategy.create(mosaic)
}

override suspend fun awaitSnapshot(duration: Duration): T {
check(contentSet) { "setContent must be called first!" }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.jakewharton.mosaic.testing

import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.setValue
import assertk.assertThat
import assertk.assertions.isEqualTo
import com.jakewharton.mosaic.ui.Text
import kotlin.test.Test
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest

class TestMosaicTest {
@Test fun setContentAndSnapshot() = runTest {
runMosaicTest {
var number by mutableIntStateOf(0)
val initial = setContentAndSnapshot {
Text("The number is: $number")
LaunchedEffect(Unit) {
number = 1
}
}

// Defer to allow effect to run.
delay(10.milliseconds)

assertThat(initial).isEqualTo("The number is: 0")
assertThat(awaitSnapshot()).isEqualTo("The number is: 1")
}
}

@Test fun setContentThenSnapshot() = runTest {
runMosaicTest {
var number by mutableIntStateOf(0)
setContent {
Text("The number is: $number")
LaunchedEffect(Unit) {
number = 1
}
}

// Defer to allow effect to run.
delay(10.milliseconds)

assertThat(awaitSnapshot()).isEqualTo("The number is: 1")
}
}
}

0 comments on commit 9f63a35

Please sign in to comment.