Skip to content
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

RangeError: Maximum call stack size exceeded with .toBe on a large string #8936

Closed
Genuifx opened this issue Sep 10, 2019 · 13 comments
Closed

Comments

@Genuifx
Copy link

Genuifx commented Sep 10, 2019

πŸ› Bug Report

    expect(["....big string here"]).toBe("another 3MB string");

Writing code like this, jest will throw RangeError, here is the error message:

  ● Test suite failed to run

    RangeError: Maximum call stack size exceeded
        at String.match (<anonymous>)

      at exports.separateMessageFromStack.content (node_modules/jest-message-util/build/index.js:368:32)
          at Array.map (<anonymous>)

the Array expect function got has an item that is an about 3MB string (base64 image), and toBe got the same base64 String.

To Reproduce

like above.

Expected behavior

should fail the test, but not throw range error

Link to repl or repo (highly encouraged)

envinfo

  System:
    OS: macOS 10.14.6
    CPU: (4) x64 Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz
  Binaries:
    Node: 11.2.0 - ~/.nvm/versions/node/v11.2.0/bin/node
    Yarn: 1.12.3 - /usr/local/bin/yarn
    npm: 6.4.1 - ~/.nvm/versions/node/v11.2.0/bin/npm
  npmPackages:
    jest: ^23.6.0 => 23.6.0 
@thymikee
Copy link
Collaborator

thymikee commented Sep 10, 2019

Does it also happen with jest@24 or jest@next? cc @pedrottimark.
Also a repro would be very helpful

@StringEpsilon
Copy link
Contributor

node.js doesn't seem to like really long strings. I'm able to reproduce the bug and I think I found a fix. But testing this takes ages. Especially with my fix, as the console output grinds to a halt.

Anyway: string.match() crashes, probably due to a recursive approach. I'm not sure if the used regular expression can be changed to avoid this recursion.

  // Problematic regex:
  const messageMatch = content.match(/(^(.|\n)*?(?=\n\s*at\s.*\:\d*\:\d*))/); 
  let message = messageMatch ? messageMatch[0] : 'Error';
  const stack = messageMatch ? content.slice(message.length) : content;

My monkeypatched fix:

  const callstackPos = content.search(/((\n\s*at\s.*\:\d*\:\d*))/);
  let message = callstackPos ? content.substring(0, callstackPos) : 'Error';
  const stack = callstackPos ? content.substring(callstackPos+1) : content; 

That should work the same, but cuts match() out, instead relying on cutting by hand.

@StringEpsilon
Copy link
Contributor

Reproducion:

it("compares the strings correcty", () => {
    expect(string1 + "w").toBe(string1);
});

whereas string1 is just a 3000000 character long string I randomly generated (be aware: some IDEs might not like this).

@thymikee thymikee changed the title [BUG] RangeError: Maximum call stack size exceeded RangeError: Maximum call stack size exceeded with .toBe on a large string Sep 10, 2019
@SimenB
Copy link
Member

SimenB commented Sep 10, 2019

While it fails here https://github.com/facebook/jest/blob/736edd2ea6c9aadfb6e8794ecdc8a726f8a76b1a/packages/jest-message-util/src/index.ts#L358-L360, I think it makes more sense to avoid huge strings here: https://github.com/facebook/jest/blob/736edd2ea6c9aadfb6e8794ecdc8a726f8a76b1a/packages/jest-matcher-utils/src/index.ts#L307-L313 rather than trying to fix the regex part. This ends up generating a huge string, which is used when throwing the assertion error, which we later run the regex against. I think such a huge string is not useful anyways

That said, the change @StringEpsilon suggests seems reasonable regardless?

@pedrottimark
Copy link
Contributor

Yes, the way Jest hangs is as annoying as #1772 and #5392 but for different reason

Because base64 strings do not contain newlines, it was:

  • not a problem with line diff, for a change
  • not a problem with substring diff, because guarded with MAX_DIFF_STRING_LENGTH

Can y’all suggest any good examples of software tools that Jest might follow to limit:

  • length of strings
  • number of lines

in the report when a matcher fails?

@pedrottimark
Copy link
Contributor

@Genuifx To help me think what is relevant information that Jest should provide, the type mismatch of array as received value and string as expected value was which of the following:

  • error in the test: how the assertion was written or an incorrect assumption about behavior
  • error in the code: return an array instead of a string

@StringEpsilon
Copy link
Contributor

I'm not entirely sure if a unit test suite does that, but think a good way of dealing with overly long lines would just be to chop to the relevant section. That would be the start of the differences + whatever surroundings can be added reasonably.

Samples for comparing against SBjb21wcmVoZW5zaXZlIEphdmFTY3JpcHQgdGVzdGluZyBzb2x1dGlvbi4gV29ya3Mgb3V0IG9mIHRoZSBib3ggZm9yIG1vc3QgSmF2YVNjcmlwdCBwcm9qZWN0cy4K

Expected: "SBjb21wcmVoZW5zaXZlIEphdmFTY3JpcHQgdGVz" + [88]
Received: "_Z_Bjb21wcmVoZW5zaXZlIEphdmFTY3JpcHQgdGVz" + [88]

Expected: [66] + "Mgb3V0I_G9ml_HRoZSBib3ggZm9yIG1vc" + [31 ]
Receveived: [66] + "Mgb3V0I_G9ML_HRoZSBib3ggZm9yIG1vc" + [31]

Expected: [80] + "ZSBib3ggZm9yIG1vc3QgSmF2YVNjcmlwdCBwcm9qZWN0cy4_K_"
Received: [80] + "ZSBib3ggZm9yIG1vc3QgSmF2YVNjcmlwdCBwcm9qZWN0cy4_L_"

It's not entirely uncommon for compilers or intrepeters to chop lines to the relevant section. I'm not entirely sure how much overhead this would introduce. I'm also not sure about the UX aspects of chopping strings that should be equal but aren't (i.E. introducing headaches to the guy debugging that test)

@Genuifx
Copy link
Author

Genuifx commented Sep 16, 2019

@pedrottimark error in the test is preferred. Actually, That was my bug while mocking some kind of function.

@StringEpsilon I was doing redux compatible work for mini-app, one case needs consider is the store's data is too large to connect the page (every single time setData call only 1024kb data can be transferred between threads), so I used jest writing some related test suites.

@ishan123456789
Copy link

I was getting this error with .toMatchObject so to solve this I JSON.stringified the object and checked toMatch instead of checking the object.

@ThiagoFelippi
Copy link

ThiagoFelippi commented Nov 14, 2020

This happen when I use functions with two ways. This will be generate call stack error because Javascript is single thread, example:

const a = () => {
const b = b();
const c = "hello"
return b + c
}

const b = () => {
const a = a()
const c = "hello"
return a + c
}

Function a call function b and function b call function a, this will fill the call stack and generate this error

@github-actions
Copy link

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added the Stale label Feb 25, 2022
@github-actions
Copy link

This issue was closed because it has been stalled for 7 days with no activity. Please open a new issue if the issue is still relevant, linking to this one.

@github-actions
Copy link

github-actions bot commented May 3, 2022

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants