Skip to content

Commit

Permalink
feat: add ws example tests
Browse files Browse the repository at this point in the history
  • Loading branch information
n1ru4l committed Jul 30, 2022
1 parent 8e3d221 commit 1253659
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 116 deletions.
19 changes: 9 additions & 10 deletions packages/todo-example/client-apollo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,6 @@
"name": "@n1ru4l/todo-example-client-apollo",
"version": "0.1.0",
"private": true,
"dependencies": {
"@apollo/client": "3.6.9",
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
"@n1ru4l/push-pull-async-iterable-iterator": "3.2.0",
"@n1ru4l/socket-io-graphql-client": "*",
"@repeaterjs/repeater": "3.0.4",
"@app/gql": "link:./src/gql",
"graphql": "16.0.0-experimental-stream-defer.5"
},
"devDependencies": {
"@graphql-codegen/cli": "2.8.0",
"@graphql-codegen/gql-tag-operations-preset": "1.5.1",
Expand All @@ -25,7 +16,15 @@
"react-dom": "17.0.2",
"socket.io-client": "4.5.1",
"todomvc-app-css": "2.4.2",
"vite": "2.9.14"
"vite": "2.9.14",
"@apollo/client": "3.6.9",
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
"@n1ru4l/push-pull-async-iterable-iterator": "3.2.0",
"@n1ru4l/socket-io-graphql-client": "*",
"@repeaterjs/repeater": "3.0.4",
"@app/gql": "link:./src/gql",
"graphql": "16.0.0-experimental-stream-defer.5",
"graphql-ws": "5.9.1"
},
"scripts": {
"start": "vite",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// for Apollo Client v3 older than v3.5.10:
import {
ApolloLink,
Operation,
FetchResult,
Observable,
} from "@apollo/client/core";
import { print } from "graphql";
import { createClient, Client } from "graphql-ws";
import { makeAsyncIterableIteratorFromSink } from "@n1ru4l/push-pull-async-iterable-iterator";
import { applySourceToSink } from "./shared";

class GraphQLWsLink extends ApolloLink {
private client: Client;
constructor(url: string) {
super();
this.client = createClient({
url,
});
}

public request(operation: Operation): Observable<FetchResult> {
return new Observable((sink) => {
const source = makeAsyncIterableIteratorFromSink((sink) => {
return this.client.subscribe<FetchResult>(
{ ...operation, query: print(operation.query) },
{
next: sink.next.bind(sink),
complete: sink.complete.bind(sink),
error: sink.error.bind(sink),
}
);
});

return applySourceToSink(source, sink);
});
}
}

export function createWSApolloLink(url: string) {
return new GraphQLWsLink(url);
}
13 changes: 13 additions & 0 deletions packages/todo-example/client-apollo/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ const Root = (): React.ReactElement | null => {
);
}
);
} else if (params.get("ws")) {
let host = params.get("host") ?? undefined;
import("./apollo-link/create-ws-apollo-link").then(
async ({ createWSApolloLink }) => {
setClient(
createApolloClient(
createWSApolloLink(
(host ?? `ws://${window.location.host}`) + "/graphql"
)
)
);
}
);
} else {
import("./apollo-link/create-socket-io-apollo-link").then(
async ({ createSocketIOApolloLink }) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/todo-example/client-relay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"todomvc-app-css": "2.4.2",
"classnames": "2.3.1",
"vite": "2.9.14",
"vite-plugin-babel-macros": "1.0.6"
"vite-plugin-babel-macros": "1.0.6",
"graphql-ws": "5.9.1"
},
"scripts": {
"start": "vite",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
GraphQLResponse,
Observable,
RequestParameters,
Variables,
} from "relay-runtime";
import { createClient } from "graphql-ws";
import { Repeater } from "@repeaterjs/repeater";
import { applySourceToSink } from "./shared";
import { makeAsyncIterableIteratorFromSink } from "@n1ru4l/push-pull-async-iterable-iterator";

function makeEventStreamSource(url: string) {
return new Repeater<GraphQLResponse>(async (push, end) => {
const eventsource = new EventSource(url);
eventsource.onmessage = function (event) {
const data = JSON.parse(event.data);
push(data);
if (eventsource.readyState === 2) {
end();
}
};
eventsource.onerror = function (event) {
console.log("Error", event);
end(new Error("Check the console bruv."));
};
await end;

eventsource.close();
});
}

export function createWSFetcher(url: string) {
const client = createClient({ url });
return (
request: RequestParameters,
variables: Variables
): Observable<GraphQLResponse> => {
if (!request.text) throw new Error("Missing document.");
const { text: operation, name } = request;

return Observable.create<GraphQLResponse>((sink) => {
const source = makeAsyncIterableIteratorFromSink((sink) => {
return client.subscribe<GraphQLResponse>(
{ variables, query: operation },
{
next: sink.next.bind(sink),
complete: sink.complete.bind(sink),
error: sink.error.bind(sink),
}
);
});

return applySourceToSink(source, sink);
});
};
}
14 changes: 12 additions & 2 deletions packages/todo-example/client-relay/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import { createSocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
import type { Environment, GraphQLResponse } from "relay-runtime";
import type { Environment } from "relay-runtime";
import "todomvc-app-css/index.css";
import { TodoApplication } from "./TodoApplication";
import { createRelayEnvironment } from "./createRelayEnvironment";
Expand All @@ -25,6 +24,17 @@ const Root = () => {
)
);
});
} else if (params.get("ws")) {
const host = params.get("host") ?? undefined;
import("./fetcher/create-ws-fetcher").then(({ createWSFetcher }) => {
setEnvironment(
createRelayEnvironment(
createWSFetcher(
(host ?? `ws://${window.location.host}`) + "/graphql"
)
)
);
});
} else {
import("./fetcher/create-socket-io-fetcher").then(
({ createSocketIOFetcher }) => {
Expand Down
8 changes: 3 additions & 5 deletions packages/todo-example/client-urql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
"name": "@n1ru4l/todo-example-client-urql",
"version": "0.1.0",
"private": true,
"dependencies": {
"urql": "2.2.2",
"graphql": "16.0.0-experimental-stream-defer.5"
},
"devDependencies": {
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
"@repeaterjs/repeater": "3.0.4",
Expand All @@ -24,7 +20,9 @@
"react-dom": "17.0.2",
"socket.io-client": "4.5.1",
"todomvc-app-css": "2.4.2",
"vite": "2.9.14"
"vite": "2.9.14",
"urql": "2.2.2",
"graphql": "16.0.0-experimental-stream-defer.5"
},
"scripts": {
"start": "vite",
Expand Down
9 changes: 9 additions & 0 deletions packages/todo-example/client-urql/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ const Root = (): ReactElement | null => {
)
);
});
} else if (params.get("ws")) {
let host = params.get("host") ?? undefined;
import("./urql-client/ws-client").then(async ({ createUrqlClient }) => {
setClient(
createUrqlClient(
(host ?? `ws://${window.location.host}`) + "/graphql"
)
);
});
} else {
import("./urql-client/socket-io-client").then(
async ({ createUrqlClient }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import {
import { getOperationAST } from "graphql";
import { isLiveQueryOperationDefinitionNode } from "@n1ru4l/graphql-live-query";
import { Repeater } from "@repeaterjs/repeater";
import { applyLiveQueryJSONPatch } from "@n1ru4l/graphql-live-query-patch-json-patch";
import { applyAsyncIterableIteratorToSink } from "@n1ru4l/push-pull-async-iterable-iterator";
import { ExecutionLivePatchResult } from "@n1ru4l/graphql-live-query-patch";
import { applySourceToSink } from "./shared";

Expand Down
46 changes: 46 additions & 0 deletions packages/todo-example/client-urql/src/urql-client/ws-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
Client,
subscriptionExchange,
fetchExchange,
cacheExchange,
dedupExchange,
ExecutionResult,
} from "urql";
import { createClient } from "graphql-ws";
import { applySourceToSink } from "./shared";
import { makeAsyncIterableIteratorFromSink } from "@n1ru4l/push-pull-async-iterable-iterator";

export const createUrqlClient = (url: string) => {
const client = createClient({ url });
return new Client({
url: "noop",
exchanges: [
cacheExchange,
dedupExchange,
subscriptionExchange({
forwardSubscription(operation) {
return {
subscribe: (sink) => {
const source = makeAsyncIterableIteratorFromSink((sink) => {
return client.subscribe<ExecutionResult>(
{ ...operation, query: operation.query },
{
next: sink.next.bind(sink),
complete: sink.complete.bind(sink),
error: sink.error.bind(sink),
}
);
});

return {
unsubscribe: applySourceToSink(source, sink),
};
},
};
},
enableAllOperations: true,
}),
fetchExchange,
],
});
};
9 changes: 7 additions & 2 deletions packages/todo-example/end2end-tests/end2end.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fastifyStatic from "fastify-static";
import { createServer as createSocketIOServer } from "../server-socket-io/src/index.js";
import { createServer as createHTTPServer } from "../server-helix/src/main.js";
import { createServer as createYogaServer } from "../server-yoga/src/main.js";
import { createServer as createWSServer } from "../server-ws/src/main.js";

import * as path from "path";

Expand All @@ -17,9 +18,13 @@ describe.each([
["GraphQL over Socket.io", "socket.io", createSocketIOServer],
["GraphQL over SSE (Helix)", "sse", createHTTPServer],
["GraphQL over SSE (Yoga)", "sse", createYogaServer],
["GraphQL over WebSocket (graphql-ws)", "ws", createWSServer],
])("%s", (_, protocol, createServer) => {
const apiPort = 6167;
const apiAddress = `http://localhost:${apiPort}`;
const apiAddress =
protocol !== "ws"
? `http://localhost:${apiPort}`
: `ws://localhost:${apiPort}`;
const staticPort = 6168;

const testPage = `http://localhost:${staticPort}?${protocol}=true&host=${encodeURIComponent(
Expand Down Expand Up @@ -93,7 +98,7 @@ describe.each([
).map((element: any) => element.innerHTML);
});
expect(todos).toEqual(["foo", "Do the laundry"]);
});
}, 100_000);

it("can complete a todo", async () => {
page = await browser.newPage();
Expand Down
46 changes: 2 additions & 44 deletions packages/todo-example/server-ws/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "0.1.2",
"private": true,
"dependencies": {
"@n1ru4l/in-memory-live-query-store": "*",
"@n1ru4l/socket-io-graphql-server": "*",
"@n1ru4l/in-memory-live-query-store": "0.10.0",
"@n1ru4l/graphql-live-query-patch-jsondiffpatch": "0.8.0",
"graphql": "16.0.0-experimental-stream-defer.5",
"graphql-ws": "5.9.1",
"ws": "8.8.0"
Expand All @@ -19,47 +19,5 @@
"write:schema": "ts-node scripts/write-graphql-schema.ts",
"build": "tsc",
"start": "ts-node-dev src/main.ts"
},
"type": "module",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"typings": "dist/typings/index.d.ts",
"typescript": {
"definition": "dist/typings/index.d.ts"
},
"exports": {
".": {
"require": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/cjs/index.js"
},
"import": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
},
"default": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
}
},
"./*": {
"require": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/cjs/*.js"
},
"import": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
},
"default": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
}
},
"./package.json": "./package.json"
},
"publishConfig": {
"directory": "dist",
"access": "public"
}
}
Loading

0 comments on commit 1253659

Please sign in to comment.