Skip to content

Commit

Permalink
[doc] Add some documentation on testing custom datafetchers with subs…
Browse files Browse the repository at this point in the history
…criptions

Signed-off-by: Stéphane Bégaudeau <[email protected]>
  • Loading branch information
sbegaudeau authored and gcoutable committed Aug 21, 2024
1 parent dd9b41e commit 30fab80
Showing 1 changed file with 72 additions and 0 deletions.
72 changes: 72 additions & 0 deletions doc/how-to/test-sirius-web-based-applications.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
= How to test Sirius Web based applications

== How to perform GraphQL requests?

There are three main APIs to perform GraphQL requests.

The first way to perform a GraphQL request is by using one of the implementations of `IQueryRunner` to execute queries used to retrieves data from the backend.
It is also possible to use one of the implementations of `IMutationRunner` to perform changes in the backend.
Finally, we can use an implementation of `ISubscriptionRunner` to subscribe to flux of data to be warned when something has been changed.

Those runners exist in order to give contributors of the Sirius Web project and downstream projects of Sirius Web a set of APIs encapsulating the body of the requests and the way to execute it.


== How to test custom datafetchers in a subscription

In the project `sirius-web`, we have countless tests using subscriptions.
In order to subscribe to the flux of data of those subscription, we are most of the time relying on `IGraphQLRequestor#subscribe` directly or not by using a `XxxSubscriptionRunner` which encapsulates the body of the request too.
By using `IGraphQLRequestor#subscribe`, we will return the raw `Flux<Object>` created by the event processor.
The subscription to this flux will not trigger the execution of child data fetchers.

For example, let's consider the following fake subscription:

```
subscription someRepresentationEvent($input: SomeRepresentationEventInput!) {
someRepresentationEvent(input: $input) {
__typename
}
}
```

Using such a subscription with `IGraphQLRequestor#subscribe` would not trigger the execution of child datafetchers.
But contrary to what one may believe, executing this subscription instead would not change this fact:

```
subscription someRepresentationEvent($input: SomeRepresentationEventInput!) {
someRepresentationEvent(input: $input) {
__typename
... on SomeRepresentationRefreshedEventPayload {
someValue {
customDataFetcherWithSomeParameters(arg1: 'foo', arg2: 'bar')
}
}
}
}
```

By using `IGraphQLRequestor#subscribe`, the custom datafetcher will not be executed and only the raw payloads will be returned.

In order to trigger the execution of the custom datafetcher in a subscription, one has to use `IGraphQLRequestor#subscribeToSpecification` which will instead return a `Flux<String>` just like the one used by the frontend.
This flux will emit the JSON serialization of the data created accordingly to the official GraphQL specification.
This will trigger the execution of all the datafetchers used in the body of the request.

In order to perform evaluation on such result, it is best to use `JsonPath` in this manner:

```
var input = new SomeRepresentationEventInput(...);
var flux = this.graphQLRequestor.subscribeToSpecification(SUBSCRIPTION, input);

Consumer<String> consumer = payload -> Optional.of(payload)
.ifPresentOrElse(body -> {
String typename = JsonPath.read(body, "$.data.someRepresentationEvent.__typename");
assertThat(typename).isEqualTo("SomeRepresentationRefreshedEventPayload");

String value = JsonPath.read(body, "$.data.someRepresentationEvent.someValue.customDataFetcherWithSomeParameters");
assertThat(value).isEqualTo("foobar");
}, () -> fail("Missing data"));

StepVerifier.create(flux)
.consumeNextWith(consumer)
.thenCancel()
.verify(Duration.ofSeconds(10));
```

0 comments on commit 30fab80

Please sign in to comment.