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

[Bug]: Since Jest 29.1.0 comparing an array of complex class instances throws an error "TypeError: this is not a typed array" #14375

Open
elchininet opened this issue Jul 29, 2023 · 8 comments

Comments

@elchininet
Copy link

Version

29.1.0

Steps to reproduce

Reproduction of the bug:

  1. Clone this repo. git clone git@github.com:elchininet/isometric.git
  2. Checkout the branch bug-jest. git checkout bug-jest
  3. Install dependencies: yarn
  4. Run this small test: yarn test tests/buggy-test.test.ts
  5. All the tests will pass without any issue (same test using toEqual, toStrictEqual and toMatchObject)
  6. Update jest in package.json from version 29.0.3 to version 29.1.0
  7. Run yarn again to update the package
  8. Run again the small test: yarn test tests/buggy-test.test.ts
  9. The console will hang for a while and at the end it will fail in the test Test with toMatchObject
image

Expected behavior

Jest should not fail with toMatchObject with an array of class instances, it should pass as toEqual or toStrictEqual pass.

Actual behavior

Jest fails to compare an array of class instances with toMatchObject. It even fails with:

expect([rectangle]).toMatchObject([rectangle]);

Additional context

No response

Environment

System: Apple M1 Pro
Binaries:
* Node: v16.15.1
* Yarn: 1.22.19
* npm: 8.11.0
npm packages:
jest `29.0.3` => `29.1.0`
@elchininet elchininet changed the title [Bug]: Since Jest 29.1.0 comparing an array of complex classes throws an error "TypeError: this is not a typed array" [Bug]: Since Jest 29.1.0 comparing an array of complex class instances throws an error "TypeError: this is not a typed array" Jul 29, 2023
@mrazauskas
Copy link
Contributor

There is something odd inside the rectangle.element prop, because the following is passing:

expect(rectangle).toMatchObject({ ...rectangle, element: expect.anything() })

If I do console.log(rectangle.element) all it shows is: SVGElement {}. Hard to say what is going on there.

@elchininet
Copy link
Author

Hi @mrazauskas,

Thanks for your response. The oddness occurs with any class from the library, I did the example with the rectangle just to make it short but it breaks in any place that I use toMatchObject with childrenproperty (almost all the classes inherith from the same base class). That has not been occurring until version 29.1.0 and the library has been working with that matcher since a long time ago (jest 28.x.x).

Something curious is that it doesn‘t fail with toEqual or toStrictEqual, it is just with toMatchObject, and all of them check that property.

What you are getting with the console.log is the same that you get if you do this inside a test:

console.log( document.createElementNS('http://www.w3.org/2000/svg', 'path') ); // SVGElement {}

Element will be always an SVGElement.

Regards

@elchininet
Copy link
Author

elchininet commented Jul 29, 2023

As you discovered that the issue is with the element property, I did a small test and this also fails:

it('Test with toMatchObject', (): void => {
    const a = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    expect(a).toMatchObject(a);
});

It doesn‘t fail with toBe, toEqual or toStrictEqual (and it doesn‘t fail either with jest 29.0.3).

@mrazauskas
Copy link
Contributor

Thanks for the idea. I was able to recreate the issue in an empty repro only with jest and jest-environment-jsdom installed:

/**
 * @jest-environment jsdom
 */

test("document.createElementNS", () => {
  const x = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
  const y = document.createElementNS("http://www.w3.org/1999/xhtml", "div");

  expect(x).toMatchObject(y);
});

I was using Yarns resolutions and the problem narrowed down to @jest/expect-utils package:

If I got it right, the changes I am pointing to are related (or mostly related) with the toMatchObject() matcher. That explains why all works well with other matchers.


Could you confirm if adding the following to the package.json allows to to upgrade Jest:

"resolutions": {
  "@jest/expect-utils": "29.3.1"
}

@mrazauskas
Copy link
Contributor

The object returned by JSDOM's createElementNS() method has _globalObject.window object. This object has more stuff installed by JSDOM and those have _globalObject.window prop. So here is what I tried:

/**
 * @jest-environment jsdom
 */

test("globalThis", () => {
  expect(globalThis).toMatchObject(globalThis);
});

It passes with "@jest/expect-utils": "29.3.1", but freezes Jest with "@jest/expect-utils": "29.4.0".

@elchininet
Copy link
Author

Hi @mrazauskas,
Yes, with @jest/expect-utils 29.3.1 the issue doesn‘t occur and I can even upgrade to jest 29.6.2 without any issues.
That is aligned with my debugging yesterday, I placed breakpoints and I noticed that the issue seems to be inside @jest/expect-utils/build/jasmineUtils.js.
Regards

@elchininet
Copy link
Author

@mrazauskas,
I didn‘t see this comment before.

The object returned by JSDOM's createElementNS() method has _globalObject.window object. This object has more stuff installed by JSDOM and those have _globalObject.window prop. So here is what I tried:

It could be related to that indeed, as jest-dom mimics the real DOM native APIs, window has a property named globalThis which is a reference to itself, maybe this is the root of the maximum call stack.

window === window.globalThis // true
window === window.globalThis.globalThis // true

@mrazauskas
Copy link
Contributor

If I got it right, jsdom is using Symbols for information hiding. After #13639 that concept got broken, because toMatchObject() now looks at props with Symbol keys. Can be that circular references are not handled well. For instance, globalThis/window could be the place which ends up in infinite loop.

@lpizzinidev @joshkel Would you have a moment to take a look? It seems that support of Symbol property keys broke Jest for users of jsdom.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants