Consolidates asserts#equal branches for keyed collections (Map/Set) and supports deep equality of Map keys #3258
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
In my fix for #3235, I simply added an additional branch to asserts#equal() to deeply compare
Map
instances in a similar fashion toSet
instances. @kitsonk sensibly raised, however, that I could consolidate these two branches for all iterables. However, it turns out such a unification is not so straightforward.Foremost,
Map
andSet
are examples of keyed collections, which are not indexable, linear sequences. Hence,equal(new Set([1, 2, 3]), new Set([3, 2, 1]))
should returntrue
, butequal([1, 2, 3], [3, 2, 1])
should returnfalse
. After some investigation, I can confirm that this also holds true in Jest and Chai. Effectively, if twoMap
s orSet
s have (i.e.Map
/Set#has(key)
) the same keys which resolve to deeply-equivalent values, thenequal(a, b) === true
.Therefore, rather than introduce a common conditional branch for all iterables, I combined the logic for keyed collections only. I'm currently detecting them with duck typing, but please let me know if an explicit
instanceof Map || instanceof Set
check would be preferable.I also realised that the current release (0.22) and my fix also fail to determine if the keys of a keyed collection are deeply equal (i.e.
equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 1 }, true]]))
should betrue
, despite the keys being different references), which I have thus addressed in this PR. Once again, Jest and Chai handle these cases in the same way.I should highlight that there's a potential performance downside to my changes: disregarding recursion, the existing solution for both
Map
s andSet
s has a worst-case complexity ofO(n)
(O(n)
for iterating overa
andO(1)
forb.has(keyOfA)
/b.get(keyOfA)
), whereas my changes have an upper bound ofO(n²)
. I understand if this trade-off isn't worth introducing to a standard module, but I don't think it hurts to support true deep equality of keyed collections out of the box if it's going to help with testing while avoiding the need for superfluous third-party dependencies.