@tryghost/express-test 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  module.exports = require('./lib/agent');
2
2
 
3
3
  // NOTE: exposing jest-snapshot as a part of express-test to avoid
4
- // version missmatching on the client side
4
+ // version mismatching on the client side
5
5
  module.exports.snapshot = {
6
6
  mochaHooks: require('@tryghost/jest-snapshot').mochaHooks,
7
7
  snapshotManager: require('@tryghost/jest-snapshot').snapshotManager,
package/lib/request.js CHANGED
@@ -2,6 +2,7 @@ const {default: reqresnext} = require('reqresnext');
2
2
  const {CookieAccessInfo} = require('cookiejar');
3
3
  const {parse} = require('url');
4
4
  const {isJSON} = require('./utils');
5
+ const {Readable} = require('stream');
5
6
 
6
7
  class RequestOptions {
7
8
  constructor({method, url, headers, body} = {}) {
@@ -23,11 +24,74 @@ class Request {
23
24
  this.cookieJar = cookieJar;
24
25
  }
25
26
 
27
+ /**
28
+ * @param {object|string|FormData|Buffer} body Set the request body object or FormData (for multipart/form-data)
29
+ * @returns
30
+ */
26
31
  body(body) {
32
+ if (body.getBuffer && typeof body.getBuffer === 'function') {
33
+ // body is FormData (we cannot reliably check instanceof, not working in all situations)
34
+ const requestBuffer = body.getBuffer();
35
+ const headers = body.getHeaders({
36
+ ...this.reqOptions.headers
37
+ });
38
+ this.reqOptions.headers = headers;
39
+ return this.body(requestBuffer);
40
+ }
41
+ if (typeof body === 'string') {
42
+ const buffer = Buffer.from(body, 'utf8');
43
+ return this.body(buffer);
44
+ }
45
+ if (body instanceof Buffer) {
46
+ this.reqOptions.headers['content-length'] = body.length;
47
+ return this.stream(Readable.from(body));
48
+ }
49
+
50
+ // Manually parsed object (e.g. JSON object)
27
51
  this.reqOptions.body = body;
28
52
  return this;
29
53
  }
30
54
 
55
+ /**
56
+ * Instead of setting a body object, you can also stream the request body. Use this if you want the body
57
+ * to be parsed by the middlewares instead of skipping that step and already setting the decoded body object.
58
+ * @param {stream.Readable} readableStream
59
+ * @returns
60
+ */
61
+ stream(readableStream) {
62
+ this.reqOptions.body = undefined;
63
+
64
+ // reqresnext doesn't support streaming, which we need for file uploads. So we need to add some new methods.
65
+ // ExpressRequest inherits from http.IncomingMessage which inherits from stream.Readable
66
+ // It is that stream that is eventually read by middlewares and converted as JSON, as text, as form data etc.
67
+ // Currently the Express middlewares (and multer for file uploads) use the pipe method and/or the event listeners, so we don't need to override other methods
68
+ // If we need other methods, we only need to map them to the readable stream.
69
+ this.reqOptions.methodOverrides = {
70
+ pipe: (destination) => {
71
+ readableStream.pipe(destination);
72
+ },
73
+ unpipe: (destination) => {
74
+ readableStream.unpipe(destination);
75
+ },
76
+ on: (event, listener) => {
77
+ readableStream.on(event, listener);
78
+ },
79
+ removeListener: (event, listener) => {
80
+ readableStream.removeListener(event, listener);
81
+ },
82
+ get readable() {
83
+ return readableStream.readable;
84
+ },
85
+ pause: () => {
86
+ readableStream.pause();
87
+ },
88
+ read: () => {
89
+ readableStream.read(...arguments);
90
+ }
91
+ };
92
+ return this;
93
+ }
94
+
31
95
  header(name, value) {
32
96
  this.reqOptions.headers[name] = value;
33
97
  return this;
@@ -64,7 +128,18 @@ class Request {
64
128
  _getReqRes() {
65
129
  const {app, reqOptions} = this;
66
130
 
67
- return reqresnext(Object.assign({}, reqOptions, {app}), {app});
131
+ const {req, res} = reqresnext({...reqOptions, app}, {app});
132
+
133
+ if (this.reqOptions.methodOverrides) {
134
+ // Copies all properties from original to copy, including getters and setters
135
+ const props = Object.keys(this.reqOptions.methodOverrides);
136
+ for (const prop of props) {
137
+ const descriptor = Object.getOwnPropertyDescriptor(this.reqOptions.methodOverrides, prop);
138
+ Object.defineProperty(req, prop, descriptor);
139
+ }
140
+ }
141
+
142
+ return {req, res};
68
143
  }
69
144
 
70
145
  _buildResponse(res) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryghost/express-test",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "repository": "https://github.com/TryGhost/framework/tree/main/packages/express-test",
5
5
  "author": "Ghost Foundation",
6
6
  "license": "MIT",
@@ -19,16 +19,18 @@
19
19
  "access": "public"
20
20
  },
21
21
  "devDependencies": {
22
- "c8": "7.12.0",
22
+ "c8": "7.13.0",
23
23
  "express": "4.18.2",
24
24
  "express-session": "1.17.3",
25
+ "form-data": "^4.0.0",
25
26
  "mocha": "10.2.0",
27
+ "multer": "^1.4.5-lts.1",
26
28
  "sinon": "15.0.1"
27
29
  },
28
30
  "dependencies": {
29
- "@tryghost/jest-snapshot": "^0.5.0",
31
+ "@tryghost/jest-snapshot": "^0.5.1",
30
32
  "cookiejar": "^2.1.3",
31
33
  "reqresnext": "^1.7.0"
32
34
  },
33
- "gitHead": "eeb39df042edb802897165ea45ea7667030c4619"
35
+ "gitHead": "ca399175e6fe217dd222067bc47b09cd8c973f5b"
34
36
  }