Skip to content

Commit

Permalink
fix: Ensure crash error messages are not duplicated (#17584)
Browse files Browse the repository at this point in the history
* fix: Ensure crash error messages are not duplicated

Fixes #17560

* Add test

* Fix merge conflicts

* Add tests

---------

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
  • Loading branch information
nzakas and mdjermanovic committed Oct 6, 2023
1 parent ee5be81 commit 0edfe36
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 4 deletions.
19 changes: 15 additions & 4 deletions bin/eslint.js
Expand Up @@ -92,6 +92,14 @@ function getErrorMessage(error) {
return util.format("%o", error);
}

/**
* Tracks error messages that are shown to the user so we only ever show the
* same message once.
* @type {Set<string>}
*/

const displayedErrors = new Set();

/**
* Catch and report unexpected error.
* @param {any} error The thrown error object.
Expand All @@ -101,14 +109,17 @@ function onFatalError(error) {
process.exitCode = 2;

const { version } = require("../package.json");
const message = getErrorMessage(error);

console.error(`
const message = `
Oops! Something went wrong! :(
ESLint: ${version}
${message}`);
${getErrorMessage(error)}`;

if (!displayedErrors.has(message)) {
console.error(message);
displayedErrors.add(message);
}
}

//------------------------------------------------------------------------------
Expand Down
30 changes: 30 additions & 0 deletions tests/bin/eslint.js
Expand Up @@ -387,6 +387,36 @@ describe("bin/eslint.js", () => {
return Promise.all([exitCodeAssertion, outputAssertion]);
});

// https://github.com/eslint/eslint/issues/17560
describe("does not print duplicate errors in the event of a crash", () => {

it("when there is an invalid config read from a config file", () => {
const config = path.join(__dirname, "../fixtures/bin/eslint.config-invalid.js");
const child = runESLint(["--config", config, "conf", "tools"]);
const exitCodeAssertion = assertExitCode(child, 2);
const outputAssertion = getOutput(child).then(output => {

// The error text should appear exactly once in stderr
assert.strictEqual(output.stderr.match(/A config object is using the "globals" key/gu).length, 1);
});

return Promise.all([exitCodeAssertion, outputAssertion]);
});

it("when there is an error in the next tick", () => {
const config = path.join(__dirname, "../fixtures/bin/eslint.config-tick-throws.js");
const child = runESLint(["--config", config, "Makefile.js"]);
const exitCodeAssertion = assertExitCode(child, 2);
const outputAssertion = getOutput(child).then(output => {

// The error text should appear exactly once in stderr
assert.strictEqual(output.stderr.match(/test_error_stack/gu).length, 1);
});

return Promise.all([exitCodeAssertion, outputAssertion]);
});
});

it("prints the error message pointing to line of code", () => {
const invalidConfig = path.join(__dirname, "../fixtures/bin/eslint.config.js");
const child = runESLint(["--no-ignore", "-c", invalidConfig]);
Expand Down
3 changes: 3 additions & 0 deletions tests/fixtures/bin/eslint.config-invalid.js
@@ -0,0 +1,3 @@
module.exports = [{
globals: {}
}];
24 changes: 24 additions & 0 deletions tests/fixtures/bin/eslint.config-tick-throws.js
@@ -0,0 +1,24 @@
function throwError() {
const error = new Error();
error.stack = "test_error_stack";
throw error;
}

module.exports = [{
plugins: {
foo: {
rules: {
bar: {
create() {
process.nextTick(throwError);
process.nextTick(throwError);
return {};
}
}
}
}
},
rules: {
"foo/bar": "error"
}
}];

0 comments on commit 0edfe36

Please sign in to comment.