Subscriptions-transport-ws: GraphQL Subscriptions Passing in GraphiQL but Failing in Jest/npm test?

Created on 21 Feb 2018  ·  1Comment  ·  Source: apollographql/subscriptions-transport-ws

I'm not sure if this is a bug, or if I am setting up my test incorrectly.

Environment

Tested on both Node v9.2.0 and Node v8.9.4.
Development machine is macOS Sierra 10.12.6 (16G1212), TravisCI is Ubuntu 14.04.5 LTS

// package.json
{
  "dependencies": {
    "apollo-server-express": "^1.3.2",
    "bcrypt": "^1.0.3",
    "body-parser": "^1.18.2",
    "cors": "^2.8.4",
    "crypto-js": "^3.1.9-1",
    "dataloader": "^1.4.0",
    "express": "^4.16.2",
    "graphql": "^0.13.1",
    "graphql-redis-subscriptions": "^1.4.0",
    "graphql-subscriptions": "^0.5.7",
    "graphql-tools": "^2.21.0",
    "jsonwebtoken": "^8.1.1",
    "mongodb": "^3.0.2",
    "nodemailer": "^4.4.2",
    "subscriptions-transport-ws": "^0.9.5"
  },
  "devDependencies": {
    "apollo-cache-inmemory": "^1.1.9",
    "apollo-client": "^2.2.5",
    "apollo-link": "^1.1.0",
    "apollo-link-http": "^1.3.3",
    "axios": "^0.18.0",
    "coveralls": "^3.0.0",
    "eslint": "^4.18.0",
    "graphql-tag": "^2.8.0",
    "jest": "^22.4.0",
    "jest-cli": "^22.4.0",
    "mockdate": "^2.0.2",
    "node-fetch": "^2.0.0",
    "ws": "^4.0.0"
  }
}

Background

I am trying to write some tests for my subscriptions. I have verified that the subscription works using GraphiQL, as well as with my React application that consumes the endpoint.

GraphiQL Verification
GraphiQL
https://giphy.com/gifs/ORUfxwVT3sS7ItFmwu (higher quality than gif)

Error

I can't seem to get this working for my integration tests.

I can verify that my subscription is connecting to the /subscriptions endpoint properly, because my code coverage analysis shows that the SubscriptionServer.onConnect method is being called when the failing subscription test is added. I don't see my subscription resolvers marked as having run though. (See the code coverage link at the bottom?)

Test Code

"use strict";

const { ApolloClient } = require("apollo-client");
const { InMemoryCache } = require("apollo-cache-inmemory");
const { ApolloLink } = require("apollo-link");
const { createHttpLink } = require("apollo-link-http");
const gql = require("graphql-tag");
const fetch = require("node-fetch");
const { SubscriptionClient } = require("subscriptions-transport-ws");
const WebSocket = require("ws");

const start = require("../../src/index");
const testHelper = require("../testhelper");
const { PORT } = require("../../src/constants");

const GRAPHQL_SUBSCRIPTIONS_ENDPOINT = `ws://localhost:${PORT}/subscriptions`;
const GRAPHQL_HTTP_ENDPOINT = `http://localhost:${PORT}/graphql`;

let server = null;
let networkInterface = null;
let client = null;

beforeAll(async done => {
  await testHelper.initializeTestState();
  const resolverUser = await testHelper.createTestUser({
    username: "subscriber",
    rawPassword: "supersecret123",
    email: "[email protected]"
  });

  const jwt = await testHelper.getJWT({
    rawPassword: "supersecret123",
    email: resolverUser.email
  });

  server = await start();
  networkInterface = new SubscriptionClient(
    GRAPHQL_SUBSCRIPTIONS_ENDPOINT,
    { reconnect: true, connectionParams: { authorization: jwt } },
    WebSocket
  );

  const httpLink = createHttpLink({ uri: GRAPHQL_HTTP_ENDPOINT, fetch });
  const middlewareLink = new ApolloLink((operation, forward) => {
    operation.setContext({ headers: { authorization: jwt } });
    return forward(operation);
  });
  const link = middlewareLink.concat(httpLink);

  client = new ApolloClient({
    networkInterface,
    link,
    cache: new InMemoryCache()
  });
  done();
});

afterAll(async done => {
  await networkInterface.close();
  await server.close();
  await testHelper.tearDownTestState(true);
  done();
});

describe("Subscriptions", () => {
  it("should subscribe to node creations", async done => {
    const subscriptionPromise = new Promise((resolve, reject) => {
      client
        .subscribe({
          query: gql`
            subscription AllNodesSubcription {
              NodeSubscription(filter: { mutation_in: [CREATED] }) {
                mutation
                node {
                  title
                }
              }
            }
          `
        })
        .subscribe({
          next: resolve,
          error: reject
        });
    });

    await client.mutate({
      mutation: gql`
        mutation createNode(
          $dataType: NodeDataType!
          $relationType: NodeRelationType!
          $title: String!
          $content: String!
          $parentId: ID
        ) {
          createNode(
            dataType: $dataType
            relationType: $relationType
            title: $title
            content: $content
            parentId: $parentId
          ) {
            title
          }
        }
      `,
      variables: {
        dataType: "TEXT",
        relationType: "POST",
        title: "Test Create Node Resolver",
        content: "Test Create Node Resolver Content String!"
      }
    });
    expect(await subscriptionPromise).toEqual({
      data: {
        NodeSubscription: {
          mutation: "CREATED",
          node: {
            title: "Test Create Node Resolver"
          }
        }
      }
    });
    done();
  });
});

Failure Message

FAIL __test__/schema/subscriptions.test.js
  Subscriptions
    ✕ should subscribe to node creations (75ms)
  ● Subscriptions › should subscribe to node creations
    expect(received).toEqual(expected)

    Expected value to equal:
      {"data": {"NodeSubscription": {"mutation": "CREATED", "node": {"title": "Test Create Node Resolver"}}}}
    Received:
      {"data": {"NodeSubscription": null}}

    Difference:

    - Expected
    + Received

      Object {
        "data": Object {
    -     "NodeSubscription": Object {
    -       "mutation": "CREATED",
    -       "node": Object {
    -         "title": "Test Create Node Resolver",
    +     "NodeSubscription": null,
        },
    -     },
    -   },
      }
      127 |       }
      128 |     });
    > 129 |     expect(await subscriptionPromise).toEqual({
      130 |       data: {
      131 |         NodeSubscription: {
      132 |           mutation: "CREATED",

      at Object.it (__test__/schema/subscriptions.test.js:129:39)

Links

Most helpful comment

Did you ever find the issue? I am trying the same thing, but cant get my subscriotion working in my jest test.

Update

I found the solution:
I think the problem is that at the time when you post the mutation, the subscription is not established yet. So you need to put in a timeout (I have 100ms) before you send the mutation.

>All comments

Did you ever find the issue? I am trying the same thing, but cant get my subscriotion working in my jest test.

Update

I found the solution:
I think the problem is that at the time when you post the mutation, the subscription is not established yet. So you need to put in a timeout (I have 100ms) before you send the mutation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

damour picture damour  ·  3Comments

PetrSnobelt picture PetrSnobelt  ·  3Comments

mjasnikovs picture mjasnikovs  ·  5Comments

anilanar picture anilanar  ·  5Comments

booboothefool picture booboothefool  ·  4Comments