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]: "Received: serializes to the same string" when using toStrictEqual with fs.readdirSync #11923

Closed
Pomax opened this issue Oct 2, 2021 · 11 comments · Fixed by #13960
Closed

Comments

@Pomax
Copy link

Pomax commented Oct 2, 2021

Version

27.2.2

Steps to reproduce

Create an empty dir, run npm init follwed by npm install jest and create a file test.js with content:

const fs = require(`fs`);

test(`fun?`, () => {
  const dirs1 = Array.from(fs.readdirSync(__dirname));
  expect(dirs1).toStrictEqual([
    `node_modules`,
    `package-lock.json`,
    `package.json`,
    `test.js`,
  ]);

  const dirs2 = fs.readdirSync(__dirname);
  expect(dirs2).toStrictEqual(dirs1);
});

Then run this with npx jest test.js

Expected behavior

Given that readdirSync returns an array already, we'd expect both tests to pass. If fact, we'd look at the first test and go "why on earth use Array.from on something that's already an array?"

Actual behavior

 FAIL  ./test.js
  × fun? (4 ms)

  ● fun?

    expect(received).toStrictEqual(expected) // deep equality

    Expected: ["node_modules", "package-lock.json", "package.json", "test.js"]
    Received: serializes to the same string

      11 |
      12 |   const dirs2 = fs.readdirSync(__dirname);
    > 13 |   expect(dirs2).toStrictEqual(dirs1);
         |                 ^
      14 | });
      15 |

      at Object.<anonymous> (test.js:13:17)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total

Additional context

I have no idea what's going on here, but I'm pretty sure it shouldn't be happening. That "received" kind of sounds like the test did pass, because what it received serialized to the same string that the expected value serializes to. That's exactly what we want. This should pass O_o

Environment

win10 pro x64, node 16.7.0, npm 7.20.3
@SimenB
Copy link
Member

SimenB commented Oct 4, 2021

I assume this is due to #2549.

If you add

  console.log('dirs1 instance', dirs1 instanceof Array);
  console.log('dirs2 instance', dirs2 instanceof Array);

to your test, only the first logs true.

You can work around it by using toEqual - on an array of strings that's identical.


That said, I think toStrictEqual should handle this case. @mattphillips @pedrottimark @jeysal is this something you have an idea for solving? 🙂

@jeysal
Copy link
Contributor

jeysal commented Oct 4, 2021

Can't think of a "symptomatic" fix for this without some kind of fix for #2549

@SimenB
Copy link
Member

SimenB commented Oct 4, 2021

Could do an Array.isArray if any side is instance of Array but the other isn't, but that's a very specific fix...

@Pomax
Copy link
Author

Pomax commented Oct 4, 2021

While instanceof indeed fails (and reading up on vm contexts, necessarily so), examining the proto constructor might offer a solution for all globals, rather than just Array.

If I run this code instead:

const fs = require(`fs`);

test(`fun?`, () => {
  const dirs1 = Array.from(fs.readdirSync(__dirname));
  const class1 = dirs1.__proto__.constructor;

  const dirs2 = fs.readdirSync(__dirname);
  const class2 = dirs2.__proto__.constructor;

  expect(class1.name).toBe(`Array`);
  expect(class2.name).toBe(`Array`);
  expect(class1).toBe(class2);
});

I get:

    expect(received).toBe(expected) // Object.is equality

    Expected: [Function Array]
    Received: serializes to the same string

      14 |   expect(class1.name).toBe(`Array`);
      15 |   expect(class2.name).toBe(`Array`);
    > 16 |   expect(class1).toBe(class2);
         |                  ^
      17 | });

      at Object.<anonymous> (test.js:16:18)

If I also throw in a console log for those classes using:

  console.log(class1.toString());
  console.log(class2.toString());

we get:

  console.log
    function Array() { [native code] }

      at Object.<anonymous> (test.js:12:11)

  console.log
    function Array() { [native code] }

So that might be something to use for an underlying fix: if the instanceof fails but we're dealing with native code constructors, I'd assume a thing.__proto__.constructor.name check would be a "safe" fallback check for the majority of users (I would imagine any code that compiles-before-use has the ability to declare its own Array object with Array as constructor name, with this same function Array() { [native code] } string serialization, but that'd be drastically fewer edge cases than all code that jest gets run on).

@phuhl
Copy link

phuhl commented Dec 22, 2021

I got a similar issue, stemming from a row returned by sqlite3. Converting the non-array to something with instanceof Array === true does not help:

    console.log("rows instance", rows instanceof Array); // ->       rows instance false
    console.log("rows instance", [...rows] instanceof Array); // ->       rows instance true
    expect([...rows]).toStrictEqual([
      {
        category: "pasta",
        description: "Spaghetti cabonara",
        rating: 5,
      },
    ]); /* ->
 Expected: [{"category": "pasta", "description": "Spaghetti cabonara", "rating": 5}]
 Received: serializes to the same string
*/

@CMCDragonkai
Copy link

I'm encountering this with just plain strings.

      payload: {
        foo: 'bar',
        jti: 'v0oqnj8nqr5o013mqh7nj7bd91c',
        iat: 1666685488,
        nbf: 1666685488,
        prev: null,
        seq: 1
      },

My data structure is just as above, and I'm doing toStrictEqual and it's giving the same error. Very confusing.

Changing to use toEqual instead.

@Pomax
Copy link
Author

Pomax commented Oct 25, 2022

@CMCDragonkai you're going to have to show a minimal reproducible example in that case. Just showing the data structure isn't quite enough for folks to understand what code needs to be in place for the bug to surface.

@CMCDragonkai
Copy link

Yea it's strange, reproducible code wise, it's literally just comparing that structure I posted above. But I suspect comparing that structure in a code snippet won't work. There's something strange about the testing environment.

But at the same time, this kind of error: Received: serializes to the same string just doesn't make sense to me at all for an operator like toStrictEqual. What does this exception even mean?

@Pomax
Copy link
Author

Pomax commented Oct 26, 2022

the reason I asked is because "it depends on what's actually going wrong", so without minimal reproducible code, it's borderline impossible to tell. You may want to start a new issue instead, with the same kind of explanation that this one started with, showing enough code and instructions on what to do in order to reproduce the problem.

In general, the error means "as far as I can tell these two things are not the same" which will happen not just on key or value disagreement, but also type. JS lets things "act like" other things, even if they aren't the same kind of thing.

@mathewvaughan
Copy link

Hey guys - I'm actually finding a similar problem. However, the 'minimum' reproducible code isn't going to be very minimal: the objects involved are being affected by so many different jest plugins at this point that even my intelli-sense isn't keeping track of what's involved. I thought I'd mention it though so there's some extra evidence of the bug.

The problem was resolved for me by JSON.stringify-ing my expected and actual result, but this isn't optimal obviously

@github-actions
Copy link

github-actions bot commented Apr 6, 2023

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 Apr 6, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants