On this Stackblitz Project there is a very simple Node.js + GraphQL Yoga
server with one simple subscription: messageEvent
and one simple mutation: sendMessage
…
The server is currently working as expected:
- Run the subscription in: https://githubhhdwqxbs2mnr-yjsn–4000–41fbae16.local-credentialless.webcontainer.io/graphql?query=subscription+MySubscription+%7B%0A++messageEvent+%7B%0A++++content%0A++++sender%0A++%7D%0A%7D
- Run the mutation in: https://githubhhdwqxbs2mnr-yjsn–4000–41fbae16.local-credentialless.webcontainer.io/graphql?query=mutation+MyMutation+%7B%0A++sendMessage%28%0A++++content%3A+%22Hi+there%21%22%2C%0A++++sender%3A+%22Bill+Gates%22%0A++%29%0A%7D
- Check the subscription receives the message from the mutation
On file: /src/__tests__/sendMessage.test.ts
there is unit test that can be executed with command: $ yarn test
.
You can do all these experiments online with Stackblitz (browsers + terminals).
Here is the content of file: /src/__tests__/sendMessage.test.ts
:
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { YogaLink } from '@graphql-yoga/apollo-link';
import fetch from 'cross-fetch';
import gql from 'graphql-tag';
const httpUri = `http://localhost:${process.env.VITE_PORT}/graphql`;
describe('Mutations', () => {
it('A user sends a message; another user listening for new messages receives the message.', async () => {
let client1: ApolloClient<any> | null = null;
let client2: ApolloClient<any> | null = null;
let subscription: ZenObservable.Subscription | null = null;
// let subscriptionSuccess = false;
const messageContent = 'Hello World!';
const messageSender = 'Bill Gates';
try {
// for performing the mutation
client1 = new ApolloClient({
link: new HttpLink({
uri: httpUri,
fetch,
}),
cache: new InMemoryCache(),
});
// for listening to the subscription
client2 = new ApolloClient({
link: new YogaLink({
endpoint: httpUri,
}),
cache: new InMemoryCache(),
});
const observer = client2.subscribe({
query: gql`
subscription messageSubscription {
messageEvent {
content
sender
}
}
`,
});
subscription = observer.subscribe({
next(response) {
// we need to make sure we are receiving the correct message
expect(response.data.messageEvent.content).toBe(messageContent);
expect(response.data.messageEvent.sender).toBe(messageSender);
// subscriptionSuccess = true;
},
});
const {
data: { sendMessage },
} = await client1.mutate({
mutation: gql`
mutation sendMessage($content: String!, $sender: String!) {
sendMessage(content: $content, sender: $sender)
}
`,
variables: {
content: messageContent,
sender: messageSender,
},
});
// prettier-ignore
expect(sendMessage).toBe(`Received: "${messageContent}" from "${messageSender}".`);
// @todo: make sure the subscription is successful
// expect(subscriptionSuccess).toBe(true);
/**
* @todo: make sure the process finishes and doesn't hang forever when running:
* $ yarn test
*/
} finally {
if (subscription) {
subscription.unsubscribe();
}
if (client1) {
client1.stop();
client1 = null;
}
if (client2) {
client2.stop();
client2 = null;
}
}
});
});
My Problem: that test /src/__tests__/sendMessage.test.ts
has 2 issues:
- the Jest process is currently hanging. As you can see on the screenshot above (bottom right panel), there is a yellow message stating: “Jest did not exit one second after the test run has completed. ‘This usually means that there are asynchronous operations that weren’t stopped in your tests. Consider running Jest with –detectOpenHandles to troubleshoot this issue.”
- but if you use option: “–detectOpenHandles” you don’t actually get any hints.
- the unit test should validate the data received in the subscription callback (inside:
observer.subscribe(...)
). Wondering how we could integrate that validation to the unit test. The lines related to variable:subscriptionSuccess
should be uncommented.
If you have any solution for this, please fork the provided Stackblitz Project, add your solution to it and post your link back in the comments.
Thanks in advance.