Last active
November 8, 2023 04:22
-
-
Save patrixr/2536ee396d488bd5e38b0278513eefeb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// E2E Test Setup | |
// e2e_helpers.js | |
// | |
import { getMainDefinition } from '@apollo/client/utilities' | |
import { AuthPayload } from '../../lib/typings/goodchat' | |
import { WebSocketLink } from '@apollo/client/link/ws' | |
import { promisify } from 'util' | |
import fetch from 'cross-fetch' | |
import http from 'http' | |
import _ from "lodash" | |
import ws from 'ws' | |
import koa from 'koa' | |
import { | |
split, | |
HttpLink, | |
ApolloClient, | |
InMemoryCache, | |
DocumentNode, | |
SubscriptionOptions | |
} from '@apollo/client/core' | |
let server : http.Server | |
let url : string | |
let port : number | |
let host = '127.0.0.1' | |
export type TestServerInfo = { | |
port: number | |
host: string | |
} | |
export async function bootTestServer() : Promise<TestServerInfo> { | |
// @TODO: Start up your test server here | |
return { | |
host: '127.0.0.1', | |
port: 3000 // or whichever port you're using | |
} | |
} | |
export async function teardownTestServer() { | |
// @TODO: Shutdown your test server | |
} | |
/** | |
* Our test apollo client <3 | |
* | |
* @export | |
* @class TestApolloClient | |
* @extends {ApolloClient<any>} | |
*/ | |
export class TestApolloClient extends ApolloClient<any> { | |
private wsLink : WebSocketLink | |
constructor(serverInfo: TestServerInfo) { | |
const { url, host } = serverInfo; | |
const wsLink = new WebSocketLink({ | |
// @TODO: Update WS url | |
uri: `ws://${host}:${port}/graphql/subscriptions`, | |
webSocketImpl: ws, | |
options: { | |
reconnect: false, | |
connectionParams: { | |
'Authorization': 'Bearer dummy' | |
} | |
} | |
}); | |
const httpLink = new HttpLink({ | |
// @TODO: update HTTP url | |
uri: `http://${host}:${port}/graphql`, | |
fetch | |
}); | |
const splitLink = split( | |
({ query }) => { | |
const definition = getMainDefinition(query); | |
return ( | |
definition.kind === 'OperationDefinition' && | |
definition.operation === 'subscription' | |
); | |
}, | |
wsLink, | |
httpLink, | |
); | |
super({ | |
link: splitLink, | |
cache: new InMemoryCache() | |
}); | |
this.wsLink = wsLink | |
} | |
stop() { | |
super.stop(); | |
// | |
// This is important, or else your test session will never close. | |
// Also the reason it inherits from ApolloClient instead of just creating it | |
// That way we can sneak in that WS closing | |
// | |
(this.wsLink as any).subscriptionClient.close(); | |
} | |
} | |
// | |
// | |
// A very rough helper for testing subscription | |
// | |
// @TODO: look into finding better alternatives | |
// | |
// | |
type SubscriptionTestParams = { | |
client: TestApolloClient, | |
query: DocumentNode, | |
variables?: SubscriptionOptions | |
} | |
type WaitCondition = () => boolean | |
/** | |
* Helper to create a subscription with a bunch of handy methods | |
* | |
* @export | |
* @param {SubscriptionTestParams} params | |
* @returns | |
*/ | |
export function createSubscription(params: SubscriptionTestParams) { | |
const results : any[] = []; | |
let error : any; | |
let observer = params.client.subscribe({ | |
errorPolicy: 'all', | |
query: params.query, | |
variables: params.variables || {} | |
}).subscribe({ | |
next(data) { results.push(data) }, | |
error: (err) => { error = err } | |
}) | |
return { | |
results, | |
observer, | |
disconnect() { | |
observer.unsubscribe(); | |
}, | |
wait(ms : number = 100) { | |
return new Promise(done => { | |
setTimeout(() => { done(null) }, ms); | |
}); | |
}, | |
waitForResults(opts : { len?: number, timeout?: number } = {}) { | |
return new Promise((done, fail) => { | |
let step = 2; | |
let sum = 0; | |
let timeout = opts.timeout ?? 30; | |
let len = opts.len ?? 1; | |
const interval = setInterval(() => { | |
if (!error && results.length >= len) { | |
clearInterval(interval); | |
return done(results); | |
} | |
if (error || sum >= timeout) { | |
error = error || new Error( | |
`Timeout: subscription did not receive the expected results after ${timeout}ms` | |
) | |
clearInterval(interval); | |
return fail(error); | |
} | |
sum += step | |
}, step); | |
}) | |
}, | |
get triggerCount() { | |
return results.length; | |
}, | |
get error () { | |
return error; | |
} | |
} | |
} | |
// | |
// A TEST EXAMPLE ! | |
// | |
import * as e2e from './e2e_helpers' | |
import { gql } from "apollo-server-core" | |
describe('Subscription Test', () => { | |
let serverInfo : e2e.TestServerInfo; | |
let gqlClient : e2e.TestApolloClient; | |
before(() => { | |
serverInfo = await e2e.bootTestServer(); | |
}) | |
after(async () => { | |
await e2e.teardownTestServer(); | |
}) | |
beforeEach(async () => { | |
gqlClient = new TestApolloClient(serverInfo); | |
}); | |
afterEach(() => gqlClient.stop()) | |
it('receives data !', async () => { | |
const sub = e2e.createSubscription({ | |
client: gqlClient, | |
query: gql` | |
subscription newMessages { | |
messageEvent { | |
message { | |
id | |
content | |
conversationId | |
} | |
} | |
} | |
` | |
}); | |
const message = await db.createMessage(); // Something that would trigger subscription event | |
await sub.waitForResults(); | |
expect(sub.results).to.be.of.length(1); // Check for success | |
sub.disconnect(); // unsubscribe | |
}) | |
}) | |
oh! Okay, Thanks for clearing out. Do you also have written unit tests before for subscription?
for apollo v4 - it should now be
const wsLink = new GraphQLWsLink(
createClient({
url: `ws://${host}:${port}/`,
connectionParams: {
Authorization: "Bearer xxx",
},
webSocketImpl: WebSocket,
})
);
thank you for this!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@saurav-bhagat This is an end-to-end test. Meaning it runs your server on the machine, and uses a POST to call it.
Notice the
// @TODO: Start up your test server here
You can just boot up your own server (most people use express+apollo server). This gist just shows how to E2E test against your own server