UNPKG

mockttp

Version:

Mock HTTP server for testing HTTP clients and stubbing webservices

159 lines 7.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildAdminServerModel = buildAdminServerModel; const _ = require("lodash"); const graphql_subscriptions_1 = require("graphql-subscriptions"); const util_1 = require("@httptoolkit/util"); const rule_deserialization_1 = require("../rules/rule-deserialization"); const request_utils_1 = require("../util/request-utils"); const graphqlSubscriptionPairs = Object.entries({ 'requestInitiated': 'request-initiated', 'requestReceived': 'request', 'responseCompleted': 'response', 'webSocketRequest': 'websocket-request', 'webSocketAccepted': 'websocket-accepted', 'webSocketMessageReceived': 'websocket-message-received', 'webSocketMessageSent': 'websocket-message-sent', 'webSocketClose': 'websocket-close', 'requestAborted': 'abort', 'tlsPassthroughOpened': 'tls-passthrough-opened', 'tlsPassthroughClosed': 'tls-passthrough-closed', 'failedTlsRequest': 'tls-client-error', 'failedClientRequest': 'client-error', 'rawPassthroughOpened': 'raw-passthrough-opened', 'rawPassthroughClosed': 'raw-passthrough-closed', 'rawPassthroughData': 'raw-passthrough-data', 'ruleEvent': 'rule-event' }); async function buildMockedEndpointData(endpoint) { return { id: endpoint.id, explanation: endpoint.toString(true), seenRequests: await endpoint.getSeenRequests(), isPending: await endpoint.isPending() }; } const decodeAndSerializeBody = async (body, headers) => { try { const decoded = await (0, request_utils_1.decodeBodyBuffer)(body.buffer, headers); if (decoded === body.buffer) return false; // No decoding required - no-op. else return { decoded }; // Successful decoding result } catch (e) { return { decodingError: e?.message ?? 'Failed to decode message body' }; } }; const serverSideRuleBodySerializer = async (body, headers) => { const encoded = body.buffer.toString('base64'); const result = await decodeAndSerializeBody(body, headers); if (result === false) { // No decoding required - no-op. return { encoded }; } else if (result.decodingError !== undefined) { // Failed decoding - we just return the error message. return { encoded, decodingError: result.decodingError }; } else if (result.decoded) { // Success - we return both formats to the client return { encoded, decoded: result.decoded.toString('base64') }; } else { throw new util_1.UnreachableCheck(result); } }; // messageBodyDecoding === 'None' => Just send encoded body as base64 const noopRuleBodySerializer = (body) => body.buffer.toString('base64'); function buildAdminServerModel(mockServer, stream, ruleParams, options = {}) { const pubsub = new graphql_subscriptions_1.PubSub(); const messageBodyDecoding = options.messageBodyDecoding || 'server-side'; const ruleDeserializationOptions = { bodySerializer: messageBodyDecoding === 'server-side' ? serverSideRuleBodySerializer : noopRuleBodySerializer, ruleParams }; for (let [gqlName, eventName] of graphqlSubscriptionPairs) { mockServer.on(eventName, (evt) => { pubsub.publish(eventName, { [gqlName]: evt }); }); } const subscriptionResolvers = Object.fromEntries(graphqlSubscriptionPairs.map(([gqlName, eventName]) => ([ gqlName, { subscribe: () => pubsub.asyncIterator(eventName) } ]))); return { Query: { mockedEndpoints: async () => { return Promise.all((await mockServer.getMockedEndpoints()).map(buildMockedEndpointData)); }, pendingEndpoints: async () => { return Promise.all((await mockServer.getPendingEndpoints()).map(buildMockedEndpointData)); }, mockedEndpoint: async (__, { id }) => { let endpoint = _.find(await mockServer.getMockedEndpoints(), (endpoint) => { return endpoint.id === id; }); if (!endpoint) return null; return buildMockedEndpointData(endpoint); } }, Mutation: { addRule: async (__, { input }) => { return mockServer.addRequestRule((0, rule_deserialization_1.deserializeRuleData)(input, stream, ruleDeserializationOptions)); }, addRules: async (__, { input }) => { return mockServer.addRequestRules(...input.map((rule) => (0, rule_deserialization_1.deserializeRuleData)(rule, stream, ruleDeserializationOptions))); }, setRules: async (__, { input }) => { return mockServer.setRequestRules(...input.map((rule) => (0, rule_deserialization_1.deserializeRuleData)(rule, stream, ruleDeserializationOptions))); }, addWebSocketRule: async (__, { input }) => { return mockServer.addWebSocketRule((0, rule_deserialization_1.deserializeWebSocketRuleData)(input, stream, ruleDeserializationOptions)); }, addWebSocketRules: async (__, { input }) => { return mockServer.addWebSocketRules(...input.map((rule) => (0, rule_deserialization_1.deserializeWebSocketRuleData)(rule, stream, ruleDeserializationOptions))); }, setWebSocketRules: async (__, { input }) => { return mockServer.setWebSocketRules(...input.map((rule) => (0, rule_deserialization_1.deserializeWebSocketRuleData)(rule, stream, ruleDeserializationOptions))); } }, Subscription: subscriptionResolvers, Request: { body: (request) => { return request.body.buffer; }, decodedBody: async (request) => { if (messageBodyDecoding === 'none') { throw new Error('Decoded body requested, but messageBodyDecoding is set to "none"'); } return (await decodeAndSerializeBody(request.body, request.headers)) || {}; // No decoding required } }, Response: { body: (response) => { return response.body.buffer; }, decodedBody: async (response) => { if (messageBodyDecoding === 'none') { throw new Error('Decoded body requested, but messageBodyDecoding is set to "none"'); } return (await decodeAndSerializeBody(response.body, response.headers)) || {}; // No decoding required } }, ClientError: { response: (error) => { if (error.response === 'aborted') return undefined; else return error.response; } } }; } //# sourceMappingURL=mockttp-admin-model.js.map