-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
test: refactor expectsError #14058
test: refactor expectsError #14058
Conversation
Where do we use this behavior? |
@tniessen every error thrown by assert have a couple more properties and currently they are tested only for assert.fail. In general I think it makes sense to test for everything that is requested for and not only for some of these properties. |
test/common/index.js
Outdated
assert.strictEqual(error.message, message); | ||
} | ||
} else { | ||
assert.strictEqual(error[key], options[key]); |
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'm thinking this needs a custom message The ${key} field of ${error} was ${error[key]} and not {options[key]} as expected
(or a little bit shorter)
Otherwise we get an AssertionError: a !== b
thrown from deep within the harness.
So the same applies for L716 and the message
strings.
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.
Done
test/common/index.js
Outdated
assert.strictEqual(error.message, message); | ||
} | ||
Object.keys(options).forEach((key) => { | ||
if (key === 'type') { |
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.
Would a switch
look better?
New code looks real pretty 💅
test/common/index.js
Outdated
assert(error instanceof type, | ||
`${error} is not the expected type ${type}`); | ||
} | ||
} else if (key === 'message') { |
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.
If we keep the if/else
change to (key === 'message' && options.message instanceof RegExp)
and let the string case fall to the else
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.
Done
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'm (not strongly) -1 on this change. I don't think every single property should match the options.
It complicates the code a little and I'm not sure this is a good idea.
Well I guess the point is to make it flexible. Instead of forcing at max |
I understand the point and appreciate the effort - but I think it makes the code more confusing for no good reason at the moment - and I can see the pitfalls of tests failing after an object is passed and a property is added unintentionally. If it was called |
It will fail also as is with unintentionally added properties ( |
@benjamingr I ran into this with another PR as I wanted to test additional properties than just You have to explicitly list every property that you want to test for and if you do not want to test any besides e.g. const err = new Error('foobar')
err.code = 'RANDOM'
err.additional = true
err.foobar = 'is ignored'
// Tests only code
common.expectsError({
code: 'RANDOM'
})(err)
// Tests other properties
common.expectsError({
code: 'RANDOM',
additional: true
type: Error
})(err) |
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.
💯
As I see it the crux of the issue is that the new The main problem with the current code is the destructuring of the formal agrument: P.S. @benjamingr IMHO the new version of the code is almost as succinct as the code before... and fixes the problem of unuseful messages.. so⚖️ Ref: #13686 |
Also relevant #13937 if message change are |
test/common/index.js
Outdated
const actual = error[key]; | ||
const expected = options[key]; | ||
if (key === 'type') { | ||
if (expected !== undefined) { |
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.
If it was called
.expects
and not.expectsError
or just deepEqual I would understand.
That made me think, remove the if
and that will make options.type
mandatory.
Also add assert(expected instanceof Error)
if (!(expected instanceof Error)) throw new TypeError('`options.type` must inherit from `Error`');
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.
That does not work as the class is passed to the function and not the instance. The simplest check I could though of is: expected !== Error && !Error.isPrototypeOf(expected)
@BridgeAR I don't want to mix 🍎s and 🍊s, but we should actually add a validation that |
01d4c28
to
a635532
Compare
Rebased due to conflicts and I updated the documentation as I missed that. @benjamingr would you mind having another look? |
I'm fine with asserting that it's an instance of an error - but I'm not sure about testing all properties. I'm concerned about cases where a "dirty" error object would be passed and it would verify incorrect things by mistake. I'm not sure I see the value this adds to be honest. The method is already a little footgunny for verifying things by convention - going over all object properties and treating some of them differently doesn't sound like good design to me. |
I'm not sure I understand what you mean with the "dirty" error object. Do you mean the As you can see there is no change needed for any test and the function will only test properties explicitly asked for in the For me the current situation was a minor footgun by not testing properties that I wanted it to test for. |
I mean someone passing a |
Ack. Probably the best thing would be to add |
test/common/README.md
Outdated
* `type` [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) | ||
expected error must be an instance of `type` | ||
expected error must be an instance of `type` and should be [subclassed by | ||
the `internal/errors` module](https://github.com/nodejs/node/blob/master/doc/guides/using-internal-errors.md#api). |
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.
This additional bit subclassed by the 'internal/errors' module
doesn't really make sense. The thing must be an instance of type
and must be an Error
subclass. Whether it is a subclass of one of the internal/errors.js
classes is somewhat inconsequential.
test/common/README.md
Outdated
|
||
The expected error should be [subclassed by the `internal/errors` module](https://github.com/nodejs/node/blob/master/doc/guides/using-internal-errors.md#api). | ||
* return [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) | ||
If `fn` is provided, it will be passed to `assert.throws` as first argument |
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.
Need a blank line after the * return
line... and it should be * Returns:
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 * Returns:
would be inconsistent with all other entries in this file. Shall I change all other entries as well?
a635532
to
82d6c48
Compare
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.
New version not using Object.keys
looks good to me
I completely reworked the code as suggested by @refack |
I had this whole spiel about flattening
|
f411221
to
00479f6
Compare
Rebased. @refack could this land or do you want me to still change something? |
Didn't see that the CR was dismissed. |
PR-URL: nodejs#14058 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Landed in 2a621d4 |
Extra sanity run on |
Should this be backported to |
This function does not exist in v.6 so backporting is obsolete. |
So far common.expectsError only tested
type
,message
andcode
instead of all properties.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
test