Skip to content

Commit 6155ffc

Browse files
authored
[Test] Add TestFormulaObserver.input() (#209)
* [Test] Add TestFormulaObserver.input() * Ensure formula is running. * Assert no errors before interaction as well.
1 parent 06092dc commit 6155ffc

23 files changed

+122
-104
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
- Move `FragmentContract` into `android` package.
3636
- Move `FragmentFlowState` into `android` package.
3737
- Move `FragmentFlowStore` into `android` package.
38+
- **Breaking**: Replaced `formula.test(inputObservable)` with `formula.test().input()`
39+
- Add `TestFormulaObserver.assertNoErrors()`
3840

3941
## [0.6.1] - November 18, 2020
4042
- Bugfix: Fix runtime ignoring `Formula.key` for the root formula.

formula-test/src/main/java/com/instacart/formula/test/TestFormulaObserver.kt

+28-3
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,59 @@ package com.instacart.formula.test
22

33
import com.instacart.formula.IFormula
44
import com.instacart.formula.rxjava3.toObservable
5-
import io.reactivex.rxjava3.core.Observable
5+
import io.reactivex.rxjava3.subjects.BehaviorSubject
66

77
class TestFormulaObserver<Input : Any, Output : Any, FormulaT : IFormula<Input, Output>>(
8-
private val input: Observable<Input>,
98
val formula: FormulaT
109
) {
1110

11+
private var started: Boolean = false
12+
private val inputRelay = BehaviorSubject.create<Input>()
1213
private val observer = formula
13-
.toObservable(input)
14+
.toObservable(inputRelay)
1415
.test()
1516
.assertNoErrors()
1617

1718
fun values(): List<Output> {
1819
return observer.values()
1920
}
2021

22+
/**
23+
* Passes input to [formula].
24+
*/
25+
fun input(value: Input) = apply {
26+
started = true
27+
assertNoErrors() // Check before interaction
28+
inputRelay.onNext(value)
29+
assertNoErrors() // Check after interaction
30+
}
31+
2132
inline fun output(assert: Output.() -> Unit) = apply {
33+
ensureFormulaIsRunning()
34+
assertNoErrors() // Check before interaction
2235
assert(values().last())
36+
assertNoErrors() // Check after interaction
2337
}
2438

2539
fun assertOutputCount(count: Int) = apply {
40+
ensureFormulaIsRunning()
41+
assertNoErrors()
2642
val size = values().size
2743
assert(size == count) {
2844
"Expected: $count, was: $size"
2945
}
3046
}
3147

48+
fun assertNoErrors() = apply {
49+
observer.assertNoErrors()
50+
}
51+
3252
fun dispose() = apply {
3353
observer.dispose()
3454
}
55+
56+
@PublishedApi
57+
internal fun ensureFormulaIsRunning() {
58+
if (!started) throw IllegalStateException("Formula is not running. Call [TeatFormulaObserver.input] to start it.")
59+
}
3560
}

formula-test/src/main/java/com/instacart/formula/test/TestRuntimeExtensions.kt

+8-18
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,27 @@ package com.instacart.formula.test
22

33
import com.instacart.formula.IFormula
44
import com.instacart.formula.Stream
5-
import io.reactivex.rxjava3.core.Observable
65

76
/**
87
* An extension function to create a [TestFormulaObserver] for a [IFormula] instance.
98
*
10-
* @param input Input passed to [IFormula].
9+
* Note: Formula won't start until you pass it an [input][TestFormulaObserver.input].
1110
*/
12-
fun <Input : Any, Output : Any, F: IFormula<Input, Output>> F.test(
13-
input: Input
14-
): TestFormulaObserver<Input, Output, F> {
15-
return test(Observable.just(input))
11+
fun <Input : Any, Output : Any, F: IFormula<Input, Output>> F.test(): TestFormulaObserver<Input, Output, F> {
12+
return TestFormulaObserver(this)
1613
}
1714

18-
1915
/**
2016
* An extension function to create a [TestFormulaObserver] for a [IFormula] instance.
2117
*
22-
* @param input A stream of inputs passed to [IFormula].
18+
* @param initialInput Input passed to [IFormula].
2319
*/
2420
fun <Input : Any, Output : Any, F: IFormula<Input, Output>> F.test(
25-
input: Observable<Input>
21+
initialInput: Input
2622
): TestFormulaObserver<Input, Output, F> {
27-
return TestFormulaObserver(
28-
input = input,
29-
formula = this
30-
)
23+
return test().apply {
24+
input(initialInput)
25+
}
3126
}
3227

33-
/**
34-
* An extension function to create a [TestFormulaObserver] for a [IFormula] instance.
35-
*/
36-
fun <Output : Any, F: IFormula<Unit, Output>> F.test() = test(Unit)
37-
3828
fun <Message> Stream<Message>.test() = TestStreamObserver(this)

formula-test/src/test/java/com/instacart/formula/test/TestFormulaTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class TestFormulaTest {
1616
@Before fun setup() {
1717
childFormula = FakeChildFormula()
1818
parentFormula = ParentFormula(childFormula)
19-
subject = ParentFormula(childFormula = childFormula).test()
19+
subject = ParentFormula(childFormula = childFormula).test(Unit)
2020
}
2121

2222
@Test fun `trigger callback using child input`() {

formula/src/test/java/com/instacart/formula/ChildRemovedOnMessage.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class ChildRemovedOnMessage {
1313
}
1414
)
1515
})
16-
.test()
16+
.test(Unit)
1717

1818
fun assertChildIsVisible(visible: Boolean) = apply {
1919
subject.output {

formula/src/test/java/com/instacart/formula/ChildStreamEvents.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import com.instacart.formula.test.test
66
class ChildStreamEvents {
77

88
private val child = StartStopFormula()
9-
private val subject = HasChildFormula(child).test()
9+
private val subject = HasChildFormula(child).test(Unit)
1010

1111
fun startListening() = apply {
1212
subject.output { child.startListening() }

formula/src/test/java/com/instacart/formula/DuplicateChildrenTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import kotlin.IllegalStateException
99
class DuplicateChildrenTest {
1010

1111
@Test fun `adding duplicate child throws an exception`() {
12-
val error = Try { ParentFormula().test() }.errorOrNull()?.cause
12+
val error = Try { ParentFormula().test(Unit) }.errorOrNull()?.cause
1313
assertThat(error).isInstanceOf(IllegalStateException::class.java)
1414
}
1515

formula/src/test/java/com/instacart/formula/DynamicFormulaInputTest.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ package com.instacart.formula
22

33
import com.google.common.truth.Truth.assertThat
44
import com.instacart.formula.test.test
5-
import io.reactivex.rxjava3.core.Observable
65
import org.junit.Test
76

87
class DynamicFormulaInputTest {
98

109
@Test
1110
fun `using dynamic input`() {
1211
TestFormula()
13-
.test(Observable.just(1, 2, 3))
12+
.test()
13+
.input(1)
14+
.input(2)
15+
.input(3)
1416
.apply {
1517
assertThat(values()).containsExactly(1, 2, 3).inOrder()
1618
}

formula/src/test/java/com/instacart/formula/DynamicStreamSubject.kt

+2-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ package com.instacart.formula
22

33
import com.google.common.truth.Truth.assertThat
44
import com.instacart.formula.test.test
5-
import com.jakewharton.rxrelay3.PublishRelay
65

76
class DynamicStreamSubject {
8-
private val streams = PublishRelay.create<List<String>>()
9-
private val subject = TestFormula().test(streams)
7+
private val subject = TestFormula().test()
108

119
fun updateStreams(vararg keys: String) = apply {
12-
streams.accept(keys.asList())
10+
subject.input(keys.asList())
1311
assertRunning(*keys)
1412
}
1513

formula/src/test/java/com/instacart/formula/FetchDataExampleTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class FetchDataExampleTest {
1111
@Test fun `fake network example`() {
1212

1313
MyFormula()
14-
.test()
14+
.test(Unit)
1515
.apply {
1616
values().last().onChangeId("1")
1717
values().last().onChangeId("2")

0 commit comments

Comments
 (0)