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

assert: handle class constructors in throws() #4168

Closed
wants to merge 1 commit into from

Conversation

cjihrig
Copy link
Contributor

@cjihrig cjihrig commented Dec 6, 2015

Currently, if a class constructor is passed as the expected value to throws(), and a match is not received, the code falls through to the validation function case, which uses fn.prototype.call(). Class constructors must be called with new, so this throws a TypeError. This commit adds a try...catch, which handles the thrown error.

I'm proposing this as an alternative to #4166. The drawback I see with #4166 is that it only handles classes which extend Error. In general, it might be a good thing to wrap user defined validation functions in a try...catch anyway. Closes #3188.

Currently, if a class constructor is passed as the expected value
to throws(), and a match is not received, the code falls through
to the validation function case, which uses fn.prototype.call().
Class constructors must be called with new, so this throws a
TypeError. This commit adds a try...catch, which handles the
thrown error.
@JungMinu JungMinu added the assert Issues and PRs related to the assert subsystem. label Dec 6, 2015
return expected.call({}, actual) === true;
} catch (e) {
// Ignore. If expected is a class constructor, an error will be thrown
}
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean that assert.throws() will now ignore all errors thrown by the validation function? (And are there semver implications to such a change? Wouldn't we want things like ReferenceError to bubble up to the user?)

Copy link
Member

Choose a reason for hiding this comment

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

I agree, this seems dangerous. You could rethrow unless e instanceof TypeError && /Class constructors cannot be invoked without 'new'/.test(e.message) but that changes the throw site and can still swallow genuine TypeErrors from the expected callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are definitely semver implications. I don't have strong feelings about this PR. To be honest, I'd rather close it than special case and rethrow errors.

Copy link
Member

Choose a reason for hiding this comment

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

For what it's worth, and likely not telling anyone anything they don't already know, the "proper" fix is probably something like:

  • Unlock API
  • Change function signature to add an options object and the user can send a validation option and/or a constructor option for an object that the thrown error must match
  • Relock the API

That could be done in a semver-minor way if we leave the legacy behavior intact, bug and all.

I'm not necessarily recommending that route--the API was locked for a reason--but just saying: If we want to fix it "right", the solution probably looks something like that...

@mscdex
Copy link
Contributor

mscdex commented Dec 6, 2015

CI is all green except for some flaky, unrelated Windows tests.

@cjihrig cjihrig closed this Dec 6, 2015
@cjihrig cjihrig deleted the throw branch December 6, 2015 18:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert Issues and PRs related to the assert subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants