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

expect(...).toEqual(...) fails on strings encoded with TextEncoder #9204

Closed
cubuspl42 opened this issue Nov 18, 2019 · 9 comments · Fixed by #9261
Closed

expect(...).toEqual(...) fails on strings encoded with TextEncoder #9204

cubuspl42 opened this issue Nov 18, 2019 · 9 comments · Fixed by #9261

Comments

@cubuspl42
Copy link

🐛 Bug Report

To Reproduce

Steps to reproduce the behavior:

  • Create a project: npx create-react-app jest-test1 --typescript
  • Modify package.json: "test": "react-scripts test --env=node" (because TextEncoder is not available at all in jsdom)
  • Create a test like the one below

Expected behavior

I expect this test...

function encodeFoo() {
  return new TextEncoder().encode("foo");
}

it('string encoded with TextEncoder equals to the expected byte array', () => {
  expect(encodeFoo()).toEqual(new Uint8Array([102, 111, 111])); // fails
});

...to succeed.

Instead it fails with:

  ✕ string encoded with TextEncoder equals to the expected byte array (3ms)

  ● string encoded with TextEncoder equals to the expected byte array

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

    Expected: [102, 111, 111]
    Received: serializes to the same string

      14 |
      15 | it('string encoded with TextEncoder equals to the expected byte array', () => {
    > 16 |   expect(encodeFoo()).toEqual(new Uint8Array([102, 111, 111])); // fails
         |                       ^
      17 | });
      18 |

      at Object.<anonymous> (src/App.test.tsx:16:23)

Link to repl or repo (highly encouraged)

https://github.com/cubuspl42/jest-test1

envinfo

  System:
    OS: macOS Mojave 10.14.5
    CPU: (8) x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
  Binaries:
    Node: 12.12.0 - /usr/local/bin/node
    npm: 6.11.3 - /usr/local/bin/npm
@cubuspl42
Copy link
Author

Other libraries (chai, deep-diff, deep-equal) find these objects equal, when using their deep object equality:
https://github.com/cubuspl42/jest-test1/blob/master/src/App.test.tsx#L22

@SimenB
Copy link
Member

SimenB commented Nov 18, 2019

I agree this is a bug. @jeysal is it fixed by #9167? I'm currently on mobile

@jeysal
Copy link
Contributor

jeysal commented Nov 20, 2019

is it fixed by #9167

Nah, note that we only strive towards and test total equivalence of expect.toStrictEqual and assert.deepStrictEqual. I suspect the non-strict ones may diverge a lot.
But happy to accept a PR fixing this! :)

@wsmd
Copy link
Contributor

wsmd commented Dec 4, 2019

I've done some investigation on this and it seems that the constructor of the Uint8Array returned from TextEncoder.prototype.encode and the global Uint8Array constructor are not the same (causing the assertion to fail via the iterableEquality); note that this only happens in the jest node environment.

// in Jest (using the node environment)
new TextEncoder().encode('').constructor === Uint8Array // false

// outside Jest (regular node runtime)
new TextEncoder().encode('').constructor === Uint8Array // true

I'm not exactly sure why these two are referencing different constructors or where either one of the constructors is referencing a different one, so I'm wondering if anyone has any pointers on this (I'm really curious!).

That said, updating the jest-environment-node's global to reference the actual Uint8Array (inside of the following block) seems to resolve this issue.

https://github.com/facebook/jest/blob/9ac2dcd55c0204960285498c590c1aa7860e6aa8/packages/jest-environment-node/src/index.ts#L54-L61

I'm happy to open a PR. Update: I opened #9261 so we can continue the conversation there.

@JonathanWilbur
Copy link

Is this possibly a subset of a larger category of similar issues? I still have this issue in 25.1.0, in which the "fixing" PR is merged. FWIW, el.value is a simple accessor that returns a private _value which is a Uint8Array.

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

    Expected: [50, 48, 50, 48, 48, 52, 48, 55]
    Received: serializes to the same string

      12 |             el.date = new Date(2020, 3, 7);
      13 |             console.log(el.value);
    > 14 |             expect(el.value).toEqual(new Uint8Array([
         |                              ^
      15 |                 0x32, 0x30, 0x32, 0x30, 0x30, 0x34, 0x30, 0x37,
      16 |             ]));
      17 |             const output = el.date;

      at Object.toEqual (test/x690/time.test.js:14:30)

@SimenB SimenB reopened this Jan 22, 2020
@SimenB
Copy link
Member

SimenB commented Jan 22, 2020

Can you provide a full example?

@JonathanWilbur
Copy link

Dang it, I am sorry, I used npm-check-updates to update my packages, and I didn't realize that it only modifies the package.json file (you have to follow up with npm install to update the latest packages). So even though it looked like I was using the latest Jest, I was not.

You can re-close this. Sorry to bother you.

@SimenB
Copy link
Member

SimenB commented Jan 22, 2020

Perfect! No worries 🙂

@SimenB SimenB closed this as completed Jan 22, 2020
@github-actions
Copy link

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 11, 2021
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.

5 participants