Compare commits
No commits in common. "4131abec824a336eeb68b531e6c91f2748a0644a" and "60cc71b31804e367de78551d528d043cc4f286be" have entirely different histories.
4131abec82
...
60cc71b318
37
index.js
37
index.js
|
@ -1,5 +1,4 @@
|
||||||
const API = require('./lib/api.js');
|
const API = require('./lib/api.js');
|
||||||
const stderrUtils = require('./lib/stderrUtils');
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For convenience purposes, we provide an already instanciated API; so that
|
* For convenience purposes, we provide an already instanciated API; so that
|
||||||
|
@ -12,40 +11,4 @@ module.exports = {
|
||||||
Logger: werelogs.Logger,
|
Logger: werelogs.Logger,
|
||||||
configure: werelogs.reconfigure.bind(werelogs),
|
configure: werelogs.reconfigure.bind(werelogs),
|
||||||
Werelogs: API,
|
Werelogs: API,
|
||||||
/**
|
|
||||||
* Timestamp logs going to stderr
|
|
||||||
*
|
|
||||||
* @example <caption>Simplest usage</caption>
|
|
||||||
* ```
|
|
||||||
* const { stderrUtils } = require('werelogs');
|
|
||||||
* stderrUtils.catchAndTimestampStderr();
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example <caption>Manage process exit</caption>
|
|
||||||
* ```
|
|
||||||
* const { stderrUtils } = require('werelogs');
|
|
||||||
* // set exitCode to null to keep process running on uncaughtException
|
|
||||||
* stderrUtils.catchAndTimestampStderr(undefined, null);
|
|
||||||
* // application init
|
|
||||||
* process.on('uncaughtException', (err) => {
|
|
||||||
* // custom handling, close connections, files
|
|
||||||
* this.worker.kill(); // or process.exit(1);
|
|
||||||
* });
|
|
||||||
* // Note you could use prependListener to execute your callback first
|
|
||||||
* // and then let stderrUtils exit the process.
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example <caption>Custom listener</caption>
|
|
||||||
* ```
|
|
||||||
* const { stderrUtils } = require('werelogs');
|
|
||||||
* stderrUtils.catchAndTimestampWarning();
|
|
||||||
* // application init
|
|
||||||
* process.on('uncaughtException', (err, origin) => {
|
|
||||||
* stderrUtils.printErrorWithTimestamp(err, origin);
|
|
||||||
* // close and stop everything
|
|
||||||
* process.exit(1);
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
stderrUtils,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
/**
|
|
||||||
* @returns {string} a timestamp in ISO format YYYY-MM-DDThh:mm:ss.sssZ
|
|
||||||
*/
|
|
||||||
const defaultTimestamp = () => new Date().toISOString();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints on stderr a timestamp, the origin and the error
|
|
||||||
*
|
|
||||||
* If no other instructions are needed on uncaughtException,
|
|
||||||
* consider using `catchAndTimestampStderr` directly.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* process.on('uncaughtException', (err, origin) => {
|
|
||||||
* printErrorWithTimestamp(err, origin);
|
|
||||||
* // server.close();
|
|
||||||
* // file.close();
|
|
||||||
* process.nextTick(() => process.exit(1));
|
|
||||||
* });
|
|
||||||
* // Don't forget to timestamp warning
|
|
||||||
* catchAndTimestampWarning();
|
|
||||||
* @param {Error} err see process event uncaughtException
|
|
||||||
* @param {uncaughtException|unhandledRejection} origin see process event
|
|
||||||
* @param {string} [date=`defaultTimestamp()`] Date to print
|
|
||||||
* @returns {boolean} see process.stderr.write
|
|
||||||
*/
|
|
||||||
function printErrorWithTimestamp(
|
|
||||||
err, origin, date = defaultTimestamp(),
|
|
||||||
) {
|
|
||||||
return process.stderr.write(`${date}: ${origin}:\n${err.stack}\n`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prefer using `catchAndTimestampStderr` instead of this function.
|
|
||||||
*
|
|
||||||
* Adds listener for uncaughtException to print with timestamp.
|
|
||||||
*
|
|
||||||
* If you want to manage the end of the process, you can set exitCode to null.
|
|
||||||
* Or use `printErrorWithTimestamp` in your own uncaughtException listener.
|
|
||||||
*
|
|
||||||
* @param {Function} [dateFct=`defaultTimestamp`] Fct returning a formatted date
|
|
||||||
* @param {*} [exitCode=1] On uncaughtException, if not null, `process.exit`
|
|
||||||
* will be called with this value
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
function catchAndTimestampUncaughtException(
|
|
||||||
dateFct = defaultTimestamp, exitCode = 1,
|
|
||||||
) {
|
|
||||||
process.on('uncaughtException', (err, origin) => {
|
|
||||||
printErrorWithTimestamp(err, origin, dateFct());
|
|
||||||
if (exitCode !== null) {
|
|
||||||
process.nextTick(() => process.exit(exitCode));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Forces the use of `--trace-warnings` and adds a date in warning.detail
|
|
||||||
* The warning will be printed by the default `onWarning`
|
|
||||||
*
|
|
||||||
* @param {string} [dateFct=`defaultTimestamp`] Fct returning a formatted date
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
function catchAndTimestampWarning(dateFct = defaultTimestamp) {
|
|
||||||
process.traceProcessWarnings = true;
|
|
||||||
// must be executed first, before the default `onWarning`
|
|
||||||
process.prependListener('warning', warning => {
|
|
||||||
if (warning.detail) {
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
warning.detail += `\nAbove Warning Date: ${dateFct()}`;
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
warning.detail = `Above Warning Date: ${dateFct()}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds listener for uncaughtException and warning to print them with timestamp.
|
|
||||||
*
|
|
||||||
* If you want to manage the end of the process, you can set exitCode to null.
|
|
||||||
* Or use `printErrorWithTimestamp` in your own uncaughtException listener.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const { stderrUtils } = require('werelogs');
|
|
||||||
* // first instruction in your index.js or entrypoint
|
|
||||||
* stderrUtils.catchAndTimestampStderr();
|
|
||||||
*
|
|
||||||
* @param {Function} [dateFct=`defaultTimestamp`] Fct returning a formatted date
|
|
||||||
* @param {*} [exitCode=1] On uncaughtException, if not null, `process.exit`
|
|
||||||
* will be called with this value
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
function catchAndTimestampStderr(
|
|
||||||
dateFct = defaultTimestamp, exitCode = 1,
|
|
||||||
) {
|
|
||||||
catchAndTimestampUncaughtException(dateFct, exitCode);
|
|
||||||
catchAndTimestampWarning(dateFct);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
defaultTimestamp,
|
|
||||||
printErrorWithTimestamp,
|
|
||||||
catchAndTimestampUncaughtException,
|
|
||||||
catchAndTimestampWarning,
|
|
||||||
catchAndTimestampStderr,
|
|
||||||
};
|
|
|
@ -3,7 +3,7 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"version": "8.1.5",
|
"version": "8.1.4",
|
||||||
"description": "An efficient raw JSON logging library aimed at micro-services architectures.",
|
"description": "An efficient raw JSON logging library aimed at micro-services architectures.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
// Convert string args into primitive value
|
|
||||||
const fromStr = (str, primitive) => (str === `${primitive}` ? primitive : str);
|
|
||||||
const date = fromStr(process.argv[2], undefined);
|
|
||||||
const exitCode = fromStr(fromStr(process.argv[3], null), undefined);
|
|
||||||
|
|
||||||
const { stderrUtils } = require('../../../../index');
|
|
||||||
|
|
||||||
stderrUtils.catchAndTimestampStderr(
|
|
||||||
date ? () => date : undefined,
|
|
||||||
exitCode,
|
|
||||||
);
|
|
||||||
|
|
||||||
process.emitWarning('TestWarningMessage');
|
|
||||||
// This will print warning after printing error before exit
|
|
||||||
throw new Error('TestingError');
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
// Convert string args into primitive value
|
|
||||||
const fromStr = (str, primitive) => (str === `${primitive}` ? primitive : str);
|
|
||||||
const date = fromStr(process.argv[2], undefined);
|
|
||||||
const exitCode = fromStr(fromStr(process.argv[3], null), undefined);
|
|
||||||
const promise = fromStr(process.argv[4], true);
|
|
||||||
|
|
||||||
const { stderrUtils } = require('../../../../index');
|
|
||||||
|
|
||||||
stderrUtils.catchAndTimestampUncaughtException(
|
|
||||||
date ? () => date : undefined,
|
|
||||||
exitCode,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Executed if process does not exit, process is in undefined behavior (bad)
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
setTimeout(() => console.log('EXECUTED AFTER UNCAUGHT EXCEPTION'), 1);
|
|
||||||
|
|
||||||
if (promise === true) {
|
|
||||||
Promise.reject();
|
|
||||||
} else {
|
|
||||||
throw new Error('TestingError');
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
// Convert string args into primitive value
|
|
||||||
const fromStr = (str, primitive) => (str === `${primitive}` ? primitive : str);
|
|
||||||
const date = fromStr(process.argv[2], undefined);
|
|
||||||
const name = fromStr(process.argv[3], undefined);
|
|
||||||
const code = fromStr(process.argv[4], undefined);
|
|
||||||
const detail = fromStr(process.argv[5], undefined);
|
|
||||||
|
|
||||||
const { stderrUtils } = require('../../../../index');
|
|
||||||
|
|
||||||
stderrUtils.catchAndTimestampWarning(
|
|
||||||
date ? () => date : undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
const warning = new Error('TestWarningMessage');
|
|
||||||
|
|
||||||
if (name) warning.name = name;
|
|
||||||
if (code) warning.code = code;
|
|
||||||
if (detail) warning.detail = detail;
|
|
||||||
|
|
||||||
process.emitWarning(warning);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
(node:203831) Error: TestWarningMessage
|
|
||||||
at Object.<anonymous> (catchWarning.js:15:17)
|
|
||||||
...
|
|
||||||
at node:internal/main/run_main_module:22:47
|
|
||||||
Above Warning Date: 2024-06-26T16:32:55.505Z
|
|
||||||
|
|
||||||
(node:205151) [TEST01] CUSTOM: TestWarningMessage
|
|
||||||
at Object.<anonymous> (catchWarning.js:15:17)
|
|
||||||
...
|
|
||||||
at node:internal/main/run_main_module:22:47
|
|
||||||
Some additional detail
|
|
||||||
Above Warning Date: Tue, 31 Dec 2024 10:20:30 GMT
|
|
||||||
*/
|
|
|
@ -1,309 +0,0 @@
|
||||||
const assert = require('assert');
|
|
||||||
const { execFile } = require('child_process');
|
|
||||||
|
|
||||||
const stderrUtils = require('../../lib/stderrUtils');
|
|
||||||
|
|
||||||
/** Simple regex for ISO YYYY-MM-DDThh:mm:ss.sssZ */
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const defaultDateRegex = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)/;
|
|
||||||
|
|
||||||
// eslint-disable-next-line valid-jsdoc
|
|
||||||
/** another format: Tue, 31 Dec 2024 10:20:30 GMT */
|
|
||||||
const customDate = () => new Date('2024-12-31T10:20:30.444Z').toUTCString();
|
|
||||||
|
|
||||||
describe('stderrUtils', () => {
|
|
||||||
const errStackRegex = /Error: TestingError\n(?:.*\sat\s.*\n)+/;
|
|
||||||
|
|
||||||
describe('defaultTimestamp', () => {
|
|
||||||
it('should match ISO format', () => {
|
|
||||||
assert.match(stderrUtils.defaultTimestamp(), defaultDateRegex);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('printErrorWithTimestamp', () => {
|
|
||||||
let stderrText;
|
|
||||||
const originalStderrWrite = process.stderr.write;
|
|
||||||
const mockedStderrWrite = text => { stderrText = text; return true; };
|
|
||||||
const err = new Error('TestingError');
|
|
||||||
const origin = 'uncaughtException';
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
stderrText = undefined;
|
|
||||||
process.stderr.write = mockedStderrWrite;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
process.stderr.write = originalStderrWrite;
|
|
||||||
stderrText = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it(
|
|
||||||
'should write to stderr with current date, origin and stacktrace',
|
|
||||||
() => {
|
|
||||||
const written = stderrUtils
|
|
||||||
.printErrorWithTimestamp(err, origin);
|
|
||||||
|
|
||||||
assert.strictEqual(written, true);
|
|
||||||
const [firstLine, errStack] = stderrText.split(':\n');
|
|
||||||
const [errDate, errOrigin] = firstLine.split(': ');
|
|
||||||
|
|
||||||
assert.match(errDate, defaultDateRegex);
|
|
||||||
assert.strictEqual(errOrigin, origin);
|
|
||||||
assert.strictEqual(errStack, `${err.stack}\n`);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
it(
|
|
||||||
'should write to stderr with custom date, origin and stacktrace',
|
|
||||||
() => {
|
|
||||||
const written = stderrUtils
|
|
||||||
.printErrorWithTimestamp(err, origin, customDate());
|
|
||||||
|
|
||||||
assert.strictEqual(written, true);
|
|
||||||
const [firstLine, errStack] = stderrText.split(':\n');
|
|
||||||
const [errDate, errOrigin] = firstLine.split(': ');
|
|
||||||
|
|
||||||
assert.strictEqual(errDate, customDate());
|
|
||||||
assert.strictEqual(errOrigin, origin);
|
|
||||||
assert.strictEqual(errStack, `${err.stack}\n`);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const execOptions = {
|
|
||||||
cwd: __dirname,
|
|
||||||
// Subprocess should always stop alone
|
|
||||||
// But just in case, kill subprocess after 500ms.
|
|
||||||
// Leave enough time for `nyc` that runs slower.
|
|
||||||
timeout: 500,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute in another process to notice the process exit
|
|
||||||
// Therefore, looks more like a functional test
|
|
||||||
const timeoutHint = (ms, retries) =>
|
|
||||||
`Test fixture process timed out after ${ms}ms with ${retries} retries.\n` +
|
|
||||||
'Due to nyc coverage first run slowing down process.\nIncrease execOptions.timeout to fix';
|
|
||||||
|
|
||||||
describe('catchAndTimestampUncaughtException', () => {
|
|
||||||
[
|
|
||||||
{ desc: 'with default date' },
|
|
||||||
{ desc: 'with custom date', date: customDate() },
|
|
||||||
{ desc: 'with custom exitCode 42', exitCode: 42 },
|
|
||||||
{ desc: 'without exit on uncaught exception', exitCode: null },
|
|
||||||
{ desc: 'for unhandled promise', promise: true },
|
|
||||||
].forEach(({
|
|
||||||
desc, date, exitCode, promise,
|
|
||||||
}) => describe(desc, () => {
|
|
||||||
/** for before all hook that doesn't support this.retries */
|
|
||||||
let retries = 4;
|
|
||||||
let err;
|
|
||||||
let stdout;
|
|
||||||
let stderr;
|
|
||||||
let errStack;
|
|
||||||
let errDate;
|
|
||||||
let errOrigin;
|
|
||||||
|
|
||||||
before('run process catchUncaughtException', function beforeAllHook(done) {
|
|
||||||
execFile(
|
|
||||||
'./fixtures/stderrUtils/catchUncaughtException.js',
|
|
||||||
[`${date}`, `${exitCode}`, `${promise}`],
|
|
||||||
execOptions,
|
|
||||||
(subErr, subStdout, subStderr) => {
|
|
||||||
if (subErr?.killed) {
|
|
||||||
retries--;
|
|
||||||
if (retries <= 0) {
|
|
||||||
assert.fail(timeoutHint(execOptions.timeout, retries));
|
|
||||||
}
|
|
||||||
execOptions.timeout *= 2;
|
|
||||||
return beforeAllHook(done);
|
|
||||||
}
|
|
||||||
err = subErr;
|
|
||||||
stdout = subStdout;
|
|
||||||
stderr = subStderr;
|
|
||||||
let firstLine;
|
|
||||||
[firstLine, errStack] = stderr.split(':\n');
|
|
||||||
[errDate, errOrigin] = firstLine.split(': ');
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exitCode === null) {
|
|
||||||
it('should not be an error (or timeout)',
|
|
||||||
() => assert.ifError(err));
|
|
||||||
it('should have stdout (printed after uncaught exception)',
|
|
||||||
() => assert.match(stdout,
|
|
||||||
/^.*EXECUTED AFTER UNCAUGHT EXCEPTION(?:.|\n)*$/));
|
|
||||||
} else {
|
|
||||||
it('should be an error',
|
|
||||||
() => assert.ok(err));
|
|
||||||
it(`should have exitCode ${exitCode || 1}`,
|
|
||||||
() => assert.strictEqual(err.code, exitCode || 1));
|
|
||||||
it('should have empty stdout',
|
|
||||||
() => assert.strictEqual(stdout, ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should have stderr',
|
|
||||||
() => assert.ok(stderr));
|
|
||||||
it('should have date in stderr first line',
|
|
||||||
() => (date
|
|
||||||
? assert.strictEqual(errDate, date)
|
|
||||||
: assert.match(errDate, defaultDateRegex)));
|
|
||||||
|
|
||||||
it('should have origin in stderr first line',
|
|
||||||
() => (promise === true
|
|
||||||
? assert.strictEqual(errOrigin, 'unhandledRejection')
|
|
||||||
: assert.strictEqual(errOrigin, 'uncaughtException')));
|
|
||||||
|
|
||||||
if (!promise) {
|
|
||||||
it('should have stack trace on stderr',
|
|
||||||
() => assert.match(errStack, errStackRegex));
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('catchAndTimestampWarning (also tests node onWarning)', () => {
|
|
||||||
[
|
|
||||||
{ desc: 'with default date' },
|
|
||||||
{ desc: 'with custom date', date: customDate() },
|
|
||||||
{ desc: 'with deprecation warning', name: 'DeprecationWarning' },
|
|
||||||
{
|
|
||||||
desc: 'with custom warning',
|
|
||||||
name: 'CUSTOM',
|
|
||||||
code: 'TEST01',
|
|
||||||
detail: 'Some additional detail',
|
|
||||||
},
|
|
||||||
].forEach(({
|
|
||||||
desc, date, name, code, detail,
|
|
||||||
}) => describe(desc, () => {
|
|
||||||
/** for before all hook that doesn't support this.retries */
|
|
||||||
let retries = 4;
|
|
||||||
let err;
|
|
||||||
let stdout;
|
|
||||||
let stderr;
|
|
||||||
|
|
||||||
before('run process catchWarning', function beforeAllHook(done) {
|
|
||||||
execFile(
|
|
||||||
'./fixtures/stderrUtils/catchWarning.js',
|
|
||||||
[`${date}`, `${name}`, `${code}`, `${detail}`],
|
|
||||||
execOptions,
|
|
||||||
(subErr, subStdout, subStderr) => {
|
|
||||||
if (subErr?.killed) {
|
|
||||||
retries--;
|
|
||||||
if (retries <= 0) {
|
|
||||||
assert.fail(timeoutHint(execOptions.timeout, retries));
|
|
||||||
}
|
|
||||||
execOptions.timeout *= 2;
|
|
||||||
return beforeAllHook(done);
|
|
||||||
}
|
|
||||||
err = subErr;
|
|
||||||
stdout = subStdout;
|
|
||||||
stderr = subStderr;
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not be an error (or timeout)',
|
|
||||||
() => assert.ifError(err));
|
|
||||||
it('should have empty stdout',
|
|
||||||
() => assert.strictEqual(stdout, ''));
|
|
||||||
it('should have stderr',
|
|
||||||
() => assert.ok(stderr));
|
|
||||||
it('should have message on stderr first line, then stack trace',
|
|
||||||
() => assert.match(stderr,
|
|
||||||
/^.*TestWarningMessage\n(?:\s+at\s.*\n)+/));
|
|
||||||
|
|
||||||
if (code) {
|
|
||||||
it('should have code on stderr first line',
|
|
||||||
() => assert.match(stderr, new RegExp(`^.*[${code}]`)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
it('should have name on stderr first line',
|
|
||||||
() => assert.match(stderr, new RegExp(`^.*${name}:`)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (detail) {
|
|
||||||
it('should have detail on stderr',
|
|
||||||
() => assert.match(stderr, new RegExp(`.*${detail}.*`)));
|
|
||||||
}
|
|
||||||
|
|
||||||
it(`should have ${date ? 'custom' : 'default'} date on stderr`,
|
|
||||||
() => assert.match(stderr, new RegExp(
|
|
||||||
`\nAbove Warning Date: ${
|
|
||||||
date || defaultDateRegex.source}\n`,
|
|
||||||
)));
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('catchAndTimestampStderr', () => {
|
|
||||||
[
|
|
||||||
{ desc: 'with default date' },
|
|
||||||
{ desc: 'with custom date', date: customDate() },
|
|
||||||
{ desc: 'with exit code', exitCode: 42 },
|
|
||||||
|
|
||||||
].forEach(({
|
|
||||||
desc, date, exitCode,
|
|
||||||
}) => describe(desc, () => {
|
|
||||||
/** for before all hook that doesn't support this.retries */
|
|
||||||
let retries = 4;
|
|
||||||
let err;
|
|
||||||
let stdout;
|
|
||||||
let stderr;
|
|
||||||
|
|
||||||
before('run process catchStderr', function beforeAllHook(done) {
|
|
||||||
execFile(
|
|
||||||
'./fixtures/stderrUtils/catchStderr.js',
|
|
||||||
[`${date}`, `${exitCode}`],
|
|
||||||
execOptions,
|
|
||||||
(subErr, subStdout, subStderr) => {
|
|
||||||
if (subErr?.killed) {
|
|
||||||
retries--;
|
|
||||||
if (retries <= 0) {
|
|
||||||
assert.fail(timeoutHint(execOptions.timeout, retries));
|
|
||||||
}
|
|
||||||
execOptions.timeout *= 2;
|
|
||||||
return beforeAllHook(done);
|
|
||||||
}
|
|
||||||
err = subErr;
|
|
||||||
stdout = subStdout;
|
|
||||||
stderr = subStderr;
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be an error',
|
|
||||||
() => assert.ok(err));
|
|
||||||
it(`should have exitCode ${exitCode || 1}`,
|
|
||||||
() => assert.strictEqual(err.code, exitCode || 1));
|
|
||||||
it('should have empty stdout',
|
|
||||||
() => assert.strictEqual(stdout, ''));
|
|
||||||
|
|
||||||
it('should have stderr',
|
|
||||||
() => assert.ok(stderr));
|
|
||||||
|
|
||||||
// 2024-06-26T15:04:55.364Z: uncaughtException:
|
|
||||||
// Error: TestingError
|
|
||||||
// at Object.<anonymous> (catchStderr.js:16:7)
|
|
||||||
// at node:internal/main/run_main_module:22:47
|
|
||||||
it('should have error date, origin and stacktrace in stderr',
|
|
||||||
() => assert.match(stderr,
|
|
||||||
new RegExp(`${date || defaultDateRegex.source
|
|
||||||
}: uncaughtException:\n${errStackRegex.source}`)));
|
|
||||||
|
|
||||||
// (node:171245) Warning: TestWarningMessage
|
|
||||||
// at Object.<anonymous> (catchStderr.js:14:9)
|
|
||||||
// at node:internal/main/run_main_module:22:47
|
|
||||||
// Above Warning Date: 2024-06-26T15:04:55.365Z
|
|
||||||
it('should have warning with stacktrace in stderr', () => {
|
|
||||||
const trace = 'Warning: TestWarningMessage\n(?:\\s+at\\s.*\n)+';
|
|
||||||
const detail = `(?:.|\n)*?(?<=\n)Above Warning Date: ${
|
|
||||||
date || defaultDateRegex.source}\n`;
|
|
||||||
assert.match(stderr,
|
|
||||||
new RegExp(`${trace}${detail}`));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -618,9 +618,9 @@ camelcase@^6.0.0:
|
||||||
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
|
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001259:
|
caniuse-lite@^1.0.30001259:
|
||||||
version "1.0.30001637"
|
version "1.0.30001261"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001637.tgz"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001261.tgz#96d89813c076ea061209a4e040d8dcf0c66a1d01"
|
||||||
integrity sha512-1x0qRI1mD1o9e+7mBI7XtzFAP4XszbHaVWsMiGbSPLYekKTJF7K+FNk6AsXH4sUpc+qrsI3pVgf1Jdl/uGkuSQ==
|
integrity sha512-vM8D9Uvp7bHIN0fZ2KQ4wnmYFpJo/Etb4Vwsuc+ka0tfGDHvOPrFm6S/7CCNLSOkAUjenT2HnUPESdOIL91FaA==
|
||||||
|
|
||||||
catharsis@^0.8.11:
|
catharsis@^0.8.11:
|
||||||
version "0.8.11"
|
version "0.8.11"
|
||||||
|
|
Loading…
Reference in New Issue