Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#3320 Native types exceptions can crash Mocha runner #3321

Closed
wants to merge 2 commits into from

Conversation

fargies
Copy link
Contributor

@fargies fargies commented Apr 12, 2018

Any non-extensible type thrown in an async callback raises an exception in Mocha runner, stopping tests.

See issue #3320

Requirements

  • Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
  • All new code requires tests to ensure against regressions.

Description of the Change

Alternate Designs

Why should this be in core?

Benefits

Tests continue and reports errors properly

Possible Drawbacks

Applicable issues

@coveralls
Copy link

coveralls commented Apr 12, 2018

Coverage Status

Coverage increased (+0.05%) to 90.063% when pulling 41fe763 on fargies:master into 1acea30 on mochajs:master.

Copy link
Member

@boneskull boneskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for the PR.

Mocha does not (and will not) support throwing of anything except an Error or Error-like object.

If you wish to modify this PR, you could perform a check as seen here which re-throws the value as an Error (and sets the uncaught property).

@boneskull boneskull added area: usability concerning user experience or interface semver-minor implementation requires increase of "minor" version number; "features" labels Apr 12, 2018
@fargies
Copy link
Contributor Author

fargies commented Apr 12, 2018

You're right, with the modification uncaught was not set once transformed into an Error.

Patch modified accordingly.

@@ -26,6 +26,24 @@ describe('a test that throws', function () {
});
});

describe('extensible', function () {
it('should not crash if throwing non-extensible type', function (done) {
var test = new Test('im async and throw string async', function (done2) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done2 is unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither it is in several places in the same file (I just reused an existing test), see :

The linter doesn't seem to report it for some reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's normal to have done2 argument there to make the test an async test.

I added eslint-ignore comments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops! I got it.
It needed to make the test as async as you said.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment makes it clearer, so it's better anyway :)

@fargies
Copy link
Contributor Author

fargies commented Apr 13, 2018

unused arguments are not checked by the linter, I'd recommend you to add the following lines at the end of your .eslintrc.yml file:

  no-unused-vars:
    - error
    - args: after-used

I have the following result:

.../mocha/lib/interfaces/common.js
  13:45  error  'mocha' is defined but never used  no-unused-vars

.../mocha/test/browser/large.spec.js
  27:49  error  'done' is defined but never used  no-unused-vars

.../mocha/test/integration/fixtures/simple-reporter.js
   9:32  error  'suite' is defined but never used  no-unused-vars
  13:37  error  'err' is defined but never used    no-unused-vars
  17:31  error  'test' is defined but never used   no-unused-vars
  21:41  error  'err' is defined but never used    no-unused-vars

.../mocha/test/integration/hook-err.spec.js
  215:26  error  'line' is defined but never used  no-unused-vars

.../mocha/test/integration/reporters.spec.js
  49:54  error  'result' is defined but never used  no-unused-vars

.../mocha/test/jsapi/index.js
  27:25  error  'test' is defined but never used  no-unused-vars

.../mocha/test/node-unit/color.spec.js
  12:77  error  'stderr' is defined but never used  no-unused-vars

.../mocha/test/reporters/helpers.js
  136:3  error  'expectedBody' is defined but never used  no-unused-vars

.../mocha/test/unit/runnable.spec.js
  101:47  error  'done' is defined but never used      no-unused-vars
  289:52  error  'done' is defined but never used      no-unused-vars
  300:52  error  'done' is defined but never used      no-unused-vars
  314:52  error  'done' is defined but never used      no-unused-vars
  370:50  error  'done' is defined but never used      no-unused-vars
  388:38  error  'rejected' is defined but never used  no-unused-vars
  404:38  error  'rejected' is defined but never used  no-unused-vars

.../mocha/test/unit/throw.spec.js
   31:72  error  'done2' is defined but never used  no-unused-vars
   63:74  error  'done2' is defined but never used  no-unused-vars
   77:75  error  'done2' is defined but never used  no-unused-vars
  109:69  error  'done2' is defined but never used  no-unused-vars
  123:70  error  'done2' is defined but never used  no-unused-vars

Not sure that those aren't false-positive, and definitely not related to this modification, so won't touch this here.

@plroebuck
Copy link
Contributor

Would prefer no-unused-vars: ["error", { "args": "none" }] if "eslint" can't add a different rule that can tell the difference between variables and function arguments. The function signature is just that -- if you don't use all its arguments, that's not an error.

@boneskull boneskull force-pushed the master branch 2 times, most recently from 4547268 to 7613521 Compare May 4, 2018 16:47
lib/runner.js Outdated
@@ -704,6 +704,9 @@ Runner.prototype.uncaught = function (err) {
debug('uncaught undefined exception');
err = undefinedError();
}
if (!(err instanceof Error || (err && typeof err.message === 'string'))) {
err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
Copy link
Contributor

@plroebuck plroebuck Aug 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe create a string2Error function and have both .uncaught() [here] and .fail() [here] call it? DRY.

@@ -26,6 +26,25 @@ describe('a test that throws', function () {
});
});

describe('extensible', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ticky-tack, but aren't you rather testing "non-extensible"?

throw 'error';
});
});
suite.addTest(test);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly outside the scope, but rather than repeating these lines over and over, why don't we just use a function runTest(test, done) instead?

@plroebuck
Copy link
Contributor

@fargies, I like this PR (making async work like sync). But it may be problematic to integrate. Typical workflow would be to create a local issue-related branch (e.g., "issue3320"), make your changes there, then push that branch to GitHub for the PR. Then the GitHub (remote) branch is eventually merged into a release. But not directly to master.

 - Any non-extensible type thrown in an async callback raises an exception in
 Mocha runner, stopping tests.
@fargies
Copy link
Contributor Author

fargies commented Aug 30, 2018

Modification updated.

I can rename my remote branch, but where should I make a merge request ?

@fargies fargies force-pushed the master branch 2 times, most recently from bf19d09 to b7acffa Compare August 30, 2018 10:38
' was thrown, throw an Error :)'
);
}
err = string2Error(err);
Copy link
Contributor

@plroebuck plroebuck Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhere else in the code, let's have:

/**
 * Check if argument is an instance of Error object or a duck-typed equivalent.
 *
 * @private
 * @param {Object} err - object to check
 * @param {string} err.message - error message
 * @returns {boolean}
 */
function isError(err) {
  return err instanceof Error || (err && typeof err.message === 'string');
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And replace the check so it's clear why the other routine would be called.

  if (!isError(err)) {
    err = thrown2Error(err);
  }

' was thrown, throw an Error :)'
);
}
err = string2Error(err);
Copy link
Contributor

@plroebuck plroebuck Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And again...

  if (!isError(err)) {
    err = thrown2Error(err);
  }

* @param {Object} err
* @return {Error}
*/
function string2Error(err) {
Copy link
Contributor

@plroebuck plroebuck Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed for added clarity.

/**
 * Converts thrown non-extensible type into proper Error.
 *
 * @private
 * @param {*} thrown - Non-extensible type thrown by code
 * @return {Error}
 */
function thrown2Error(thrown) {
  return new Error(
    'the ' +
    type(thrown) +
    ' ' +
    stringify(thrown) +
    ' was thrown, throw an Error :)'
  );
}

@plroebuck
Copy link
Contributor

Rename your remote branch "issue3320" after updates.

@fargies
Copy link
Contributor Author

fargies commented Aug 31, 2018

New pull request from issue3320 branch -> #3471

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: usability concerning user experience or interface semver-minor implementation requires increase of "minor" version number; "features"
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants