@unito/integration-sdk 2.3.3 → 2.3.5

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.
@@ -3,6 +3,7 @@
3
3
  var integrationApi = require('@unito/integration-api');
4
4
  var cachette = require('cachette');
5
5
  var crypto = require('crypto');
6
+ var util = require('util');
6
7
  var express = require('express');
7
8
  var busboy = require('busboy');
8
9
  var https = require('https');
@@ -161,7 +162,13 @@ class Logger {
161
162
  status: logLevel,
162
163
  };
163
164
  if (process.env.NODE_ENV === 'development') {
164
- console[logLevel](JSON.stringify(processedLogs, null, 2));
165
+ const coloredMessage = Logger.colorize(message, processedLogs, logLevel);
166
+ const metadata = {
167
+ date: new Date(processedLogs.date).toISOString(),
168
+ ...(processedMetadata.error && { error: processedMetadata.error }),
169
+ };
170
+ const metadataString = Object.keys(metadata).length > 1 ? ` ${JSON.stringify(metadata, null, 2)}` : ` ${JSON.stringify(metadata)}`;
171
+ console[logLevel](`${coloredMessage}${metadataString}`);
165
172
  }
166
173
  else {
167
174
  console[logLevel](JSON.stringify(processedLogs));
@@ -204,6 +211,55 @@ class Logger {
204
211
  }
205
212
  return prunedMetadata;
206
213
  }
214
+ /**
215
+ * Colorizes the log message based on the log level and status codes.
216
+ * @param message The message to colorize.
217
+ * @param metadata The metadata associated with the log.
218
+ * @param logLevel The log level of the message.
219
+ * @returns The colorized output string.
220
+ */
221
+ static colorize(message, metadata, logLevel) {
222
+ if (!process.stdout.isTTY) {
223
+ return `${logLevel}: ${message}`;
224
+ }
225
+ // Extract status code from logs
226
+ let statusCode;
227
+ if (metadata.http && typeof metadata.http === 'object' && !Array.isArray(metadata.http)) {
228
+ const statusCodeValue = metadata.http.status_code;
229
+ if (typeof statusCodeValue === 'number') {
230
+ statusCode = statusCodeValue;
231
+ }
232
+ else if (typeof statusCodeValue === 'string') {
233
+ statusCode = parseInt(statusCodeValue, 10);
234
+ }
235
+ }
236
+ // Color based on status code first
237
+ if (statusCode) {
238
+ if (statusCode >= 400) {
239
+ return `${util.styleText('red', logLevel)}: ${util.styleText('red', message)}`;
240
+ }
241
+ else if (statusCode >= 300) {
242
+ return `${util.styleText('yellow', logLevel)}: ${util.styleText('yellow', message)}`;
243
+ }
244
+ else if (statusCode >= 200) {
245
+ return `${util.styleText('green', logLevel)}: ${util.styleText('green', message)}`;
246
+ }
247
+ }
248
+ // Fall back to log level if no status code found
249
+ switch (logLevel) {
250
+ case LogLevel.ERROR:
251
+ return `${util.styleText('red', logLevel)}: ${util.styleText('red', message)}`;
252
+ case LogLevel.WARN:
253
+ return `${util.styleText('yellow', logLevel)}: ${util.styleText('yellow', message)}`;
254
+ case LogLevel.INFO:
255
+ case LogLevel.LOG:
256
+ return `${util.styleText('green', logLevel)}: ${util.styleText('green', message)}`;
257
+ case LogLevel.DEBUG:
258
+ return `${util.styleText('cyan', logLevel)}: ${util.styleText('cyan', message)}`;
259
+ default:
260
+ return `${logLevel}: ${message}`;
261
+ }
262
+ }
207
263
  }
208
264
  const NULL_LOGGER = new Logger({}, true);
209
265
 
@@ -68,6 +68,14 @@ export default class Logger {
68
68
  private send;
69
69
  private static snakifyKeys;
70
70
  private static pruneSensitiveMetadata;
71
+ /**
72
+ * Colorizes the log message based on the log level and status codes.
73
+ * @param message The message to colorize.
74
+ * @param metadata The metadata associated with the log.
75
+ * @param logLevel The log level of the message.
76
+ * @returns The colorized output string.
77
+ */
78
+ private static colorize;
71
79
  }
72
80
  export declare const NULL_LOGGER: Logger;
73
81
  export {};
@@ -1,3 +1,4 @@
1
+ import { styleText } from 'util';
1
2
  var LogLevel;
2
3
  (function (LogLevel) {
3
4
  LogLevel["ERROR"] = "error";
@@ -133,7 +134,13 @@ export default class Logger {
133
134
  status: logLevel,
134
135
  };
135
136
  if (process.env.NODE_ENV === 'development') {
136
- console[logLevel](JSON.stringify(processedLogs, null, 2));
137
+ const coloredMessage = Logger.colorize(message, processedLogs, logLevel);
138
+ const metadata = {
139
+ date: new Date(processedLogs.date).toISOString(),
140
+ ...(processedMetadata.error && { error: processedMetadata.error }),
141
+ };
142
+ const metadataString = Object.keys(metadata).length > 1 ? ` ${JSON.stringify(metadata, null, 2)}` : ` ${JSON.stringify(metadata)}`;
143
+ console[logLevel](`${coloredMessage}${metadataString}`);
137
144
  }
138
145
  else {
139
146
  console[logLevel](JSON.stringify(processedLogs));
@@ -176,5 +183,54 @@ export default class Logger {
176
183
  }
177
184
  return prunedMetadata;
178
185
  }
186
+ /**
187
+ * Colorizes the log message based on the log level and status codes.
188
+ * @param message The message to colorize.
189
+ * @param metadata The metadata associated with the log.
190
+ * @param logLevel The log level of the message.
191
+ * @returns The colorized output string.
192
+ */
193
+ static colorize(message, metadata, logLevel) {
194
+ if (!process.stdout.isTTY) {
195
+ return `${logLevel}: ${message}`;
196
+ }
197
+ // Extract status code from logs
198
+ let statusCode;
199
+ if (metadata.http && typeof metadata.http === 'object' && !Array.isArray(metadata.http)) {
200
+ const statusCodeValue = metadata.http.status_code;
201
+ if (typeof statusCodeValue === 'number') {
202
+ statusCode = statusCodeValue;
203
+ }
204
+ else if (typeof statusCodeValue === 'string') {
205
+ statusCode = parseInt(statusCodeValue, 10);
206
+ }
207
+ }
208
+ // Color based on status code first
209
+ if (statusCode) {
210
+ if (statusCode >= 400) {
211
+ return `${styleText('red', logLevel)}: ${styleText('red', message)}`;
212
+ }
213
+ else if (statusCode >= 300) {
214
+ return `${styleText('yellow', logLevel)}: ${styleText('yellow', message)}`;
215
+ }
216
+ else if (statusCode >= 200) {
217
+ return `${styleText('green', logLevel)}: ${styleText('green', message)}`;
218
+ }
219
+ }
220
+ // Fall back to log level if no status code found
221
+ switch (logLevel) {
222
+ case LogLevel.ERROR:
223
+ return `${styleText('red', logLevel)}: ${styleText('red', message)}`;
224
+ case LogLevel.WARN:
225
+ return `${styleText('yellow', logLevel)}: ${styleText('yellow', message)}`;
226
+ case LogLevel.INFO:
227
+ case LogLevel.LOG:
228
+ return `${styleText('green', logLevel)}: ${styleText('green', message)}`;
229
+ case LogLevel.DEBUG:
230
+ return `${styleText('cyan', logLevel)}: ${styleText('cyan', message)}`;
231
+ default:
232
+ return `${logLevel}: ${message}`;
233
+ }
234
+ }
179
235
  }
180
236
  export const NULL_LOGGER = new Logger({}, true);
@@ -129,7 +129,7 @@ describe('Logger', () => {
129
129
  { id: 2, organization_id: 'b' },
130
130
  ]);
131
131
  });
