diff --git a/lib/subscription-connection.js b/lib/subscription-connection.js index 330dd9a0..163700d4 100644 --- a/lib/subscription-connection.js +++ b/lib/subscription-connection.js @@ -197,7 +197,7 @@ module.exports = class SubscriptionConnection { pubsub: sc, lruGatewayResolvers: this.lruGatewayResolvers, reply: { - [kLoaders]: subscriptionLoaders && subscriptionLoaders.create(), + [kLoaders]: subscriptionLoaders && subscriptionLoaders.create(context), [kEntityResolvers]: this.entityResolvers, request: { headers: {} } } diff --git a/test/subscription.js b/test/subscription.js index 4da97030..0841f2b7 100644 --- a/test/subscription.js +++ b/test/subscription.js @@ -1876,3 +1876,176 @@ test('subscription server works with fastify-websocket', t => { })) }) }) + +test('subscription passes context to its loaders', t => { + const app = Fastify() + t.teardown(async () => { + await app.close() + }) + + const sendTestMutation = () => { + app.inject({ + method: 'POST', + url: '/graphql', + body: { + query: ` + mutation { + addNotification(message: "Hello World") { + id + } + } + ` + } + }, () => {}) + } + + const emitter = mq() + const schema = ` + type Notification { + id: ID! + message: String + } + + type Query { + notifications: [Notification] + } + + type Mutation { + addNotification(message: String): Notification + } + + type Subscription { + notificationAdded: Notification + } + ` + + let idCount = 1 + const notifications = [{ + id: idCount, + message: 'Notification message' + }] + + const loaders = { + Notification: { + message: async (queries, context) => { + t.ok(context, 'context is not missing') + const { username } = context + return queries.map(({ obj }) => `${obj.message} ${username}`) + } + } + } + + const resolvers = { + Query: { + notifications: () => notifications + }, + Mutation: { + addNotification: async (_, { message }) => { + const id = idCount++ + const notification = { + id, + message + } + notifications.push(notification) + await emitter.emit({ + topic: 'NOTIFICATION_ADDED', + payload: { + notificationAdded: notification + } + }) + + return notification + } + }, + Subscription: { + notificationAdded: { + subscribe: (root, args, { pubsub, topic }) => pubsub.subscribe(topic) + } + } + } + + app.register(GQL, { + schema, + resolvers, + loaders, + subscription: { + emitter, + context: () => ({ + topic: 'NOTIFICATION_ADDED', + username: 'foobar' + }) + } + }) + + app.listen(0, err => { + t.error(err) + + const ws = new WebSocket('ws://localhost:' + (app.server.address()).port + '/graphql', 'graphql-ws') + const client = WebSocket.createWebSocketStream(ws, { encoding: 'utf8', objectMode: true }) + t.teardown(client.destroy.bind(client)) + client.setEncoding('utf8') + + client.write(JSON.stringify({ + type: 'connection_init' + })) + + client.write(JSON.stringify({ + id: 1, + type: 'start', + payload: { + query: ` + subscription { + notificationAdded { + id + message + } + } + ` + } + })) + + client.write(JSON.stringify({ + id: 2, + type: 'start', + payload: { + query: ` + subscription { + notificationAdded { + id + message + } + } + ` + } + })) + + client.write(JSON.stringify({ + id: 2, + type: 'stop' + })) + + client.on('data', chunk => { + const data = JSON.parse(chunk) + + if (data.id === 1 && data.type === 'data') { + t.equal(chunk, JSON.stringify({ + type: 'data', + id: 1, + payload: { + data: { + notificationAdded: { + id: '1', + message: 'Hello World foobar' + } + } + } + })) + + client.end() + t.end() + } else if (data.id === 2 && data.type === 'complete') { + sendTestMutation() + } + }) + }) +})