1 | const _ = require('lodash');
|
2 | const endResponse = require('./endResponse');
|
3 |
|
4 | /**
|
5 | * Creates a new request object based on an existing request and some overrides.
|
6 | *
|
7 | * @param {string} path
|
8 | * The route path to execute.
|
9 | * @param {IncomingMessage} originalReq
|
10 | * The original request object.
|
11 | * @param {Object} requestOverrides
|
12 | * Manual overrides for the request.
|
13 | *
|
14 | * @return {Object}
|
15 | * The newly created request object.
|
16 | */
|
17 | const createRequest = (path, originalReq, requestOverrides = {}) => {
|
18 | // Clone the original request.
|
19 | const newReq = _.cloneDeep(originalReq);
|
20 | // Delete all private properties since those should be computed.
|
21 | Object.keys(newReq)
|
22 | .filter(key => key[0] === '_')
|
23 | .forEach((key) => {
|
24 | delete newReq[key];
|
25 | });
|
26 | // Apply overrides.
|
27 | Object.keys(requestOverrides)
|
28 | .forEach((key) => {
|
29 | newReq[key] = requestOverrides[key];
|
30 | });
|
31 | // Override the URL.
|
32 | newReq.url = path;
|
33 | newReq.originalUrl = path;
|
34 | // Make sure the request method is uppercase.
|
35 | newReq.method = newReq.method.toUpperCase();
|
36 | newReq.originalMethod = newReq.method;
|
37 |
|
38 | return newReq;
|
39 | };
|
40 |
|
41 | /**
|
42 | * Creates a response that other middlewares can interact with.
|
43 | *
|
44 | * @param {ServerResponse} originalRes
|
45 | * The original response.
|
46 | * @param {IncomingMessage} req
|
47 | * The modified request object.
|
48 | * @param {function} callback
|
49 | * Instead of terminating the response as express would normally do upon
|
50 | * calling res.end, we will execute this callback.
|
51 | *
|
52 | * @return {Object}
|
53 | * A response mock that contains the most commonly called response methods.
|
54 | */
|
55 | const createResponse = (originalRes, req, callback) => {
|
56 | // Clone the original response.
|
57 | const newRes = _.cloneDeep(originalRes);
|
58 | // Set the modified request object.
|
59 | newRes.req = req;
|
60 |
|
61 | // Response termination using our custom callback instead.
|
62 | newRes.end = endResponse(newRes, callback);
|
63 | newRes.send = newRes.end;
|
64 | newRes.write = newRes.end;
|
65 |
|
66 | return newRes;
|
67 | };
|
68 |
|
69 | /**
|
70 | * Creates the request and response objects.
|
71 | *
|
72 | * @param {string} path
|
73 | * The route path to execute.
|
74 | * @param {IncomingMessage} req
|
75 | * The original request object.
|
76 | * @param {ServerResponse} res
|
77 | * The original response object.
|
78 | * @param {Object} requestOverrides
|
79 | * Manual overrides for the request.
|
80 | * @param {function} callback
|
81 | * Instead of terminating the response as express would normally do upon
|
82 | * calling res.end, we will execute this callback.
|
83 | *
|
84 | * @return {[IncomingMessage, ServerResponse]}
|
85 | * A tuple containing the request and response objects.
|
86 | */
|
87 | const createRequestAndResponse = (path, req, res, requestOverrides, callback) => {
|
88 | callback = _.once(callback);
|
89 | const newRew = createRequest(path, req, requestOverrides);
|
90 | const newRes = createResponse(res, newRew, callback);
|
91 | return [newRew, newRes];
|
92 | };
|
93 |
|
94 | module.exports = (app) => {
|
95 | app.use((req, res, next) => {
|
96 | req.runMiddleware = (path, requestOverrides, callback) => {
|
97 | app.runMiddleware(path, req, res, requestOverrides, callback);
|
98 | };
|
99 | next();
|
100 | });
|
101 |
|
102 | // Only add once to the app object.
|
103 | if (app.runMiddleware) {
|
104 | return;
|
105 | }
|
106 |
|
107 | app.runMiddleware = (path, req, res, requestOverrides, callback) => {
|
108 | const tuple = createRequestAndResponse(path, req, res, requestOverrides, callback);
|
109 | app(tuple[0], tuple[1]);
|
110 | };
|
111 | };
|