132
- it('prunes sensitive Metadata', { only: true }, testContext => {
132
+ it('prunes sensitive Metadata', testContext => {
133
133
  const logSpy = testContext.mock.method(global.console, 'log', () => { });
134
134
  assert.strictEqual(logSpy.mock.calls.length, 0);
135
135
  const metadata = {
@@ -177,4 +177,134 @@ describe('Logger', () => {
177
177
  assert.strictEqual(infoSpy.mock.calls.length, 0);
178
178
  assert.strictEqual(debugSpy.mock.calls.length, 0);
179
179
  });
180
+ it('colorizes logs by status codes over log levels', () => {
181
+ const originalEnv = process.env.NODE_ENV;
182
+ const originalIsTTY = process.stdout.isTTY;
183
+ try {
184
+ process.env.NODE_ENV = 'development';
185
+ Object.defineProperty(process.stdout, 'isTTY', {
186
+ value: true,
187
+ configurable: true,
188
+ });
189
+ // 4xx status with warn level, should be red
190
+ const metadataWith400 = {
191
+ http: { status_code: 400 },
192
+ };
193
+ const redResult = Logger['colorize']('Some error', metadataWith400, 'warn');
194
+ // warn level without status code, should be yellow
195
+ const metadataNoStatus = {};
196
+ const yellowResult = Logger['colorize']('Some warning', metadataNoStatus, 'warn');
197
+ // Results should be different colors
198
+ assert.notEqual(redResult, yellowResult);
199
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
200
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
201
+ }
202
+ finally {
203
+ // Restore original values
204
+ process.env.NODE_ENV = originalEnv;
205
+ Object.defineProperty(process.stdout, 'isTTY', {
206
+ value: originalIsTTY,
207
+ configurable: true,
208
+ });
209
+ }
210
+ });
211
+ it('colorizes logs with different status code ranges', () => {
212
+ const originalEnv = process.env.NODE_ENV;
213
+ const originalIsTTY = process.stdout.isTTY;
214
+ try {
215
+ process.env.NODE_ENV = 'development';
216
+ Object.defineProperty(process.stdout, 'isTTY', {
217
+ value: true,
218
+ configurable: true,
219
+ });
220
+ // 2xx status codes should be green
221
+ const successMetadata = {
222
+ http: { status_code: 200 },
223
+ };
224
+ const greenResult = Logger['colorize']('Success', successMetadata, 'info');
225
+ assert.ok(greenResult.includes('\x1b[32m')); // Green color code
226
+ // 3xx status codes should be yellow
227
+ const redirectMetadata = {
228
+ http: { status_code: 301 },
229
+ };
230
+ const yellowResult = Logger['colorize']('Redirect', redirectMetadata, 'info');
231
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
232
+ // 4xx status codes should be red
233
+ const clientErrorMetadata = {
234
+ http: { status_code: 404 },
235
+ };
236
+ const redResult = Logger['colorize']('Not Found', clientErrorMetadata, 'warn');
237
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
238
+ // 5xx status codes should be red
239
+ const serverErrorMetadata = {
240
+ http: { status_code: 500 },
241
+ };
242
+ const redResult2 = Logger['colorize']('Server Error', serverErrorMetadata, 'error');
243
+ assert.ok(redResult2.includes('\x1b[31m')); // Red color code
244
+ }
245
+ finally {
246
+ process.env.NODE_ENV = originalEnv;
247
+ Object.defineProperty(process.stdout, 'isTTY', {
248
+ value: originalIsTTY,
249
+ configurable: true,
250
+ });
251
+ }
252
+ });
253
+ it('only logs date for metadata of successful requests in development', testContext => {
254
+ const originalEnv = process.env.NODE_ENV;
255
+ try {
256
+ process.env.NODE_ENV = 'development';
257
+ const infoSpy = testContext.mock.method(global.console, 'info', () => { });
258
+ const metadata = {
259
+ correlation_id: '123456789',
260
+ http: { method: 'GET', status_code: 200 },
261
+ user_id: 'user123',
262
+ request_id: 'req456',
263
+ };
264
+ const logger = new Logger(metadata);
265
+ logger.info('Test message without error');
266
+ assert.strictEqual(infoSpy.mock.calls.length, 1);
267
+ const loggedOutput = infoSpy.mock.calls[0]?.arguments[0];
268
+ assert.ok(loggedOutput.includes('Test message without error'));
269
+ // Should only contain date in metadata JSON
270
+ const metadataMatch = loggedOutput.match(/({.*})/);
271
+ assert.ok(metadataMatch);
272
+ const parsedMetadata = JSON.parse(metadataMatch[1]);
273
+ assert.ok(parsedMetadata.date);
274
+ assert.strictEqual(Object.keys(parsedMetadata).length, 1); // What matters: Only the date
275
+ }
276
+ finally {
277
+ process.env.NODE_ENV = originalEnv;
278
+ }
279
+ });
280
+ it('logs date & error stack for metadata of failed requests in development', testContext => {
281
+ const originalEnv = process.env.NODE_ENV;
282
+ try {
283
+ process.env.NODE_ENV = 'development';
284
+ const metadata = {
285
+ correlation_id: '123456789',
286
+ http: { method: 'GET', status_code: 200 },
287
+ user_id: 'user123',
288
+ request_id: 'req456',
289
+ };
290
+ const logger = new Logger(metadata);
291
+ // Test with error metadata
292
+ const errorSpy = testContext.mock.method(global.console, 'error', () => { });
293
+ logger.error('Test message with error', { error: { code: 500, message: 'Internal Server Error' } });
294
+ assert.strictEqual(errorSpy.mock.calls.length, 1);
295
+ const errorLoggedOutput = errorSpy.mock.calls[0]?.arguments[0];
296
+ assert.ok(errorLoggedOutput.includes('Test message with error'));
297
+ // Should contain both date and error in metadata JSON
298
+ const errorMetadataMatch = errorLoggedOutput.match(/({.*})/s);
299
+ assert.ok(errorMetadataMatch);
300
+ const parsedErrorMetadata = JSON.parse(errorMetadataMatch[1]);
301
+ assert.ok(parsedErrorMetadata.date);
302
+ assert.ok(parsedErrorMetadata.error);
303
+ assert.deepEqual(parsedErrorMetadata.error, { code: 500, message: 'Internal Server Error' });
304
+ assert.strictEqual(Object.keys(parsedErrorMetadata).length, 2); // What matters: Date and error only
305
+ }
306
+ finally {
307
+ process.env.NODE_ENV = originalEnv;
308
+ }
309
+ });
180
310
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unito/integration-sdk",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "Integration SDK",
5
5
  "type": "module",
6
6
  "types": "dist/src/index.d.ts",
@@ -1,3 +1,5 @@
1
+ import { styleText } from 'util';
2
+
1
3
  const enum LogLevel {
2
4
  ERROR = 'error',
3
5
  WARN = 'warn',
@@ -162,7 +164,17 @@ export default class Logger {
162
164
  };
163
165
 
164
166
  if (process.env.NODE_ENV === 'development') {
165
- console[logLevel](JSON.stringify(processedLogs, null, 2));
167
+ const coloredMessage = Logger.colorize(message, processedLogs, logLevel);
168
+
169
+ const metadata = {
170
+ date: new Date(processedLogs.date).toISOString(),
171
+ ...(processedMetadata.error && { error: processedMetadata.error }),
172
+ };
173
+
174
+ const metadataString =
175
+ Object.keys(metadata).length > 1 ? ` ${JSON.stringify(metadata, null, 2)}` : ` ${JSON.stringify(metadata)}`;
176
+
177
+ console[logLevel](`${coloredMessage}${metadataString}`);
166
178
  } else {
167
179
  console[logLevel](JSON.stringify(processedLogs));
168
180
  }
@@ -209,6 +221,57 @@ export default class Logger {
209
221
 
210
222
  return prunedMetadata;
211
223
  }
224
+
225
+ /**
226
+ * Colorizes the log message based on the log level and status codes.
227
+ * @param message The message to colorize.
228
+ * @param metadata The metadata associated with the log.
229
+ * @param logLevel The log level of the message.
230
+ * @returns The colorized output string.
231
+ */
232
+ private static colorize(message: string, metadata: Value, logLevel: LogLevel): string {
233
+ if (!process.stdout.isTTY) {
234
+ return `${logLevel}: ${message}`;
235
+ }
236
+
237
+ // Extract status code from logs
238
+ let statusCode: number | undefined;
239
+ if (metadata.http && typeof metadata.http === 'object' && !Array.isArray(metadata.http)) {
240
+ const statusCodeValue = metadata.http.status_code;
241
+
242
+ if (typeof statusCodeValue === 'number') {
243
+ statusCode = statusCodeValue;
244
+ } else if (typeof statusCodeValue === 'string') {
245
+ statusCode = parseInt(statusCodeValue, 10);
246
+ }
247
+ }
248
+
249
+ // Color based on status code first
250
+ if (statusCode) {
251
+ if (statusCode >= 400) {
252
+ return `${styleText('red', logLevel)}: ${styleText('red', message)}`;
253
+ } else if (statusCode >= 300) {
254
+ return `${styleText('yellow', logLevel)}: ${styleText('yellow', message)}`;
255
+ } else if (statusCode >= 200) {
256
+ return `${styleText('green', logLevel)}: ${styleText('green', message)}`;
257
+ }
258
+ }
259
+
260
+ // Fall back to log level if no status code found
261
+ switch (logLevel) {
262
+ case LogLevel.ERROR:
263
+ return `${styleText('red', logLevel)}: ${styleText('red', message)}`;
264
+ case LogLevel.WARN:
265
+ return `${styleText('yellow', logLevel)}: ${styleText('yellow', message)}`;
266
+ case LogLevel.INFO:
267
+ case LogLevel.LOG:
268
+ return `${styleText('green', logLevel)}: ${styleText('green', message)}`;
269
+ case LogLevel.DEBUG:
270
+ return `${styleText('cyan', logLevel)}: ${styleText('cyan', message)}`;
271
+ default:
272
+ return `${logLevel}: ${message}`;
273
+ }
274
+ }
212
275
  }
213
276
 
214
277
  export const NULL_LOGGER = new Logger({}, true);
@@ -155,7 +155,7 @@ describe('Logger', () => {
155
155
  ]);
156
156
  });
157
157
 
158
- it('prunes sensitive Metadata', { only: true }, testContext => {
158
+ it('prunes sensitive Metadata', testContext => {
159
159
  const logSpy = testContext.mock.method(global.console, 'log', () => {});
160
160
  assert.strictEqual(logSpy.mock.calls.length, 0);
161
161
 
@@ -209,4 +209,155 @@ describe('Logger', () => {
209
209
  assert.strictEqual(infoSpy.mock.calls.length, 0);
210
210
  assert.strictEqual(debugSpy.mock.calls.length, 0);
211
211
  });
212
+
213
+ it('colorizes logs by status codes over log levels', () => {
214
+ const originalEnv = process.env.NODE_ENV;
215
+ const originalIsTTY = process.stdout.isTTY;
216
+
217
+ try {
218
+ process.env.NODE_ENV = 'development';
219
+ Object.defineProperty(process.stdout, 'isTTY', {
220
+ value: true,
221
+ configurable: true,
222
+ });
223
+
224
+ // 4xx status with warn level, should be red
225
+ const metadataWith400 = {
226
+ http: { status_code: 400 },
227
+ };
228
+ const redResult = Logger['colorize']('Some error', metadataWith400, 'warn' as any);
229
+
230
+ // warn level without status code, should be yellow
231
+ const metadataNoStatus = {};
232
+ const yellowResult = Logger['colorize']('Some warning', metadataNoStatus, 'warn' as any);
233
+
234
+ // Results should be different colors
235
+ assert.notEqual(redResult, yellowResult);
236
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
237
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
238
+ } finally {
239
+ // Restore original values
240
+ process.env.NODE_ENV = originalEnv;
241
+ Object.defineProperty(process.stdout, 'isTTY', {
242
+ value: originalIsTTY,
243
+ configurable: true,
244
+ });
245
+ }
246
+ });
247
+
248
+ it('colorizes logs with different status code ranges', () => {
249
+ const originalEnv = process.env.NODE_ENV;
250
+ const originalIsTTY = process.stdout.isTTY;
251
+
252
+ try {
253
+ process.env.NODE_ENV = 'development';
254
+ Object.defineProperty(process.stdout, 'isTTY', {
255
+ value: true,
256
+ configurable: true,
257
+ });
258
+
259
+ // 2xx status codes should be green
260
+ const successMetadata = {
261
+ http: { status_code: 200 },
262
+ };
263
+ const greenResult = Logger['colorize']('Success', successMetadata, 'info' as any);
264
+ assert.ok(greenResult.includes('\x1b[32m')); // Green color code
265
+
266
+ // 3xx status codes should be yellow
267
+ const redirectMetadata = {
268
+ http: { status_code: 301 },
269
+ };
270
+ const yellowResult = Logger['colorize']('Redirect', redirectMetadata, 'info' as any);
271
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
272
+
273
+ // 4xx status codes should be red
274
+ const clientErrorMetadata = {
275
+ http: { status_code: 404 },
276
+ };
277
+ const redResult = Logger['colorize']('Not Found', clientErrorMetadata, 'warn' as any);
278
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
279
+
280
+ // 5xx status codes should be red
281
+ const serverErrorMetadata = {
282
+ http: { status_code: 500 },
283
+ };
284
+ const redResult2 = Logger['colorize']('Server Error', serverErrorMetadata, 'error' as any);
285
+ assert.ok(redResult2.includes('\x1b[31m')); // Red color code
286
+ } finally {
287
+ process.env.NODE_ENV = originalEnv;
288
+ Object.defineProperty(process.stdout, 'isTTY', {
289
+ value: originalIsTTY,
290
+ configurable: true,
291
+ });
292
+ }
293
+ });
294
+
295
+ it('only logs date for metadata of successful requests in development', testContext => {
296
+ const originalEnv = process.env.NODE_ENV;
297
+
298
+ try {
299
+ process.env.NODE_ENV = 'development';
300
+
301
+ const infoSpy = testContext.mock.method(global.console, 'info', () => {});
302
+ const metadata = {
303
+ correlation_id: '123456789',
304
+ http: { method: 'GET', status_code: 200 },
305
+ user_id: 'user123',
306
+ request_id: 'req456',
307
+ };
308
+
309
+ const logger = new Logger(metadata);
310
+
311
+ logger.info('Test message without error');
312
+ assert.strictEqual(infoSpy.mock.calls.length, 1);
313
+
314
+ const loggedOutput = infoSpy.mock.calls[0]?.arguments[0];
315
+ assert.ok(loggedOutput.includes('Test message without error'));
316
+
317
+ // Should only contain date in metadata JSON
318
+ const metadataMatch = loggedOutput.match(/({.*})/);
319
+ assert.ok(metadataMatch);
320
+ const parsedMetadata = JSON.parse(metadataMatch[1]);
321
+ assert.ok(parsedMetadata.date);
322
+ assert.strictEqual(Object.keys(parsedMetadata).length, 1); // What matters: Only the date
323
+ } finally {
324
+ process.env.NODE_ENV = originalEnv;
325
+ }
326
+ });
327
+
328
+ it('logs date & error stack for metadata of failed requests in development', testContext => {
329
+ const originalEnv = process.env.NODE_ENV;
330
+
331
+ try {
332
+ process.env.NODE_ENV = 'development';
333
+
334
+ const metadata = {
335
+ correlation_id: '123456789',
336
+ http: { method: 'GET', status_code: 200 },
337
+ user_id: 'user123',
338
+ request_id: 'req456',
339
+ };
340
+
341
+ const logger = new Logger(metadata);
342
+
343
+ // Test with error metadata
344
+ const errorSpy = testContext.mock.method(global.console, 'error', () => {});
345
+ logger.error('Test message with error', { error: { code: 500, message: 'Internal Server Error' } });
346
+ assert.strictEqual(errorSpy.mock.calls.length, 1);
347
+
348
+ const errorLoggedOutput = errorSpy.mock.calls[0]?.arguments[0];
349
+ assert.ok(errorLoggedOutput.includes('Test message with error'));
350
+
351
+ // Should contain both date and error in metadata JSON
352
+ const errorMetadataMatch = errorLoggedOutput.match(/({.*})/s);
353
+ assert.ok(errorMetadataMatch);
354
+ const parsedErrorMetadata = JSON.parse(errorMetadataMatch[1]);
355
+ assert.ok(parsedErrorMetadata.date);
356
+ assert.ok(parsedErrorMetadata.error);
357
+ assert.deepEqual(parsedErrorMetadata.error, { code: 500, message: 'Internal Server Error' });
358
+ assert.strictEqual(Object.keys(parsedErrorMetadata).length, 2); // What matters: Date and error only
359
+ } finally {
360
+ process.env.NODE_ENV = originalEnv;
361
+ }
362
+ });
212
363
  });