Skip to content

Commit 72136f3

Browse files
authored
feat: add ws example tests (#953)
1 parent 8e3d221 commit 72136f3

File tree

16 files changed

+449
-116
lines changed

16 files changed

+449
-116
lines changed

packages/todo-example/client-apollo/package.json

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22
"name": "@n1ru4l/todo-example-client-apollo",
33
"version": "0.1.0",
44
"private": true,
5-
"dependencies": {
6-
"@apollo/client": "3.6.9",
7-
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
8-
"@n1ru4l/push-pull-async-iterable-iterator": "3.2.0",
9-
"@n1ru4l/socket-io-graphql-client": "*",
10-
"@repeaterjs/repeater": "3.0.4",
11-
"@app/gql": "link:./src/gql",
12-
"graphql": "16.0.0-experimental-stream-defer.5"
13-
},
145
"devDependencies": {
156
"@graphql-codegen/cli": "2.8.0",
167
"@graphql-codegen/gql-tag-operations-preset": "1.5.1",
@@ -25,7 +16,15 @@
2516
"react-dom": "17.0.2",
2617
"socket.io-client": "4.5.1",
2718
"todomvc-app-css": "2.4.2",
28-
"vite": "2.9.14"
19+
"vite": "2.9.14",
20+
"@apollo/client": "3.6.9",
21+
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
22+
"@n1ru4l/push-pull-async-iterable-iterator": "3.2.0",
23+
"@n1ru4l/socket-io-graphql-client": "*",
24+
"@repeaterjs/repeater": "3.0.4",
25+
"@app/gql": "link:./src/gql",
26+
"graphql": "16.0.0-experimental-stream-defer.5",
27+
"graphql-ws": "5.9.1"
2928
},
3029
"scripts": {
3130
"start": "vite",
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// for Apollo Client v3 older than v3.5.10:
2+
import {
3+
ApolloLink,
4+
Operation,
5+
FetchResult,
6+
Observable,
7+
} from "@apollo/client/core";
8+
import { print } from "graphql";
9+
import { createClient, Client } from "graphql-ws";
10+
import { makeAsyncIterableIteratorFromSink } from "@n1ru4l/push-pull-async-iterable-iterator";
11+
import { applySourceToSink } from "./shared";
12+
13+
class GraphQLWsLink extends ApolloLink {
14+
private client: Client;
15+
constructor(url: string) {
16+
super();
17+
this.client = createClient({
18+
url,
19+
});
20+
}
21+
22+
public request(operation: Operation): Observable<FetchResult> {
23+
return new Observable((sink) => {
24+
const source = makeAsyncIterableIteratorFromSink((sink) => {
25+
return this.client.subscribe<FetchResult>(
26+
{ ...operation, query: print(operation.query) },
27+
{
28+
next: sink.next.bind(sink),
29+
complete: sink.complete.bind(sink),
30+
error: sink.error.bind(sink),
31+
}
32+
);
33+
});
34+
35+
return applySourceToSink(source, sink);
36+
});
37+
}
38+
}
39+
40+
export function createWSApolloLink(url: string) {
41+
return new GraphQLWsLink(url);
42+
}

packages/todo-example/client-apollo/src/index.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ const Root = (): React.ReactElement | null => {
3737
);
3838
}
3939
);
40+
} else if (params.get("ws")) {
41+
let host = params.get("host") ?? undefined;
42+
import("./apollo-link/create-ws-apollo-link").then(
43+
async ({ createWSApolloLink }) => {
44+
setClient(
45+
createApolloClient(
46+
createWSApolloLink(
47+
(host ?? `ws://${window.location.host}`) + "/graphql"
48+
)
49+
)
50+
);
51+
}
52+
);
4053
} else {
4154
import("./apollo-link/create-socket-io-apollo-link").then(
4255
async ({ createSocketIOApolloLink }) => {

packages/todo-example/client-relay/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"todomvc-app-css": "2.4.2",
2929
"classnames": "2.3.1",
3030
"vite": "2.9.14",
31-
"vite-plugin-babel-macros": "1.0.6"
31+
"vite-plugin-babel-macros": "1.0.6",
32+
"graphql-ws": "5.9.1"
3233
},
3334
"scripts": {
3435
"start": "vite",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {
2+
GraphQLResponse,
3+
Observable,
4+
RequestParameters,
5+
Variables,
6+
} from "relay-runtime";
7+
import { createClient } from "graphql-ws";
8+
import { Repeater } from "@repeaterjs/repeater";
9+
import { applySourceToSink } from "./shared";
10+
import { makeAsyncIterableIteratorFromSink } from "@n1ru4l/push-pull-async-iterable-iterator";
11+
12+
function makeEventStreamSource(url: string) {
13+
return new Repeater<GraphQLResponse>(async (push, end) => {
14+
const eventsource = new EventSource(url);
15+
eventsource.onmessage = function (event) {
16+
const data = JSON.parse(event.data);
17+
push(data);
18+
if (eventsource.readyState === 2) {
19+
end();
20+
}
21+
};
22+
eventsource.onerror = function (event) {
23+
console.log("Error", event);
24+
end(new Error("Check the console bruv."));
25+
};
26+
await end;
27+
28+
eventsource.close();
29+
});
30+
}
31+
32+
export function createWSFetcher(url: string) {
33+
const client = createClient({ url });
34+
return (
35+
request: RequestParameters,
36+
variables: Variables
37+
): Observable<GraphQLResponse> => {
38+
if (!request.text) throw new Error("Missing document.");
39+
const { text: operation, name } = request;
40+
41+
return Observable.create<GraphQLResponse>((sink) => {
42+
const source = makeAsyncIterableIteratorFromSink((sink) => {
43+
return client.subscribe<GraphQLResponse>(
44+
{ variables, query: operation },
45+
{
46+
next: sink.next.bind(sink),
47+
complete: sink.complete.bind(sink),
48+
error: sink.error.bind(sink),
49+
}
50+
);
51+
});
52+
53+
return applySourceToSink(source, sink);
54+
});
55+
};
56+
}

packages/todo-example/client-relay/src/index.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as React from "react";
22
import * as ReactDOM from "react-dom";
3-
import { createSocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
4-
import type { Environment, GraphQLResponse } from "relay-runtime";
3+
import type { Environment } from "relay-runtime";
54
import "todomvc-app-css/index.css";
65
import { TodoApplication } from "./TodoApplication";
76
import { createRelayEnvironment } from "./createRelayEnvironment";
@@ -25,6 +24,17 @@ const Root = () => {
2524
)
2625
);
2726
});
27+
} else if (params.get("ws")) {
28+
const host = params.get("host") ?? undefined;
29+
import("./fetcher/create-ws-fetcher").then(({ createWSFetcher }) => {
30+
setEnvironment(
31+
createRelayEnvironment(
32+
createWSFetcher(
33+
(host ?? `ws://${window.location.host}`) + "/graphql"
34+
)
35+
)
36+
);
37+
});
2838
} else {
2939
import("./fetcher/create-socket-io-fetcher").then(
3040
({ createSocketIOFetcher }) => {

packages/todo-example/client-urql/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
"name": "@n1ru4l/todo-example-client-urql",
33
"version": "0.1.0",
44
"private": true,
5-
"dependencies": {
6-
"urql": "2.2.2",
7-
"graphql": "16.0.0-experimental-stream-defer.5"
8-
},
95
"devDependencies": {
106
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
117
"@repeaterjs/repeater": "3.0.4",
@@ -24,7 +20,9 @@
2420
"react-dom": "17.0.2",
2521
"socket.io-client": "4.5.1",
2622
"todomvc-app-css": "2.4.2",
27-
"vite": "2.9.14"
23+
"vite": "2.9.14",
24+
"urql": "2.2.2",
25+
"graphql": "16.0.0-experimental-stream-defer.5"
2826
},
2927
"scripts": {
3028
"start": "vite",

packages/todo-example/client-urql/src/index.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ const Root = (): ReactElement | null => {
2121
)
2222
);
2323
});
24+
} else if (params.get("ws")) {
25+
let host = params.get("host") ?? undefined;
26+
import("./urql-client/ws-client").then(async ({ createUrqlClient }) => {
27+
setClient(
28+
createUrqlClient(
29+
(host ?? `ws://${window.location.host}`) + "/graphql"
30+
)
31+
);
32+
});
2433
} else {
2534
import("./urql-client/socket-io-client").then(
2635
async ({ createUrqlClient }) => {

packages/todo-example/client-urql/src/urql-client/http-client.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import {
88
import { getOperationAST } from "graphql";
99
import { isLiveQueryOperationDefinitionNode } from "@n1ru4l/graphql-live-query";
1010
import { Repeater } from "@repeaterjs/repeater";
11-
import { applyLiveQueryJSONPatch } from "@n1ru4l/graphql-live-query-patch-json-patch";
12-
import { applyAsyncIterableIteratorToSink } from "@n1ru4l/push-pull-async-iterable-iterator";
1311
import { ExecutionLivePatchResult } from "@n1ru4l/graphql-live-query-patch";
1412
import { applySourceToSink } from "./shared";
1513

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {
2+
Client,
3+
subscriptionExchange,
4+
fetchExchange,
5+
cacheExchange,
6+
dedupExchange,
7+
ExecutionResult,
8+
} from "urql";
9+
import { createClient } from "graphql-ws";
10+
import { applySourceToSink } from "./shared";
11+
import { makeAsyncIterableIteratorFromSink } from "@n1ru4l/push-pull-async-iterable-iterator";
12+
13+
export const createUrqlClient = (url: string) => {
14+
const client = createClient({ url });
15+
return new Client({
16+
url: "noop",
17+
exchanges: [
18+
cacheExchange,
19+
dedupExchange,
20+
subscriptionExchange({
21+
forwardSubscription(operation) {
22+
return {
23+
subscribe: (sink) => {
24+
const source = makeAsyncIterableIteratorFromSink((sink) => {
25+
return client.subscribe<ExecutionResult>(
26+
{ ...operation, query: operation.query },
27+
{
28+
next: sink.next.bind(sink),
29+
complete: sink.complete.bind(sink),
30+
error: sink.error.bind(sink),
31+
}
32+
);
33+
});
34+
35+
return {
36+
unsubscribe: applySourceToSink(source, sink),
37+
};
38+
},
39+
};
40+
},
41+
enableAllOperations: true,
42+
}),
43+
fetchExchange,
44+
],
45+
});
46+
};

0 commit comments

Comments
 (0)