Skip to content

Commit

Permalink
Implement host-side view recycling (#1904)
Browse files Browse the repository at this point in the history
* Implement host-side view recycling

* Fix a build break

* Fix some failing tests

* Use more compose in the test harness

* Track test schema changes

* Track an API change

* Update redwood-protocol-host/src/commonMain/kotlin/app/cash/redwood/protocol/widget/ProtocolBridge.kt

Co-authored-by: Jake Wharton <[email protected]>

* Update redwood-protocol-host/src/commonMain/kotlin/app/cash/redwood/protocol/widget/ProtocolBridge.kt

Co-authored-by: Jake Wharton <[email protected]>

* Update test-app/ios-uikit/TestApp/IosTestSchemaWidgetFactory.swift

Co-authored-by: Jake Wharton <[email protected]>

* Sort in Compose, not protocol

* Reuse as a part of EmojiSearch API

* Track change reorder in test generation

* Track an API change in EmojiSearch

---------

Co-authored-by: Jake Wharton <[email protected]>
  • Loading branch information
squarejesse and JakeWharton authored Mar 29, 2024
1 parent 8e22975 commit 5519280
Show file tree
Hide file tree
Showing 27 changed files with 1,114 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ abstract class AbstractChangeListenerTest {
snapshot: () -> T,
): TestRedwoodComposition<T>

@Test fun propertyChangeNotifiesWidget() = runTest {
@Test
fun propertyChangeNotifiesWidget() = runTest {
val button = ListeningButton()
val widgetSystem = TestSchemaWidgetSystem(
TestSchema = object : TestSchemaWidgetFactory<WidgetValue> by TestSchemaTestingWidgetFactory() {
Expand All @@ -91,13 +92,14 @@ abstract class AbstractChangeListenerTest {
c.setContent {
Button(text, onClick = null)
}
assertThat(c.awaitSnapshot()).containsExactly("modifier Modifier", "text hi", "onClick false", "onEndChanges")
assertThat(c.awaitSnapshot()).containsExactly("text hi", "onClick false", "modifier Modifier", "onEndChanges")

text = "hello"
assertThat(c.awaitSnapshot()).containsExactly("text hello", "onEndChanges")
}

@Test fun unrelatedPropertyChangeDoesNotNotifyWidget() = runTest {
@Test
fun unrelatedPropertyChangeDoesNotNotifyWidget() = runTest {
val button = ListeningButton()
val widgetSystem = TestSchemaWidgetSystem(
TestSchema = object : TestSchemaWidgetFactory<WidgetValue> by TestSchemaTestingWidgetFactory() {
Expand All @@ -113,13 +115,14 @@ abstract class AbstractChangeListenerTest {
Button("hi", onClick = null)
Text(text)
}
assertThat(c.awaitSnapshot()).containsExactly("modifier Modifier", "text hi", "onClick false", "onEndChanges")
assertThat(c.awaitSnapshot()).containsExactly("text hi", "onClick false", "modifier Modifier", "onEndChanges")

text = "hello"
assertThat(c.awaitSnapshot()).isEmpty()
}

@Test fun modifierChangeNotifiesWidget() = runTest {
@Test
fun modifierChangeNotifiesWidget() = runTest {
val button = ListeningButton()
val widgetSystem = TestSchemaWidgetSystem(
TestSchema = object : TestSchemaWidgetFactory<WidgetValue> by TestSchemaTestingWidgetFactory() {
Expand All @@ -134,15 +137,16 @@ abstract class AbstractChangeListenerTest {
c.setContent {
Button("hi", onClick = null, modifier = modifier)
}
assertThat(c.awaitSnapshot()).containsExactly("modifier Modifier", "text hi", "onClick false", "onEndChanges")
assertThat(c.awaitSnapshot()).containsExactly("text hi", "onClick false", "modifier Modifier", "onEndChanges")

modifier = with(object : TestScope {}) {
Modifier.accessibilityDescription("hey")
}
assertThat(c.awaitSnapshot()).containsExactly("modifier AccessibilityDescription(value=hey)", "onEndChanges")
}

@Test fun multipleChangesNotifyWidgetOnce() = runTest {
@Test
fun multipleChangesNotifyWidgetOnce() = runTest {
val button = ListeningButton()
val widgetSystem = TestSchemaWidgetSystem(
TestSchema = object : TestSchemaWidgetFactory<WidgetValue> by TestSchemaTestingWidgetFactory() {
Expand All @@ -158,16 +162,17 @@ abstract class AbstractChangeListenerTest {
c.setContent {
Button(text, onClick = null, modifier = modifier)
}
assertThat(c.awaitSnapshot()).containsExactly("modifier Modifier", "text hi", "onClick false", "onEndChanges")
assertThat(c.awaitSnapshot()).containsExactly("text hi", "onClick false", "modifier Modifier", "onEndChanges")

text = "hello"
modifier = with(object : TestScope {}) {
Modifier.accessibilityDescription("hey")
}
assertThat(c.awaitSnapshot()).containsExactly("modifier AccessibilityDescription(value=hey)", "text hello", "onEndChanges")
assertThat(c.awaitSnapshot()).containsExactly("text hello", "modifier AccessibilityDescription(value=hey)", "onEndChanges")
}

@Test fun childrenChangeNotifiesWidget() = runTest {
@Test
fun childrenChangeNotifiesWidget() = runTest {
val row = ListeningTestRow()
val widgetSystem = TestSchemaWidgetSystem(
TestSchema = object : TestSchemaWidgetFactory<WidgetValue> by TestSchemaTestingWidgetFactory() {
Expand All @@ -194,7 +199,8 @@ abstract class AbstractChangeListenerTest {
assertThat(c.awaitSnapshot()).containsExactly("children insert", "onEndChanges")
}

@Test fun childrenDescendantChangeDoesNotNotifyWidget() = runTest {
@Test
fun childrenDescendantChangeDoesNotNotifyWidget() = runTest {
val row = ListeningTestRow()
val widgetSystem = TestSchemaWidgetSystem(
TestSchema = object : TestSchemaWidgetFactory<WidgetValue> by TestSchemaTestingWidgetFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,18 @@ class ProtocolTest {
ModifierChange(Id(1)),
// Text
Create(Id(2), WidgetTag(3)),
ModifierChange(Id(2)),
// text
PropertyChange(Id(2), PropertyTag(1), JsonPrimitive("hey")),
ModifierChange(Id(2)),
ChildrenChange.Add(Id(1), ChildrenTag(1), Id(2), 0),
// Row
Create(Id(3), WidgetTag(1)),
ModifierChange(Id(3)),
// Text
Create(Id(4), WidgetTag(3)),
ModifierChange(Id(4)),
// text
PropertyChange(Id(4), PropertyTag(1), JsonPrimitive("hello")),
ModifierChange(Id(4)),
ChildrenChange.Add(Id(3), ChildrenTag(1), Id(4), 0),
ChildrenChange.Add(Id(1), ChildrenTag(1), Id(3), 1),
ChildrenChange.Add(Id.Root, ChildrenTag.Root, Id(1), 0),
Expand All @@ -131,27 +131,27 @@ class ProtocolTest {
listOf(
// Button
Create(Id(1), WidgetTag(4)),
ModifierChange(Id(1)),
// text
PropertyChange(Id(1), PropertyTag(1), JsonPrimitive("hi")),
// onClick
PropertyChange(Id(1), PropertyTag(2), JsonPrimitive(false)),
ModifierChange(Id(1)),
ChildrenChange.Add(Id.Root, ChildrenTag.Root, Id(1), 0),
// Button
Create(Id(2), WidgetTag(4)),
ModifierChange(Id(2)),
// text
PropertyChange(Id(2), PropertyTag(1), JsonPrimitive("hi")),
// onClick
PropertyChange(Id(2), PropertyTag(2), JsonPrimitive(true)),
ModifierChange(Id(2)),
ChildrenChange.Add(Id.Root, ChildrenTag.Root, Id(2), 1),
// Button2
Create(Id(3), WidgetTag(7)),
ModifierChange(Id(3)),
// text
PropertyChange(Id(3), PropertyTag(1), JsonPrimitive("hi")),
// onClick
PropertyChange(Id(3), PropertyTag(2), JsonPrimitive(true)),
ModifierChange(Id(3)),
ChildrenChange.Add(Id.Root, ChildrenTag.Root, Id(3), 2),
),
)
Expand Down Expand Up @@ -190,11 +190,11 @@ class ProtocolTest {
listOf(
// Button
Create(Id(1), WidgetTag(4)),
ModifierChange(Id(1)),
// text
PropertyChange(Id(1), PropertyTag(1), JsonPrimitive("state: 0")),
// onClick
PropertyChange(Id(1), PropertyTag(2), JsonPrimitive(true)),
ModifierChange(Id(1)),
ChildrenChange.Add(Id.Root, ChildrenTag.Root, Id(1), 0),
),
)
Expand Down Expand Up @@ -257,11 +257,11 @@ class ProtocolTest {
listOf(
// Button2
Create(Id(1), WidgetTag(7)),
ModifierChange(Id(1)),
// text
PropertyChange(Id(1), PropertyTag(1), JsonPrimitive("state: 0")),
// onClick
PropertyChange(Id(1), PropertyTag(2), JsonPrimitive(true)),
ModifierChange(Id(1)),
ChildrenChange.Add(Id.Root, ChildrenTag.Root, Id(1), 0),
),
)
Expand Down
Loading

0 comments on commit 5519280

Please sign in to comment.