supertest-graphql
Version:
Extends supertest to test a GraphQL endpoint
301 lines (300 loc) • 11.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const apollo_server_express_1 = require("apollo-server-express");
const express_1 = __importDefault(require("express"));
const http_1 = require("http");
const subscriptions_transport_ws_1 = require("subscriptions-transport-ws");
const ws_1 = require("graphql-ws/lib/use/ws");
const graphql_1 = require("graphql");
const schema_1 = require("@graphql-tools/schema");
const graphql_subscriptions_1 = require("graphql-subscriptions");
const delay_1 = __importDefault(require("delay"));
const _1 = __importStar(require("./"));
const ws_2 = require("ws");
const typeDefs = (0, apollo_server_express_1.gql) `
type Query {
hi(name: String): String!
}
type Mutation {
do: String!
}
type Subscription {
onHi(name: String): String!
}
`;
let server;
let queryHiResolver;
let mutationDoResolver;
const pubsub = new graphql_subscriptions_1.PubSub();
const initTestServer = ({ graphqlPath = "/graphql", wsProtocol = "graphql-transport-ws", } = {}) => __awaiter(void 0, void 0, void 0, function* () {
const app = (0, express_1.default)();
const httpServer = (0, http_1.createServer)(app);
queryHiResolver = jest.fn((_, { name = "" }) => `hi ${name}!`);
mutationDoResolver = jest.fn(() => "done!");
const schema = (0, schema_1.makeExecutableSchema)({
typeDefs,
resolvers: {
Query: {
hi: queryHiResolver,
},
Mutation: {
do: mutationDoResolver,
},
Subscription: {
onHi: {
subscribe: () => pubsub.asyncIterator(["ON_HI"]),
resolve: (_, { name }) => {
return `Hi ${name ? name : "unknown"}`;
},
},
},
},
});
let closeWsMobile;
if (wsProtocol === "graphql-ws") {
const subscriptionServer = subscriptions_transport_ws_1.SubscriptionServer.create({
schema,
execute: graphql_1.execute,
subscribe: graphql_1.subscribe,
}, {
server: httpServer,
});
closeWsMobile = () => __awaiter(void 0, void 0, void 0, function* () { return subscriptionServer.close(); });
}
else {
const server = new ws_2.WebSocketServer({
server: httpServer,
path: graphqlPath,
});
const serverCleanup = (0, ws_1.useServer)({ schema }, server);
closeWsMobile = () => __awaiter(void 0, void 0, void 0, function* () { return yield serverCleanup.dispose(); });
}
const server = new apollo_server_express_1.ApolloServer({
schema,
context: (c) => c,
plugins: [
{
serverWillStart() {
return __awaiter(this, void 0, void 0, function* () {
return {
drainServer() {
return __awaiter(this, void 0, void 0, function* () {
closeWsMobile();
});
},
};
});
},
},
],
});
yield server.start();
server.applyMiddleware({ app, path: graphqlPath });
return httpServer;
});
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
server = yield initTestServer();
}));
describe(".query()", () => {
test("it queries", () => __awaiter(void 0, void 0, void 0, function* () {
const { data } = yield (0, _1.default)(server).query((0, apollo_server_express_1.gql) `
query {
hi
}
`);
expect(data === null || data === void 0 ? void 0 : data.hi).toBe("hi !");
}));
describe("with variables", () => {
test("it queries", () => __awaiter(void 0, void 0, void 0, function* () {
const { data } = yield (0, _1.default)(server).query((0, apollo_server_express_1.gql) `
query Greetings($name: String!) {
hi(name: $name)
}
`, { name: "Alex" });
expect(data === null || data === void 0 ? void 0 : data.hi).toBe("hi Alex!");
}));
});
describe("with errors in return", () => {
it("should make them available", () => __awaiter(void 0, void 0, void 0, function* () {
queryHiResolver.mockImplementation(() => {
throw new Error("Bad");
});
const { errors } = yield (0, _1.default)(server).query((0, apollo_server_express_1.gql) `
query {
hi
}
`);
expect(errors).toBeDefined();
expect(errors).toHaveLength(1);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(errors[0].message).toEqual("Bad");
}));
});
});
describe(".mutate()", () => {
test("it mutates", () => __awaiter(void 0, void 0, void 0, function* () {
const { data } = yield (0, _1.default)(server).query((0, apollo_server_express_1.gql) `
mutation {
do
}
`);
expect(data === null || data === void 0 ? void 0 : data.do).toBe("done!");
}));
});
describe(".variables()", () => {
test("it queries with variables", () => __awaiter(void 0, void 0, void 0, function* () {
const { data } = yield (0, _1.default)(server)
.query((0, apollo_server_express_1.gql) `
query Greetings($name: String!) {
hi(name: $name)
}
`)
.variables({ name: "Alex" });
expect(data === null || data === void 0 ? void 0 : data.hi).toBe("hi Alex!");
}));
});
describe(".path()", () => {
it("changes the path to query graphql", () => __awaiter(void 0, void 0, void 0, function* () {
server = yield initTestServer({
graphqlPath: "/specialUrl",
});
const { data } = yield (0, _1.default)(server)
.path("/specialUrl")
.query((0, apollo_server_express_1.gql) `
query Greetings($name: String!) {
hi(name: $name)
}
`)
.variables({ name: "Alex" });
expect(data === null || data === void 0 ? void 0 : data.hi).toBe("hi Alex!");
}));
});
describe(".set()", () => {
test("it properly set headers", () => __awaiter(void 0, void 0, void 0, function* () {
yield (0, _1.default)(server)
.set("authorization", "bar")
.query((0, apollo_server_express_1.gql) `
query {
hi
}
`);
expect(queryHiResolver).toHaveBeenCalled();
const { req } = queryHiResolver.mock.calls[0][2];
expect(req.headers["authorization"]).toEqual("bar");
}));
});
describe(".auth()", () => {
test("it properly set basic headers", () => __awaiter(void 0, void 0, void 0, function* () {
yield (0, _1.default)(server)
.auth("username", "password")
.query((0, apollo_server_express_1.gql) `
query {
hi
}
`);
expect(queryHiResolver).toHaveBeenCalled();
const { req } = queryHiResolver.mock.calls[0][2];
expect(req.headers["authorization"]).toEqual("Basic dXNlcm5hbWU6cGFzc3dvcmQ=");
}));
});
describe(".expectNoErrors()", () => {
it("when there is an error it should throw", () => __awaiter(void 0, void 0, void 0, function* () {
queryHiResolver.mockImplementation(() => {
throw new Error("Bad");
});
return expect((0, _1.default)(server)
.query((0, apollo_server_express_1.gql) `
query {
hi
}
`)
.expectNoErrors()).rejects.toThrow("expected no errors but got 1 error(s) in GraphQL response: Bad");
}));
it("when there is no error it should not throw", () => __awaiter(void 0, void 0, void 0, function* () {
return expect((0, _1.default)(server)
.query((0, apollo_server_express_1.gql) `
query {
hi
}
`)
.expectNoErrors()).resolves.not.toThrow();
}));
});
describe("test ws legacy", () => {
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
server = yield initTestServer({ wsProtocol: "graphql-ws" });
yield new Promise((res) => server.listen(0, "localhost", () => res()));
}));
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
yield _1.supertestWs.end();
server.close();
}));
it("should work", () => __awaiter(void 0, void 0, void 0, function* () {
const sub = yield (0, _1.supertestWs)(server).protocol(_1.LEGACY_WEBSOCKET_PROTOCOL)
.subscribe((0, apollo_server_express_1.gql) `
subscription {
onHi
}
`);
// there is no wayt to know if the subscription is active,
// to avoid race conditions we need to wait a bit
yield (0, delay_1.default)(200);
pubsub.publish("ON_HI", {});
const res = yield sub.next().expectNoErrors();
expect(res.data).toEqual({ onHi: "Hi unknown" });
}));
});
describe("test ws", () => {
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
server = yield initTestServer();
yield new Promise((res) => server.listen(0, "localhost", () => res()));
}));
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
yield _1.supertestWs.end();
server.close();
}));
it("should work", () => __awaiter(void 0, void 0, void 0, function* () {
const sub = yield (0, _1.supertestWs)(server).subscribe((0, apollo_server_express_1.gql) `
subscription {
onHi
}
`);
// there is no wayt to know if the subscription is active,
// to avoid race conditions we need to wait a bit
yield (0, delay_1.default)(200);
pubsub.publish("ON_HI", {});
const res = yield sub.next().expectNoErrors();
expect(res.data).toEqual({ onHi: "Hi unknown" });
}));
});