-
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: make *deepEqual() closer to *deepStrictEqual() #28011
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I am in favor of something like this but it seems to break a lot of modules even in CITGM. Interestingly the tests seem to fail the prototype check and not the abstract equality check. Modules that fail in CITGM due to a different prototype: At least One good thing is though that not a single test fails (or at least I did not see any) because of the former use of abstract equality checks (that is the main problem with the current implementation. The other two differences are minor compared to that). Should we maybe just change the equality and symbol checks in |
I had the same thought. Or maybe just a similar thought? Basically, make |
@Trott it is definitely not ideal when it comes to the name... since this did not show any problems with the abstract equality, we might actually just change both in one go. There will be a few more failures related to that and as you outline in the top: we have to be prepared to revert the change but I think it is worth a try. Removing the prototype check completely does not seem ideal though. I think updating the docs and taking back the deprecation would work in this case where |
243b2e7
to
1e75dbe
Compare
Still a WIP because the docs need to be updated (and I'm also testing each commit one-by-one to make sure there's no test failures at any point in the chain of 3 commits), but this is now closer to something that might be usable. Instead of an alias for |
8ebc451
to
1a848ca
Compare
Turns out this should probably be just one commit. Things left to do (not necessarily consecutively):
|
This is ready for reviews. @nodejs/assert |
CITGM against master: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/1894/ CITGM against this PR (queued): https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/1895/ |
Rebased and force-pushed to eliminate conflict.
|
CITGM with master branch for comparison: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/1934/ (queued, will 404 until a worker is available) |
CITGM looks good. This would be all clear to land on master if there are two TSC approvals and no Collborator objections. This is a rather notable change, and not one I'd want to have slip through unnoticed, so I'm going to ping widely. @nodejs/collaborators The upshot of this: |
This seems to defeat the purpose of even having the loose version. It exists because it's valuable as-is, in core - why remove the looseness? |
I'd say not. We basically don't use it in core anymore. I don't think the loose-equality aspect of it exists to fill a demonstrable need. AFAICT, it exists because a somewhat-embryonic CommonJS spec included it, and so, very early on in Node.js's development, it was implemented according to that spec (which never gained much adoption). The Node.js implementation has evolved since then (and all-but-certainly diverges from that original spec at this point), but the loose-equal aspect of it is of questionable utility. I'm unable to locate a real-world example demonstrating the utility of the loose-equalness in
AFAICT, that looseness is never actually why it's used. The only real-world usage of
This PR has already resulted in a small improvement in the ecosystem. We fixed a (very small, but nonetheless real) bug in the tests for All that said, I agree that caution is appropriate here, and if we land this change (which I think we should), we should also be prepared to revert quickly if there are large unforeseen consequences. That said, I do find the lack of CITGM problems reassuring. |
Let me rephrase; it's valuable to the ecosystem to have it in core, as-is. The If you're going to effectively destroy the use case of |
Can you (or someone else) point me to someone using it for its looseness? As you know (since you're a maintainer), it lists other selling points--runs in the browser, is faster than wrapping
Can you point me to one or two of them? Oooh, I'll start looking through some of substack's repos to see potential use cases there.... |
I agree that most people are using it without the strict option solely because that's the default. However, tape, mocha, jest, ava, jasmine, etc, all have a "deep equal" that uses loose equality. Many test cases for the DOM don't want to differentiate between |
AFAICT,
Also in favor of "keep it as it is" would seem to be some chai discussions that describe use cases where someone might want deep equal to have loose comparison at the leaves. It's apparently on their roadmap but the fact that folks have lived without it for this long is also an interesting data point. chaijs/chai#644 It also seems that jasmine and jest (and possibly others) detect DOM comparisons, sort of auto-handling one of the use cases suggested above. (This can probably be used to argue things both ways. "See? People need loose deep comparisons, even if it's abstracted away from them!" vs. "See? Test tools already deal with the DOM use case. Node.js core doesn't need to and shouldn't." |
That would certainly solve the API design problems this change would create. I'd go very incremental on something like this:
Despite the impossibility of achieving the last three bullet points, I rather like that incremental approach. (I also like the approach in this PR. I contain multitudes.) |
It certainly seems like it’d more carefully prove the premise of this PR, at least :-) |
Jest only has strict equality, yeah. I don't remember anyone asking for a loose one either (although I've only been involved in the project for 2 years, so might have come before that for all I know). @pedrottimark is the master of Jest's assertions, so maybe he can chime in on the DOM node example? We've relatively recently changed how that works and I have to admit I don't remember the details. FWIW, I just read the post I was tagged in, the thread is a bit long to read through unless you think there's some context in here I need? |
Thanks for chiming in! No, I don't think you need to read the whole thread. There are basically two questions. First, does |
With AVA, the following passes: import test from 'ava'
test('equality', t => {
t.deepEqual({ foo: { bar: 'baz' } }, { foo: { bar: 'baz' } })
}) See https://github.com/concordancejs/concordance#comparison-details for a high-level overview of the comparison rules.
It's been a long time since I wrote the code that AVA uses, but we do require string tags and constructors to be the same. Is that what you consider strict equality?
There's so many ways to interpret "equality" though, e.g. whether insertion order in sets and maps is significant. It might be too hard to reach consensus. The breaking changes are not worth it, it's possibly better to leave this to userland. |
In this particular context, I mean whether or not this should pass: assert.deepEqual({foo: 5}, {foo: '5'}); My understanding is that there is no built-in equivalent in AVA that does deep equality but ignores types at the leaf comparisons.
Definitely a problem.
Yeah, I'm pretty sure that if we were building Node.js all over again from the ground up, there would be no |
In the From #28011 (comment)
Yes, so a criterion is
With respect, I don’t follow the analogy. To test a response from an endpoint like From #28011 (comment)
Yes, I can imagine an expected criterion in literal object notation without calling constructors. From #28011 (comment)
Rich, I have empathy for y’all to decide about cost and benefit of breaking changes like this. |
Glad to see some of my incorrect assumptions clarified; and i agree that assert probably shouldn’t have been in node - however, i still think there’s use cases for having it, and i don’t see it as having that much maintenance cost as it is - so I’d prefer to see it remain. |
There's no chance That said, I'm finding #28011 (comment) appealing. It shifts the hardship away from the ecosystem a little bit. It's also destined to stall at some point, but when it does, the proposal here can be re-visited and we'd be able to say that we did a bunch of work to minimize impact on the ecosystem. |
Agreed! |
deepEqual() and notDeepEqual() are identical to deepStrictEqual() and notDeepStrictEqual() respectively with the exception that prototype/class is not checked.
071682a
to
5bd5b0b
Compare
Allow usage of assert.deepStrictEqual() without prototype checks. Refs: nodejs#28011
With these changes, the only difference between
deepEqual()
anddeepStrictEqual()
is thatdeepEqual()
doesn't require the same prototype.*[dD]eepEqual()
functions have surprising behaviors, which is why they are deprecated. They are very easy to misuse and not easy to use correctly. It is entirely possible that most people who are using them are in fact using them incorrectly or at least using them in a way where thestrict
equivalent would work just fine. Even if this results in some failing tests in the ecosystem, many of those tests may in fact reveal bugs in the tests/implementation. In other words, for many people, this might be a fix, not a breaking change.lib
.assert.deepEqual()
/assert.notDeepEqual()
have been deprecated for a long time, but we can never remove them. Making them near-aliases for theirstrict
equivalents might be do-able though.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes