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

Confusing and inconsistent comparison of NaN #1653

Open
aradzie opened this issue Nov 5, 2024 · 3 comments
Open

Confusing and inconsistent comparison of NaN #1653

aradzie opened this issue Nov 5, 2024 · 3 comments

Comments

@aradzie
Copy link

aradzie commented Nov 5, 2024

Consider the following example:

import { test } from "node:test";
import { assert, expect } from "chai";

test("pass", () => {
  expect([NaN]).to.deep.equal([NaN]);
  expect({ a: NaN }).to.deep.equal({ a: NaN });

  assert.deepStrictEqual([NaN], [NaN]);
  assert.deepStrictEqual({ a: NaN }, { a: NaN });
});

test("fail/expect", () => {
  expect(NaN).to.equal(NaN);
});

test("fail/assert", () => {
  assert.strictEqual(NaN, NaN);
});
✖ fail/expect
  Error [AssertionError]: expected NaN to equal NaN
✖ fail/assert
  Error [AssertionError]: expected NaN to equal NaN

The comparison algorithm behaves differently depending on whether NaN values are compared directly or as deep property/member values. This inconsistency creates confusion and diminishes the developer experience.

We suggest to change the behavior of expect(...).to.equal(...) and assert.strictEqual(..., ...) to match their deep counterparts.

@aradzie
Copy link
Author

aradzie commented Nov 5, 2024

And for the sake of comparison, a similar example, this time using the Node.js assert module:

import assert from "node:assert/strict";
import { test } from "node:test";

test("pass", () => {
  assert.strictEqual(NaN, NaN);
  assert.deepStrictEqual([NaN], [NaN]);
  assert.deepStrictEqual({ a: NaN }, { a: NaN });
});

The test above successfully passes.

@43081j
Copy link
Contributor

43081j commented Nov 7, 2024

Makes sense to me

We should do the same as node I suspect

@koddsson thoughts?

@koddsson
Copy link
Member

koddsson commented Nov 7, 2024

equals is essentially just a short-hand for === and in JavaScript NaN !== NaN so to me chai is doing the correct thing here.

Node was special casing their implementation to specifically handle NaN === NaN which to me is confusing. It seems like they're moving away from this by marking assert.equals as deprecated and pointing users towards assert.strictEqual which uses Object.is.

I think our strictEquals should probably assert correctly that NaN === NaN but the equals is working correctly to me.

I'm not 100% sure on the .deep bits. deep-eql uses Object.is for equality so it makes sense that it says that NaN === NaN like the node implementation.


With all this being said this has been working like this for a while so I think this feedback is good for how we change the API for Chai@v6 as it seems like most of these changes warrant a breaking change.

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

No branches or pull requests

3 participants