-
-
Notifications
You must be signed in to change notification settings - Fork 699
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
Remove implementation frames from stack trace #922
Conversation
46a1c6b
to
c1a08c8
Compare
Pinging @keithamus @lucasfcosta @vieiralucas @shvaikalesh for review :D |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome job! Very clean implementation.
I also liked the tests, I think they cover all the edge cases and general functioning of this change.
I think, however, that some minor details in docstrings and error messages should be changed.
I left a few other comments throughout the code with suggestions and my thoughts on this matter.
I also tried to find any nested assertion invocations that did not set the keep_ssfi
flag but I couldn't find any.
Thanks for your work @meeber!
// Setting the `ssfi` flag to `chainableMethodWrapper` causes this | ||
// function to be the starting point for removing implementation | ||
// frames from the stack trace of a failed assertion. | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me see if I get this:
If we're dealing with a "single-level" assertion it is okay to remove these frames from the stack since they're irrelevant due to the fact that they're just calling the assertion's inner routine, but if we're dealing with "nested" assertions (assertions that call other assertions) we must not remove this because we need to have the frames from before calling this function (which is the topmost assertion's code).
Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ssfi
flag should always contain a reference to the lowest internal Chai frame in the stack, because that frame and all frames above it will be filtered out. In other words, the very first Chai internal function that gets hit in an assertion should set the ssfi
flag, and any functions after that shouldn't mess with the ssfi
flag.
For example:
expect({foo: 1}).to.include({foo: 1});
- When
expect({foo: 1})
gets called,ssfi
isundefined
. - When
.to
gets called,ssfi
gets set to either theproxyGetter
orpropertyGetter
function for.to
, depending on whether on not proxies are supported and enabled. Note that.to
doesn't call any more internal Chai functions, so we're done with this step. But if it did happen to call more internal Chai functions, then it'd freeze it'sssfi
before calling them since we want to keepssfi
pointing at the first internal Chai function that gets hit when.to
is invoked. - When
.include
gets called,ssfi
gets set to thechainableMethodWrapper
function for.include
. Now,.include
calls the.property
assertion internally, so we freezessfi
before calling.property
since we want to keepssfi
pointing at the first internal Chai function that gets hit when.include
is invoked.
lib/chai/utils/expectTypes.js
Outdated
@@ -13,6 +13,8 @@ | |||
* | |||
* @param {Mixed} obj constructed Assertion | |||
* @param {Array} type A list of allowed types for this assertion | |||
* @param {fn} ssfi starting point for removing implementation frames from stack |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it @param {Function}
instead of @param {fn}
?
test/globalErr.js
Outdated
throw Error(); | ||
}); | ||
} catch (e) { | ||
throw Error("This should never happen"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps these error messages here could be a little more descriptive to ease bug detection/interpretation.
test/globalErr.js
Outdated
throw Error(); | ||
}, undefined, true); | ||
} catch (e) { | ||
throw Error("This should never happen"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same goes for the Error
s below.
c1a08c8
to
2999156
Compare
Pushed a new version. Changes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome job @meeber!
The variable name change was much better than what I suggested, lock
is really the right word for this. Very well thought.
Also, by reading the code I think that we have too many comments explaining simple tests, especially because some of them are almost identical versions of each other. IMO this adds unnecessary noise to the code and makes it more laborious to maintain (as I explained in another comment).
However, I won't reject these changes because of that, but please, if you agree with these opinions, let us know.
test/globalErr.js
Outdated
// is being asserted on. Instead, if a test is failing, then Mocha will pick | ||
// up the error that's thrown by `err`. | ||
describe('falsey', function () { | ||
// The inner `err` executes `myGetter` and catches the thrown error. But |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need these comments.
They are really well written, but I think it is very easy to understand what is happening just by reading the code. If we have too many comments on the code it just makes it more difficult to maintain because we gotta make sure we update all the related comments, otherwise they will tell a different story than the code does.
IMO the outer code is okay, but this one (inner one) seems too much.
Anyway, I won't reject this PR because of this, please let me know what you think about it. 😄
test/globalErr.js
Outdated
}, undefined, true); | ||
}); | ||
|
||
// `err` executes `myWrapper` and catches the thrown error. Since |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments are almost all the same, I think it adds a lot of noise to the code, especially because one of them would already be enough, but even more because now that we've got more descriptive error messages and awesome test case descriptions that already do the job of conveying the message we want it to.
Pushed new version with excessive comments removed. (Changed it in a new commit instead of rebase in case we change mind in future). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks much cleaner now!
Excellent work 😄
LGTM, let's wait for another review to merge this.
this article refers to this pr http://lucasfcosta.com/2017/02/17/JavaScript-Errors-and-Stack-Traces.html |
@keithamus I made that note to myself yesterday :D I'll update this PR after work! |
- Allows the `keep_ssfi` flag to be set when creating new Assertion objects by providing its value as the fourth argument. - Updates the `transferFlags` util to only transfer `keep_ssfi` when the `includeAll` argument is set to `true`. - Updates assertion creation and proxify utils to only set `ssfi` if `keep_ssfi` isn't set. - Updates inline docs to reflect expanded usage of `keep_ssfi`.
- Make it so that only `AssertionError` is thrown from inside of an assertion - Always pass the current `ssfi` to a `new AssertionError` inside of an assertion - Always pass the current `ssfi` to a new `Assertion` inside of an assertion, and set the `keep_ssfi` flag - Improve the `globalErr` test helper function to also validate that the thrown error's stack trace doesn't contain implementation frames
- Make it so that only `AssertionError` is thrown from inside of an assert interface wrapper function - Always set `ssfi` to the current function when creating a new `AssertionError` inside of an assert interface wrapper function - Always set `ssfi` to the current function when creating a new `Assertion` inside of an assert interface wrapper function, and set the `keep_ssfi` flag - Improve the `globalErr` test helper function to also validate that the thrown error's stack trace doesn't contain frames from the assert interface
42ff3c0
to
a253b4c
Compare
@keithamus @shvaikalesh @vieiralucas @lucasfcosta Rebased since #899 was merged. As expected, some I think this PR is ready to go. After this is merged, there will be a follow-up PR related to messages. |
LGTM! |
@keithamus @shvaikalesh @vieiralucas Need a second review on this one! |
LGTM @meeber! Great work, it's not always glamorous to do this kind of work, but it's definitely needed. That's one of the many reasons you're such a valuable contributor 😘 👍 💯 |
Note to self: Rebase after #899 is merged and update to turn
Error
into anAssertionError
that properly retains ssfi. A follow up PR will properly retain the user's custom message here and elsewhere.This PR is split into five commits:
Expand the role of the
keep_ssfi
flag so that it's easier to tell Chai not to overwrite an existingssfi
when it shouldn't, such as when an assertion is being called from within another assertion, or when an assertion is wrapped in a function such as every assertion on theassert
interface.Fix all issues on
expect
/should
interfaces that were causing implementation frames to leak through. Also improve the internal Chai error test helper to validate stack traces.Fix all issues on
assert
interface that were causing implementation frames to leak through. Further improve the internal Chai error test helper to validate stack traces.Rename
keep_ssfi
flag tolockSsfi
.Clean up excessive test comments.
Closes #878
Closes #904