From dadc9b89d9f18be830777bed0e2cdacffb11bf93 Mon Sep 17 00:00:00 2001 From: Robert Fletcher Date: Mon, 9 Dec 2019 20:33:17 -0800 Subject: [PATCH] Fix `toMatch` when re-using RegExp with 'g' flag Fixes #9283 When testing a regex with the `g` flag, the regular expression is not reset between assertions, such that subsequent assertions that should pass, fail. The test below passes on Jest 23 but fails on 24: ```ts it('matches consistently when re-using a regex with the "g" flag', () => { const regex = /foo/g; jestExpect('foo').toMatch(regex); // passes jestExpect('foo').toMatch(regex); // fails! }); ``` It appears this behavior was introduced in c3a0167. Previously, Jest cloned the regex with `new RegExp()`, which sidestepped the issue by using a new regex for every assertion. This restores that behavior. The issue here is due to somewhat confusing behavior in the way that regular expressions with the `g` or `y` flag behave. Internally, the regex [keeps a `lastIndex`][1] and the next time it is matched against, it will search from that index, or cycle back to 0 if no match is found: ``` > regex = /foo/g /foo/g > regex.test('foo') true > regex.lastIndex 3 > regex.test('foo') false > regex.lastIndex 0 > regex.test('foo') true > regex.lastIndex 3 ``` [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex --- CHANGELOG.md | 1 + packages/expect/src/__tests__/matchers.test.js | 6 ++++++ packages/expect/src/matchers.ts | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4160a719cd8d..de90052578d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ - `[expect]` Avoid incorrect difference for subset when `toMatchObject` fails ([#9005](https://github.com/facebook/jest/pull/9005)) - `[expect]` Consider all RegExp flags for equality ([#9167](https://github.com/facebook/jest/pull/9167)) - `[expect]` [**BREAKING**] Consider primitives different from wrappers instantiated with `new` ([#9167](https://github.com/facebook/jest/pull/9167)) +- `[expect]` Fix `toMatch` to return consistent results when re-using `RegExp` with `g` flag ([#9290](https://github.com/facebook/jest/pull/9290)) - `[jest-config]` Use half of the available cores when `watchAll` mode is enabled ([#9117](https://github.com/facebook/jest/pull/9117)) - `[jest-config]` Fix Jest multi project runner still cannot handle exactly one project ([#8894](https://github.com/facebook/jest/pull/8894)) - `[jest-console]` Add missing `console.group` calls to `NullConsole` ([#9024](https://github.com/facebook/jest/pull/9024)) diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index fb6223a9466f..f98cb99224c8 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -1617,6 +1617,12 @@ describe('.toMatch()', () => { it('escapes strings properly', () => { jestExpect('this?: throws').toMatch('this?: throws'); }); + + it('matches consistently when re-using a regex with the "g" flag', () => { + const regex = /foo/g; + jestExpect('foo').toMatch(regex); + jestExpect('foo').toMatch(regex); + }); }); describe('.toHaveLength', () => { diff --git a/packages/expect/src/matchers.ts b/packages/expect/src/matchers.ts index ca51e52291ba..58c015992aeb 100644 --- a/packages/expect/src/matchers.ts +++ b/packages/expect/src/matchers.ts @@ -835,7 +835,7 @@ const matchers: MatchersObject = { const pass = typeof expected === 'string' ? received.includes(expected) - : expected.test(received); + : new RegExp(expected).test(received); const message = pass ? () =>