-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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: adds partialDeepStrictEqual #54630
base: main
Are you sure you want to change the base?
Conversation
466c2f0
to
c0a58e2
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #54630 +/- ##
==========================================
+ Coverage 88.23% 88.41% +0.17%
==========================================
Files 652 654 +2
Lines 183920 187906 +3986
Branches 35863 36165 +302
==========================================
+ Hits 162286 166132 +3846
- Misses 14913 15011 +98
- Partials 6721 6763 +42
|
c0a58e2
to
04e92f0
Compare
The
notable-change
Please suggest a text for the release notes if you'd like to include a more detailed summary, then proceed to update the PR description with the text or a link to the notable change suggested text comment. Otherwise, the commit will be placed in the Other Notable Changes section. |
This PR adds new functionality, hence semver-minor This PR's new functionality (IMO) is notable-change |
04e92f0
to
0ee83d4
Compare
doc/api/assert.md
Outdated
// AssertionError | ||
``` | ||
|
||
## `assert.includes(actual, expected[, 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.
I'm less convinced that this one is useful. Why not just simply use assert(actual.includes(expected))
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.
@jasnell I just followed the most "approved" comment in the original PR and implemented it :)
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 agree with @jasnell and don't think this should be implemented. Let us concentrate on the partial inclusion. If anyone would ever ask for something else, we can still implement more.
is there any way we can push this forward? ar far as I know there is a little bit of people waiting for this and no clear consensus on the naming convention :) |
I still have concerns about whether we need everything in this PR but would very much like others to weigh in. @nodejs/test_runner @nodejs/assert ... anyone have thoughts? |
re naming, I definitely think the term "match" should be reserved for regexes. if the only difference between these new methods and deepEqual etc is that they allow extra properties, then perhaps it would make more sense as an option to the existing methods rather than entirely new ones? |
@ljharb the discussion where the "option" was discarded in favor of the new API started from this comment: #50399 (comment) |
other method names we could consider:
|
To clarify, the current proposal takes an "actual" and "expected", and it checks that every property on What about if I want to assert that a property is not present? is there a way to represent "never"? |
good questions! yes, this test will pass: {
description: 'compares two deeply nested objects with partial equality',
actual: { a: {nested: {property: true, some: 'other'}} },
expected: { a: {nested: {property: true}} },
}, and no, there is no way to check "not inclusion" , just if an object is a subset of another |
|
that would deviate from the already present implementations, like |
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.
implementation LGTM, I agree with the concerns on naming, lets change the name so this can land?
+1 for partialDeepEqual
Agreed. Also, should this have a |
ab7e68e
to
3d52d4b
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.
I just look at this now and I could not find any comments about why we want to have two methods includes()
and partialDeepEqual()
. I think it would be nicer to simplify that and just have partialDeepEqual()
as it should IMO just do the same what includes()
currently does.
Could someone please point me to some discussion around that?
Also, |
doc/api/assert.md
Outdated
// AssertionError | ||
``` | ||
|
||
## `assert.includes(actual, expected[, 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.
WDYT about includes
and includesStrict
?
includesStrict([obj, otherObj], obj)
-> True
includesStrict([{}], {})
-> False
But
includes([obj, otherObj], obj)
-> True
includes([{}], {})
-> True
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.
See #54630 (comment)
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 name does not tell anything about how the comparison works. The original one was about strict equality as in three equal signs. This is about reference equality and I don't think we should do this.
doc/api/assert.md
Outdated
@@ -2548,6 +2548,232 @@ assert.throws(throwingFirst, /Second$/); | |||
Due to the confusing error-prone notation, avoid a string as the second | |||
argument. | |||
|
|||
## `assert.partialDeepEqual(actual, expected[, 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.
The existence of the strict
method is something that is very confusing and I strongly recommend we do not add any "non"-strict version. I could not find anyone asking for this either.
That should never be used. If we ever want to have a different comparison, it should be done by e.g., assert.any(Number)
or similar.
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 give you a whole discussion around wanting this fastify/fastify#5628
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.
@jsumners I am absolutely +1 on adding some kind of partial deep equal comparison as done here. This PR just adds three different APIs while I believe we should only ship the partialDeepStrictEqual
one. I am not a super fan of the name but I know there was a lot of back and forth and it is tricky to find the right name.
@puskin94 what about doing the following as next steps:
- Remove everything besides the current
partialDeepStrictEqual()
implementation. - Have a small poll for the name.
That way we could ship the main requested feature and later on decide if we want to add anything else on top.
I think this is great work and we should definitely ship that functionality!
aaa2b60
to
237cf53
Compare
Small poll about the name of the
👍 partialDeepStrictEqual You can use the emojis above to react on this comment to vote your favorite! |
To determine the best name, I'm thinking of the structure of the method name by looking at two main components:
It's conventional to place the operator at the end of the method name (e.g., deepEqual). The key question is whether this method is a modification of the existing "Equal" operator or if it represents a new operator altogether. If it's a modification of "Equal," the method name would logically be constructed as:
Regarding the modifiers:
With this in mind, a possible name could be However, given that this method operates differently from a standard equality check—specifically, it checks for a subset rather than full equality—it might be better to consider a new operator. The goal is to find an operator that implies recursive comparison and ideally is a single word. Possible operators and considerations:
Final suggestions:
|
@puskin94 See also my reasoning for
|
I understand that |
Using |
I agree with you, I would remove it too, but wouldn't it be more confusing to remove the |
If you don't want |
How do we want to move with this one? |
I've seen this PR open for quite a while. Before this PR, I noticed a very similar discussion in another PR, from which this one originated (#53415). I think that this feature would add significant value to the assertions set, so I strongly believe we should unblock this by deciding on a name. @nodejs/tsc |
@pmarchini are you happy with the proposal in #54630 (comment), or is there a more up-to-date list if it does go to a TSC vote?
We should at least add the one implemented in the PR:
|
Hey @aduh95, absolutely, I also agree with considering IMHO I think we should go with that one, but I’d suggest that everyone involved in this discussion be able to give a "final word" on it by a set deadline 🚀 |
ddac6c3
to
d58ffe7
Compare
I would consider two more candidates for the voting list.
|
We could add the name to the strict export only. That would keep it consistent with the other names. |
lib/assert.js
Outdated
return false; | ||
} | ||
|
||
return ArrayPrototypeEvery(expected, (item) => ArrayPrototypeIncludes(actual, item)); |
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 is actually incorrect. It will match identical parts multiple times. It is also going to have a bad performance.
I am not going to block this though, to get the general idea in and to improve afterwards. Can we just mark it experimental for now, due to these issues?
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.
@BridgeAR this was an actual issue, addressed it!
const key = keysExpected[i]; | ||
assert( | ||
ReflectHas(actual, key), | ||
new AssertionError({ message: `Expected key ${String(key)} not found in actual object` }), |
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 message won't be ideal. If it's a deeper array, it is completely unclear what this belongs to. It was actually my main issue with my first attempt. To highlight what parts are missing is tricky.
if (comparedObjects.has(actual)) { | ||
return true; | ||
} | ||
comparedObjects.add(actual); |
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 did not verify that but I believe the circular structure won't always work this way. AFAIC we have to handle both sides similar to the current implementation.
Fixes: nodejs#50399 Co-Authored-By: Cristian Barlutiu <[email protected]>
d58ffe7
to
c47e009
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.
I think the documentation should precisely characterize the behavior of this function, including edge cases. Right now, it only mentions the "main difference", but that doesn't explain differences such as the following:
assert.deepStrictEqual(new Set([{ a: 1 }]), new Set([{ a: 1 }]))
// No error.
assert.partialDeepStrictEqual(new Set([{ a: 1 }]), new Set([{ a: 1 }]))
// Uncaught AssertionError.
On a side note, the commit message should use an imperative verb (e.g., add
) instead of adds
to comply with our guidelines.
@@ -2548,6 +2548,81 @@ assert.throws(throwingFirst, /Second$/); | |||
Due to the confusing error-prone notation, avoid a string as the second | |||
argument. | |||
|
|||
## `assert.partialDeepStrictEqual(actual, expected[, 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.
This should probably be marked as experimental.
* `expected` {any} | ||
* `message` {string|Error} | ||
|
||
[`assert.partialDeepStrictEqual()`][] Assesses the equivalence between the `actual` and `expected` parameters through a |
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.
[`assert.partialDeepStrictEqual()`][] Assesses the equivalence between the `actual` and `expected` parameters through a | |
[`assert.partialDeepStrictEqual()`][] asserts the equivalence between the `actual` and `expected` parameters through a |
Fixes: #50399
Took heavy inspiration from #53415 , trying to push it to the finish line 🚀
On top of it, I took the liberty of:
Co-Authored-By: Cristian Barlutiu