qunitjs / qunitjs/qunit

Support differentiating -0 and +0 (sameValue assertion)

Open
#1,010 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Category: API Component: Assert Type: Enhancement Type: Meta
Dominant language
JavaScript
Stars
4k
Forks
773
PR merge metrics
No merged PRs in 30d

Description

ECMAScript has two internal abstractions to compare values called sameValue and sameValueZero.

They are different than == and === as they return true for NaN values and compare -0 and +0.

Based on my experience with test262, and considering some personal goals I have for QUnit (still seeking funding for it) I believe it's fair to ship assertions that does the same comparisons, while I believe it's dangerous to simply modify strictEqual.

Object.is returns the exact result for sameValue, but that's an ES6 feature and not available on supported browsers. The results are the same as === but with special checks for NaN and bit precision zeros.

Here goes some data on how they would work:

method NaN, NaN 0, -0 -0, -0 [1, 2], [1, 2]
equal fail pass pass fail
strictEqual fail pass pass fail
deepEqual pass pass pass pass
propEqual pass pass pass pass
_.isEqual pass pass pass pass
sameValue pass fail pass fail
sameValueZero pass pass pass fail

The following code can provide some results, as it uses lodash's isEqual as well:
cc @jdalton

QUnit.assert.sameValue = function(a, b, message) {
  var result;

  if (a === b) {
    // -0 vs +0
    result = (a !== 0 || 1/a === 1/b);
  } else

  // NaN
  if (a !== a && b !== b) {
    result = true;
  }

  this.pushResult({
    result,
    actual: a,
    expected: b,
    message
  });
};

QUnit.assert.sameValueZero = function(a, b, message) {
  var result;

  if (a === b) {
    result = true;
  } else 

  // NaN
  if (a !== a && b !== b) {
    result = true;
  }

  this.pushResult({
    result,
    actual: a,
    expected: b,
    message
  });
};


var {test} = QUnit;

test("NaN", function(t) {
  t.ok(_.isEqual(NaN, NaN), "lodash equals");
  t.equal(NaN, NaN, "equal");
  t.strictEqual(NaN, NaN, "strictEqual");
  t.deepEqual(NaN, NaN, "deepEqual");
  t.propEqual(NaN, NaN, "propEqual");
  t.sameValue(NaN, NaN, "sameValue");
  t.sameValueZero(NaN, NaN, "sameValueZero");
});

test("-0 vs +0", function(t) {
  t.ok(_.isEqual(0, -0), "lodash equals");
  t.equal(0, -0);
  t.strictEqual(0, -0);
  t.deepEqual(0, -0);
  t.propEqual(0, -0);
  t.sameValue(0, -0, "sameValue");
  t.sameValueZero(0, -0);
});

test("-0", function(t) {
  t.ok(_.isEqual(0, -0), "lodash equals");
  t.equal(-0, -0);
  t.strictEqual(-0, -0);
  t.propEqual(-0, -0);
  t.deepEqual(-0, -0);
  t.sameValue(-0, -0);
  t.sameValueZero(-0, -0);
});

test("arrays", function(t) {
  t.ok(_.isEqual([1, 2], [1, 2]), "lodash equals");
  t.equal([1, 2], [1, 2], "equal");
  t.strictEqual([1, 2], [1, 2], "strictEqual");
  t.propEqual([1, 2], [1, 2], "propEqual");
  t.deepEqual([1, 2], [1, 2], "deepEqual");
  t.sameValue([1, 2], [1, 2], "sameValue");
  t.sameValueZero([1, 2], [1, 2], "sameValueZero");
});

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating QUnit's assertion API and its existing assertion tests; the issue names no specific files or test entry points. Compare the proposed sameValue and sameValueZero cases for NaN, signed zero, and arrays, then verify the assertions through the project's test suite.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
testing
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.