Repository: apollographql/apollo-kotlin
Pull request #4377 (2022-09-09 16:30:12)

updates roadmap for sept 2022
Sept 2022 roadmap updates. 

netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *apollo-android-docs* processing.


|  Name | Link |
|---------------------------------|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 854bd993823abb350b0981486cfaab6619086f8f |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/apollo-android-docs/deploys/631b6a15a1c3aa00093a866a |
jpvajda: @martinbonnin 👋  let me know how this sounds to you. 😎 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a95310ff31..f9635d1cc9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ This version brings initial support for `@defer` as well as data builders.
 
 Many thanks to @engdorm, @Goooler, @pt2121 and @StylianosGakis for their contributions!
 
+## ✨️ [new] Kotlin 1.7 (#4314)
+
+Starting with this release, Apollo Kotlin is built with Kotlin 1.7.10. This doesn't impact Android and JVM projects (the minimum supported version of Kotlin continues to be 1.5) but if you are on a project using Native or JS, you will need to update the Kotlin version to 1.7.0+.
+
 ## ✨️ [new] `@defer` support
 
 `@defer` support is experimental in the Kotlin Client and currently a [Stage 2 GraphQL specification draft](https://github.com/graphql/graphql-spec/blob/main/CONTRIBUTING.md#stage-2-draft) to allow incremental delivery of response payloads. 
@@ -119,10 +123,6 @@ val data = GetHeroQuery.Data {
 } 
 ```
 
-## ✨️ [new] Kotlin 1.7 (#4314)
-
-Starting with this release, Apollo Kotlin is built with Kotlin 1.7.10. This doesn't impact Android and JVM projects (the minimum supported version of Kotlin continues to be 1.5) but if you are on a project using Native, you will need to update the Kotlin version to 1.7.0+.
-
 ## 👷‍ All changes
 
 * fix registering Java scalars. Many thanks @parker for catching this. (#4375)
diff --git a/ROADMAP.md b/ROADMAP.md
index 0e03d530b7..c166ccfa9f 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -1,6 +1,6 @@
 # 🔮 Apollo Kotlin Roadmap
 
-**Last updated: Aug 2022**
+**Last updated: Sept 2022**
 
 For up to date release notes, refer to the project [Change Log](https://github.com/apollographql/apollo-kotlin/blob/main/CHANGELOG.md).
 
@@ -15,9 +15,9 @@ For up to date release notes, refer to the project [Change Log](https://github.c
 
 ## Upcoming Releases
 
-### 3.6
+### Release TBD
 
-- Release 3.6 will focus on adding support for the `@defer` directive as well as adding `schemaBased` test builders. See Github [3.6 Milestone](https://github.com/apollographql/apollo-kotlin/milestone/23) for more details.
+- This release will focus on providing better Java support in Apollo Kotlin.  See Github [Java Support Release TBD](https://github.com/apollographql/apollo-kotlin/milestone/25) for more details.
 
 ## Longer Term
 
@@ -25,14 +25,14 @@ For up to date release notes, refer to the project [Change Log](https://github.c
 
 The declarative cache makes working with the cache and defining unique object ids easier. We also want to include helpers to handle with common cases like pagination, garbage collection and eviction. Follow [#2331](https://github.com/apollographql/apollo-kotlin/issues/2331) for a high level overview. The current focus is on cache control and expiration. You can read more in [the cache control design document](https://github.com/apollographql/apollo-kotlin/pull/4009).
 
-### Test APIs
-
-Apollo Kotlin 3 introduces [test builders](https://www.apollographql.com/docs/kotlin/testing/test-builders/) as a new type-safe way to build test data. While this is working, it generates a lot of code, making it hard to include in main source sets. This can be problematic in some cases like Jetpack Compose `@Preview` for an example. We are investigating generating schema-based test builders for simpler and more lightweight APIs.
-
 ### Rel 1.0 Android Studio Plugin
 
 Currently there is no plugin for Android Studio for Apollo GraphQL. We'd like to offer better support for Android developers who wish to use our Kotlin Client.
 
+### Better support for Jetpack Compose
+
+[Jetpack Compose](https://developer.android.com/jetpack/compose) is a declarative UI framework for building Android UIs written in Kotlin. We'd like to offer better support for Android developers who wish to use Jetpack Compose with our Kotlin Client.
+
 ### `release-2.x` branch
 
 `release-2.x` is the Apollo Android `2.x` branch. Major security issues or fixes will get new releases.
diff --git a/apollo-gradle-plugin/build.gradle.kts b/apollo-gradle-plugin/build.gradle.kts
index f72342a276..114b3c8dba 100644
--- a/apollo-gradle-plugin/build.gradle.kts
+++ b/apollo-gradle-plugin/build.gradle.kts
@@ -112,12 +112,6 @@ configure<PublishingExtension> {
         }
       }
     }
-    if (relocateJar && name == "pluginMaven") {
-      this as MavenPublication
-      artifact(file("build/gr8/shadow/mapping.txt")) {
-        classifier = "mapping"
-      }
-    }
   }
 }
 
diff --git a/apollo-gradle-plugin/rules.pro b/apollo-gradle-plugin/rules.pro
index c22131c61e..1710d713c5 100644
--- a/apollo-gradle-plugin/rules.pro
+++ b/apollo-gradle-plugin/rules.pro
@@ -4,7 +4,6 @@
 -keep class kotlin.Metadata { *; }
 -keep class kotlin.Unit { *; }
 
-
 # We need to keep type arguments (Signature) for Gradle to be able to instantiate abstract models like `Property`
 # Else it fails with
 # 'Declaration of property alwaysGenerateTypesMatching does not include any type arguments in its property type interface org.gradle.api.provider.SetProperty'
@@ -53,6 +52,8 @@
 
 # Makes it easier to debug on MacOS case-insensitive filesystem when unzipping the jars
 -dontusemixedcaseclassnames
+# Keep class names to make debugging easier
+-dontobfuscate
 -repackageclasses com.apollographql.relocated
 
 # Allow to repackage com.moshi.JsonAdapter.lenient
diff --git a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt
index 83acb0f79e..51aa867a80 100644
--- a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt
+++ b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt
@@ -34,6 +34,14 @@ class DeferredJsonMerger {
   var hasNext: Boolean = true
     private set
 
+  /**
+   * A payload can sometimes have no `incremental` field, e.g. when the server couldn't predict if there were more data after the last
+   * emitted payload. This field allows to test for this in order to ignore such payloads.
+   * See https://github.com/apollographql/router/issues/1687.
+   */
+  var isEmptyPayload: Boolean = false
+    private set
+
   fun merge(payload: BufferedSource): JsonMap {
     val payloadMap = jsonToMap(payload)
     return merge(payloadMap)
@@ -48,7 +56,10 @@ class DeferredJsonMerger {
     }
 
     val incrementalList = payload["incremental"] as? List<JsonMap>
-    if (incrementalList != null) {
+    if (incrementalList == null) {
+      isEmptyPayload = true
+    } else {
+      isEmptyPayload = false
       val mergedErrors = mutableListOf<JsonMap>()
       val mergedExtensions = mutableListOf<JsonMap>()
       for (incrementalItem in incrementalList) {
@@ -131,6 +142,7 @@ class DeferredJsonMerger {
     _merged.clear()
     _mergedFragmentIds.clear()
     hasNext = true
+    isEmptyPayload = false
   }
 }
 
diff --git a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt
index 37b60b68f9..bc7107e1aa 100644
--- a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt
+++ b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt
@@ -23,6 +23,7 @@ import com.apollographql.apollo3.network.NetworkTransport
 import com.benasher44.uuid.Uuid
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.emitAll
+import kotlinx.coroutines.flow.filterNot
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.map
 
@@ -110,19 +111,21 @@ private constructor(
       httpResponse: HttpResponse,
   ): Flow<ApolloResponse<D>> {
     val jsonMerger = DeferredJsonMerger()
-    return multipartBodyFlow(httpResponse).map { part ->
-      try {
-        val merged = jsonMerger.merge(part)
-        val deferredFragmentIds = jsonMerger.mergedFragmentIds
-        val isLast = !jsonMerger.hasNext
-        operation.parseJsonResponse(
-            jsonReader = merged.jsonReader(),
-            customScalarAdapters = customScalarAdapters.withDeferredFragmentIds(deferredFragmentIds)
-        ).newBuilder().isLast(isLast).build()
-      } catch (e: Exception) {
-        throw wrapThrowableIfNeeded(e)
-      }
-    }
+    return multipartBodyFlow(httpResponse)
+        .map { part ->
+          try {
+            val merged = jsonMerger.merge(part)
+            val deferredFragmentIds = jsonMerger.mergedFragmentIds
+            val isLast = !jsonMerger.hasNext
+            operation.parseJsonResponse(
+                jsonReader = merged.jsonReader(),
+                customScalarAdapters = customScalarAdapters.withDeferredFragmentIds(deferredFragmentIds)
+            ).newBuilder().isLast(isLast).build()
+          } catch (e: Exception) {
+            throw wrapThrowableIfNeeded(e)
+          }
+        }
+        .filterNot { jsonMerger.isEmptyPayload }
   }
 
   private fun <D : Operation.Data> ApolloResponse<D>.withHttpInfo(
diff --git a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/ws/WebSocketNetworkTransport.kt b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/ws/WebSocketNetworkTransport.kt
index 49b66a4d5d..683d8b2105 100644
--- a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/ws/WebSocketNetworkTransport.kt
+++ b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/ws/WebSocketNetworkTransport.kt
@@ -40,6 +40,7 @@ import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNot
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onCompletion
 import kotlinx.coroutines.flow.onSubscription
@@ -303,12 +304,15 @@ private constructor(
           }
           apolloResponse
         }
+
         is OperationError -> throw SubscriptionOperationException(request.operation.name(), response.payload)
         is NetworkError -> throw ApolloNetworkException("Network error while executing ${request.operation.name()}", response.cause)
 
         // Cannot happen as these events are filtered out upstream
         is OperationComplete, is GeneralError -> error("Unexpected event $response")
       }
+    }.filterNot {
+      deferredJsonMerger.isEmptyPayload
     }.onCompletion {
       messages.send(StopOperation(request))
     }
diff --git a/docs/source/advanced/multi-modules.mdx b/docs/source/advanced/multi-modules.mdx
index 16f6004b83..f971cd385a 100644
--- a/docs/source/advanced/multi-modules.mdx
+++ b/docs/source/advanced/multi-modules.mdx
@@ -52,16 +52,19 @@ dependencies {
 }
 
 // shared/build.gradle.kts
+// This module must not have a schema
 // This module can use fragments and types from 'schema'
 dependencies {
     apolloMetadata(project(":schema"))
+}
+apollo {
     generateApolloMetadata.set(true)
 }
 
 // schema/build.gradle.kts
 // This module is the schema module
 // Place the schema in this module
-dependencies {
+apollo {
     generateApolloMetadata.set(true)
 }
 ```
diff --git a/docs/source/fetching/defer.mdx b/docs/source/fetching/defer.mdx
index 32262f69b8..e40eb4477f 100644
--- a/docs/source/fetching/defer.mdx
+++ b/docs/source/fetching/defer.mdx
@@ -3,9 +3,9 @@ title: 'Using the @defer directive in Apollo Kotlin'
 description: 'Fetch slower schema fields asynchronously'
 ---
 
-> ⚠️ **The `@defer` directive is experimental in Apollo Kotlin and currently a [Stage 2 GraphQL specification draft](https://github.com/graphql/graphql-spec/blob/main/CONTRIBUTING.md#stage-2-draft).** Before it reaches Stage3 acceptance into the GraphQL specification, it could change in backward incompatible ways. If you have feedback on it, please let us know via [GitHub issues](https://github.com/apollographql/apollo-android/issues/new?assignees=&labels=Type%3A+Bug&template=bug_report.md&title=[Defer%20Support]) or in the [Kotlin Slack community](https://slack.kotl.in/).
+> ⚠️ **The `@defer` directive is currently [experimental](https://www.apollographql.com/docs/resources/release-stages/#experimental-features) in Apollo Kotlin and enabled for use by default.** If you have feedback on it, please let us know via [GitHub issues](https://github.com/apollographql/apollo-android/issues/new?assignees=&labels=Type%3A+Bug&template=bug_report.md&title=[Defer%20Support]) or in the [Kotlin Slack community](https://slack.kotl.in/).
 
-Beginning with version `3.6.0`, Apollo Kotlin supports [the `@defer` directive](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md), which enables your queries to receive data for specific fields asynchronously. This is helpful whenever some fields in a query take much longer to resolve than the others.
+Beginning with version `3.6.0`, Apollo Kotlin provides experimental support of [the `@defer` directive](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md), which enables your queries to receive data for specific fields asynchronously. This is helpful whenever some fields in a query take much longer to resolve than the others.
 
 For example, let's say we're building a social media application that can quickly fetch a user's basic profile information, but retrieving that user's friends takes longer. If we include _all_ of those fields in a single query, we want to be able to display the profile information as soon as it's available, instead of waiting for the friend fields to resolve.
 
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bdfcc729d1..98be7b5b63 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -65,7 +65,7 @@ dokka-base = { group = "org.jetbrains.dokka", name = "dokka-base", version.ref =
 dokka-plugin = { group = "org.jetbrains.dokka", name = "dokka-gradle-plugin", version.ref = "dokka" }
 google-testing-compile = { group = "com.google.testing.compile", name = "compile-testing", version = "0.19" }
 google-testparameterinjector = { group = "com.google.testparameterinjector", name = "test-parameter-injector", version = "1.4" }
-gr8 = { group = "com.gradleup", name = "gr8-plugin", version = "0.4" }
+gr8 = { group = "com.gradleup", name = "gr8-plugin", version = "0.6" }
 #
 # See https://github.com/gradle/gradle/issues/1835
 # We use the Nokee[redistributed artifacts](https://docs.nokee.dev/manual/gradle-plugin-development.html#sec:gradle-dev-redistributed-gradle-api)


Test patch:
diff --git a/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt b/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferredJsonMergerTest.kt
similarity index 86%
rename from apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt
rename to apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferredJsonMergerTest.kt
index 5b06a81f20..f858e6daaf 100644
--- a/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt
+++ b/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferredJsonMergerTest.kt
@@ -9,13 +9,15 @@ import com.apollographql.apollo3.api.json.readAny
 import okio.Buffer
 import kotlin.test.Test
 import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
 
-class DeferJsonMergerTest {
-  @Test
-  fun mergeJsonSingleIncrementalItem() {
-      val deferredJsonMerger = DeferredJsonMerger()
+class DeferredJsonMergerTest {
+    @Test
+    fun mergeJsonSingleIncrementalItem() {
+        val deferredJsonMerger = DeferredJsonMerger()
 
-      val payload1 = """
+        val payload1 = """
       {
         "data": {
           "computers": [
@@ -352,14 +354,14 @@ class DeferJsonMergerTest {
         ]
       }
     """
-      deferredJsonMerger.merge(payload5.buffer())
-      assertEquals(jsonToMap(mergedPayloads_1_2_3_4_5), deferredJsonMerger.merged)
-      assertEquals(setOf(
-          DeferredFragmentIdentifier(path = listOf("computers", 0), label = "query:Query1:0"),
-          DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
-          DeferredFragmentIdentifier(path = listOf("computers", 1, "screen"), label = "fragment:ComputerFields:0"),
-      ), deferredJsonMerger.mergedFragmentIds)
-  }
+        deferredJsonMerger.merge(payload5.buffer())
+        assertEquals(jsonToMap(mergedPayloads_1_2_3_4_5), deferredJsonMerger.merged)
+        assertEquals(setOf(
+            DeferredFragmentIdentifier(path = listOf("computers", 0), label = "query:Query1:0"),
+            DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
+            DeferredFragmentIdentifier(path = listOf("computers", 1, "screen"), label = "fragment:ComputerFields:0"),
+        ), deferredJsonMerger.mergedFragmentIds)
+    }
 
     @Test
     fun mergeJsonMultipleIncrementalItems() {
@@ -624,6 +626,81 @@ class DeferJsonMergerTest {
             DeferredFragmentIdentifier(path = listOf("computers", 1, "screen"), label = "fragment:ComputerFields:0"),
         ), deferredJsonMerger.mergedFragmentIds)
     }
+
+    @Test
+    fun emptyPayloads() {
+        val deferredJsonMerger = DeferredJsonMerger()
+
+        val payload1 = """
+      {
+        "data": {
+          "computers": [
+            {
+              "id": "Computer1",
+              "screen": {
+                "isTouch": true
+              }
+            },
+            {
+              "id": "Computer2",
+              "screen": {
+                "isTouch": false
+              }
+            }
+          ]
+        },
+        "hasNext": true
+      }
+    """
+        deferredJsonMerger.merge(payload1.buffer())
+        assertFalse(deferredJsonMerger.isEmptyPayload)
+
+        val payload2 = """
+      {
+        "hasNext": true
+      }
+    """
+        deferredJsonMerger.merge(payload2.buffer())
+        assertTrue(deferredJsonMerger.isEmptyPayload)
+
+        val payload3 = """
+      {
+        "incremental": [
+          {
+            "data": {
+              "cpu": "386",
+              "year": 1993,
+              "screen": {
+                "resolution": "640x480"
+              }
+            },
+            "path": [
+              "computers",
+              0
+            ],
+            "label": "query:Query1:0",
+            "extensions": {
+              "duration": {
+                "amount": 100,
+                "unit": "ms"
+              }
+            }
+          }
+        ],
+        "hasNext": true
+      }
+    """
+        deferredJsonMerger.merge(payload3.buffer())
+        assertFalse(deferredJsonMerger.isEmptyPayload)
+
+        val payload4 = """
+      {
+        "hasNext": false
+      }
+    """
+        deferredJsonMerger.merge(payload4.buffer())
+        assertTrue(deferredJsonMerger.isEmptyPayload)
+    }
 }
 
 private fun String.buffer() = Buffer().writeUtf8(this)
diff --git a/tests/defer/README.md b/tests/defer/README.md
index f592d552d8..ba3ebf7c4d 100644
--- a/tests/defer/README.md
+++ b/tests/defer/README.md
@@ -1,5 +1,4 @@
 # Tests related to `@defer`
 
-At the moment the tests use `StreamingNSURLSessionHttpEngine` on Apple targets, which requires
-the [new Memory Manager](https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md). It is enabled on this
-project in `gradle.propertis`.
+Note: on Apple targets, the client is configured to use `StreamingNSURLSessionHttpEngine` which supports chunked
+encoding.  
diff --git a/tests/defer/src/commonMain/graphql/base/operation.graphql b/tests/defer/src/commonMain/graphql/base/operation.graphql
index a8f3dfb722..c7a2489148 100644
--- a/tests/defer/src/commonMain/graphql/base/operation.graphql
+++ b/tests/defer/src/commonMain/graphql/base/operation.graphql
@@ -62,3 +62,12 @@ subscription WithFragmentSpreadsSubscription {
 fragment CounterFields on Counter{
   valueTimesTwo
 }
+
+query SimpleDeferQuery {
+  computers {
+    id
+    ... on Computer @defer {
+      cpu
+    }
+  }
+}
diff --git a/tests/defer/src/commonTest/kotlin/test/DeferTest.kt b/tests/defer/src/commonTest/kotlin/test/DeferTest.kt
index 069e01ff62..ba9b353ec6 100644
--- a/tests/defer/src/commonTest/kotlin/test/DeferTest.kt
+++ b/tests/defer/src/commonTest/kotlin/test/DeferTest.kt
@@ -11,6 +11,7 @@ import com.apollographql.apollo3.mpp.currentTimeMillis
 import com.apollographql.apollo3.mpp.platform
 import com.apollographql.apollo3.testing.internal.runTest
 import com.benasher44.uuid.uuid4
+import defer.SimpleDeferQuery
 import defer.WithFragmentSpreadsQuery
 import defer.WithInlineFragmentsQuery
 import defer.fragment.ComputerFields
@@ -285,4 +286,34 @@ class DeferTest {
     }
     job.cancel()
   }
+
+  @Test
+  fun emptyPayloadsAreIgnored() = runTest(before = { setUp() }, after = { tearDown() }) {
+    val jsonWithEmptyPayload = listOf(
+        """{"data":{"computers":[{"__typename":"Computer","id":"computer1"}]},"hasNext":true}""",
+        """{"incremental": [{"data":{"cpu":"386"},"path":["computers",0]}],"hasNext":true}""",
+        """{"hasNext":false}""",
+    )
+    val jsonWithoutEmptyPayload = listOf(
+        """{"data":{"computers":[{"__typename":"Computer","id":"computer1"}]},"hasNext":true}""",
+        """{"incremental": [{"data":{"cpu":"386"},"path":["computers",0]}],"hasNext":false}""",
+    )
+
+    val expectedDataList = listOf(
+        SimpleDeferQuery.Data(
+            listOf(SimpleDeferQuery.Computer("Computer", "computer1", null))
+        ),
+        SimpleDeferQuery.Data(
+            listOf(SimpleDeferQuery.Computer("Computer", "computer1", SimpleDeferQuery.OnComputer("386")))
+        ),
+    )
+
+    mockServer.enqueueMultipart(jsonWithEmptyPayload)
+    var actualDataList = apolloClient.query(SimpleDeferQuery()).toFlow().toList().map { it.dataAssertNoErrors }
+    assertEquals(expectedDataList, actualDataList)
+
+    mockServer.enqueueMultipart(jsonWithoutEmptyPayload)
+    actualDataList = apolloClient.query(SimpleDeferQuery()).toFlow().toList().map { it.dataAssertNoErrors }
+    assertEquals(expectedDataList, actualDataList)
+  }
 }