-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Fix: Prevent maintaining RegExp state between multiple tests #9289
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
Conversation
| typeof expected === 'string' | ||
| ? received.includes(expected) | ||
| : expected.test(received); | ||
| : new RegExp(expected).test(received); |
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 doubt there be will any issues with instantiating a new RegExp object for every call, but if this is a concern, I could limit that to only RegExps with the global/sticky flag since that's where this issue seems most likely to arise. Let me know what you think!
78f3208 to
14fda54
Compare
14fda54 to
88a8cbd
Compare
| it('does not maintain RegExp state between calls', () => { | ||
| const regex = /[f]\d+/gi; | ||
| jestExpect('f123').toMatch(regex); | ||
| jestExpect('F456').toMatch(regex); |
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 don't really know how I feel about this. As a JS user, I would expect this regex to be stateful and would be surprised that it's re-set by a specific matcher.
Not to mention this is a breaking change and needs documentation.
cc @pedrottimark @SimenB
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 @thymikee, FWIW that's the entire point of having a global flag in the first place is to be able to test against multiple matches. The issue reported via #9283 could be solved by removing the global from the RegExp since it's doing what it's supposed to do.
That said, #9283 was marked as a bug because this (specifically with Jest) could also be considered a regression since this was not the intended behavior before v24 was released.
I'm not sure if this behavior change was intentional or documented somewhere (since it was also a breaking change), or if it was just a regression that needs to be fixed (hence this PR).
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.
For what it's worth, I wouldn't expect Jest to change the state of an object, including a regular expression. It seems like it creates confusion and potential for false-positives in cases where the regular expression is being tested against several strings in the same test. If I want to test the lastIndex of a regex, I think I would test that directly:
regex.test('f123');
expect(regex.lastIndex).toBe(4);
regex.test('f456');
expect(regex.lastIndex).toBe(0);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.
You have my apology that I missed commenting on the issue or pull request before this.
It was my mistake in #8008 not to keep the code path to create a new instance for expected RegExp when I changed an expected string to match using includes method.
Therefore, this PR fixes what I broke, no more and no less.
@wsmd Thanks for your work. If you can merge changes from master and resolve the conflict in CHANGELOG.md then this is ready to merge.
There is a related (but separate) documentation chore in ExpectAPI.md under toMatch to adapt the example in #9283 and in the preceding #9289 (comment) so people understand how to write tests that are independent of RegExp state or intentionally testing RegExp state.
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 @pedrottimark! The merge conflict is now resolved. 👍
Codecov Report
@@ Coverage Diff @@
## master #9289 +/- ##
==========================================
- Coverage 64.98% 64.79% -0.19%
==========================================
Files 278 281 +3
Lines 11882 12009 +127
Branches 2926 2962 +36
==========================================
+ Hits 7721 7781 +60
- Misses 3532 3597 +65
- Partials 629 631 +2
Continue to review full report at Codecov.
|
pedrottimark
left a 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.
By the way, I verified locally that new RegExp(regexp) copies any flags like i
|
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 #9283
Currently
expectmaintains the state of RegExp objects when usingtoMatch(RegExp)ortoThrow(RegExp)with a global flagg.For example, the second assertion here fails:
What's expected there is for both assertions to pass.
This happens because
expectis using the same RegExp object for every test. This can be solved by instantiating a new RegExp object for every test.Test plan
Added a new test.