-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
toStrictEqual
does not consider arrays with objects having undefined values correctly
#7938
Conversation
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need the corporate CLA signed. If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks! |
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
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.
Thanks for reporting this issue and submitting the fix! Left a few comments with things that came to my mind
CHANGELOG.md
Outdated
@@ -12,6 +12,7 @@ | |||
- `[jest-cli]` Fix prototype pollution vulnerability in dependency ([#7904](https://github.com/facebook/jest/pull/7904)) | |||
- `[jest-cli]` Refactor `-o` and `--coverage` combined ([#7611](https://github.com/facebook/jest/pull/7611)) | |||
- `[expect]` Fix custom async matcher stack trace ([#7652](https://github.com/facebook/jest/pull/7652)) | |||
- `[expect]` `toStrictEqual` does not consider arrays with objects having undefined values correctly ([#7938](https://github.com/facebook/jest/pull/7938)) |
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.
- `[expect]` `toStrictEqual` does not consider arrays with objects having undefined values correctly ([#7938](https://github.com/facebook/jest/pull/7938)) | |
- `[expect]` Fix `toStrictEqual` not considering arrays with objects having undefined values correctly ([#7938](https://github.com/facebook/jest/pull/7938)) |
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.
Will do
packages/expect/src/utils.js
Outdated
@@ -251,7 +251,9 @@ export const sparseArrayEquality = (a: any, b: any) => { | |||
// A sparse array [, , 1] will have keys ["2"] whereas [undefined, undefined, 1] will have keys ["0", "1", "2"] | |||
const aKeys = Object.keys(a); | |||
const bKeys = Object.keys(b); | |||
return equals(a, b) && equals(aKeys, bKeys); | |||
return ( | |||
equals(a, b, [iterableEquality, typeEquality], true) && equals(aKeys, bKeys) |
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.
Should this have sparseArrayEquality
too? There could be nested arrays for which we need to do that check. Or does that already work this way?
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.
It would create an infinite loop:
toStrictEqual(a, b)
-> equals(a, b, [iterableEquality, typeEquality, sparseArrayEquality], true)
-> sparseArrayEquality(a, b)
-> equals(a, b, [iterableEquality, typeEquality, sparseArrayEquality], true)
-> ...
😁 I did try it at the beginning
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've just checked and it also works e.g. for
expect([[{a: undefined}]]).not.toStrictEqual([[]]);
expect([{a: [{a: undefined}]}]).not.toStrictEqual([{a: []}]);
I just wasn't quite sure how exactly the recursion works in the beginning.
Maybe add those test cases as well for peace of mind?
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 added an extra test to check that strictEqual will work fine with deeper objects
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 regression and the question about correctness of its correction is evidence that as we continue to fix edge cases in expect
package, we also need to think how to reduce the complexity of coupling between custom testers.
Codecov Report
@@ Coverage Diff @@
## master #7938 +/- ##
=======================================
Coverage 65.33% 65.33%
=======================================
Files 255 255
Lines 9941 9941
Branches 1041 1041
=======================================
Hits 6495 6495
Misses 3195 3195
Partials 251 251
Continue to review full report at Codecov.
|
Thanks for the PR! We just merged a migration of |
No problem I will rebase asap |
@SimenB I rebased locally with no issue, is the migration to Typescript of |
It's on master, yes. You can see GitHub reporting a merge conflict |
@SimenB should be rebased now |
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.
Thank you very much!
Thanks a lot for your quick reviews 👍 Following this bug, I wanted to come with some kind of automatic way to detect such regression or bug in the future. For the moment I commited a draft proposal for such test on my fork: dubzzz@114022f The test basically checks the following:
It caught another bug in @SimenB, @thymikee, @pedrottimark, @jeysal: |
@dubzzz I've heard of fast-check (and jsverify) before and I like the idea, could imagine adding them in a separate test file |
@jeysal Thanks a lot for your input, I will write a new spec with only properties for matchers. I let you know when I have something ready so that we can iterate on it ;) |
I'd be particularly interested to learn how to achieve determinism with this, but let's see when you have prepared a draft and discuss such topics there :) |
I clearly get your concerns of potential flakiness added by such test suites. There are multiple things to keep in mind with property based testing:
I would say that bug detection is pretty good and stable - I mean it finds bugs consistently. Justification: integration test and examples of fast-check - executed for all CI runs on node 6, 8 and 10 - check that fast-check properly detects bugs in buggy code. And they are stable. Example: detect a bug occuring only when an object contains a sub-object. But indeed sometimes bugs are not easy to detect and might be detected a bit later. In a way it is still useful as it means the bug is now known. |
I think it detected another bug: const s1 = new Set([false, true]);
const s2 = new Set([new Boolean(true), new Boolean(true)]);
expect(s1).not.toEqual(s2); // success
expect(s2).not.toEqual(s1); // failure
// expect(received).not.toEqual(expected)
// Expected: Set {false, true}
// Received: Set {{}, {}} An issue with symmetry of |
Interesting, thanks for elaborating! As mentioned, I'm in favor of integrating such tests in places where it makes sense, and |
I'm very much in favor of adding fuzz testing to This got me thinking, should we ship fuzz testing as part of jest itself? Might make it a bit more mainstream. Should be enough to just wrap |
As you both agree to add property based testing or fuzzing into the tests of Jest, I am going to open a PR for that purpose. @SimenB I definitely welcome the idea to wrap property based testing tools directly within Jest. I think it is a great idea: growing the popularity of such approach among JavaScript world would be very nice. I am obviously a little biased concerning the choice of the framework as I wrote fast-check. In a nutshell when I first wanted to do property based in my company I opted for jsverify but got stuck on some of its limitations (due to initial design choices). So I started to explore how it worked and somehow started fast-check. Why fast-check? Concerning integration in Jest, I did some wrapper of fast-check for ava. Might give you some ideas: https://github.com/dubzzz/ava-fast-check/ |
Awesome!
Would you mind opening an RFC for it? It doesn't have to be very detailed, the paragraphs you have above are great. I'd like to see a separate RFC so it's more visible to other people, instead of being discussed in a merged PR. Thanks! ❤️ |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
Fixes #7937:
toStrictEqual
does not consider arrays with objects having undefined values correctlyTest plan
Before that change, the following assertion was failing:
Now it passes as expected.