Skip to content

Commit

Permalink
Use Object.is when testing for equality where the === operator was pr…
Browse files Browse the repository at this point in the history
…eviously used.

This affects the 'to be' and 'to equal' assertions and means that NaN is considered equal to itself, whereas -0 and 0 are considered different.

Closes #116.
  • Loading branch information
papandreou committed Mar 2, 2015
1 parent 5f23734 commit 88565fb
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 7 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ expect(null, 'to be falsy');
expect(undefined, 'to be falsy');
```

**be**: asserts `===` equality
**be**: asserts equality using `Object.is`/the [SameValue](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevalue) algorithm

```js
expect(obj, 'to be', obj);
Expand All @@ -117,6 +117,13 @@ expect(false, 'to be defined');
expect({}, 'to be defined');
```

The SameValue/`Object.is` algorithm has some subtle differences compared to the `===` operator, which makes it more suitable for an assertion lib:

```js
expect(NaN, 'to be', NaN);
expect(-0, 'not to be', 0);
```

**equal**: asserts deep equality that works with objects

```js
Expand Down
11 changes: 10 additions & 1 deletion documentation/assertions/any/to-be.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Asserts `===` equality.
Asserts equality using `Object.is`/the [SameValue](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevalue) algorithm.

```javascript
var obj = {};
Expand All @@ -9,6 +9,15 @@ expect(undefined, 'to be', obj.foo);
expect(true, 'to be', !false);
```

The SameValue/`Object.is` algorithm has some subtle differences compared to the `===` operator, which makes it more suitable for an assertion lib:

<!-- evaluate -->
```javascript
expect(NaN, 'to be', NaN);
expect(-0, 'not to be', 0);
```
<!-- /evaluate -->

In case of a failing expectation you get the following output:

```javascript
Expand Down
4 changes: 1 addition & 3 deletions lib/Unexpected.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ var anyType = {
identify: function () {
return true;
},
equal: function (a, b) {
return a === b;
},
equal: utils.objectIs,
inspect: function (value, depth, output) {
return output.text(value);
},
Expand Down
3 changes: 2 additions & 1 deletion lib/assertions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var utils = require('./utils');
var objectIs = utils.objectIs;
var isRegExp = utils.isRegExp;
var isArray = utils.isArray;
var extend = utils.extend;
Expand All @@ -13,7 +14,7 @@ module.exports = function (expect) {
});

expect.addAssertion('[not] to be', function (expect, subject, value) {
expect(subject === value, '[not] to be truthy');
expect(objectIs(subject, value), '[not] to be truthy');
});

expect.addAssertion('string', '[not] to be', function (expect, subject, value) {
Expand Down
7 changes: 6 additions & 1 deletion lib/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,12 @@ module.exports = function (expect) {
return typeof value === 'number';
},
inspect: function (value, depth, output) {
output.jsNumber(value);
if (value === 0 && 1 / value === -Infinity) {
value = '-0';
} else {
value = String(value);
}
output.jsNumber(String(value));
}
});

Expand Down
11 changes: 11 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ var errorMethodBlacklist = ['message', 'line', 'sourceId', 'sourceURL', 'stack',
var specialCharRegexp = /([\x00-\x09\x0B-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BA-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF])/g;

var utils = module.exports = {
objectIs: Object.is || function (a, b) {
// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
if (a === 0 && b === 0) {
return 1 / a === 1 / b;
}
if (a !== a) {
return b !== b;
}
return a === b;
},

// https://gist.github.com/1044128/
getOuterHTML: function (element) {
// jshint browser:true
Expand Down
40 changes: 40 additions & 0 deletions test/unexpected.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,22 @@ describe('unexpected', function () {
expect('', 'to be defined');
});

it('NaN as equal to NaN', function () {
expect(NaN, 'to be', NaN);
});

it('considers negative zero not to be zero', function () {
expect(-0, 'not to be', 0);
});

it('considers negative zero to be itself', function () {
expect(-0, 'to be', -0);
});

it('considers zero to be itself', function () {
expect(0, 'to be', 0);
});

it.skipIf(typeof Buffer === 'undefined', 'asserts === equality for Buffers', function () {
var buffer = new Buffer([0x45, 0x59]);
expect(buffer, 'to be', buffer);
Expand Down Expand Up @@ -330,6 +346,22 @@ describe('unexpected', function () {
expect(new Error('foo'), 'to equal', new Error('foo'));
});

it('treats NaN as equal to NaN', function () {
expect(NaN, 'to equal', NaN);
});

it('treats negative zero and zero as unequal', function () {
expect(-0, 'not to equal', 0);
});

it('treats negative zero as equal to itself', function () {
expect(-0, 'to equal', -0);
});

it('treats zero as equal to itself', function () {
expect(0, 'to equal', 0);
});

it('treats an arguments object as different from an array', function () {
(function () {
expect(arguments, 'not to equal', ['foo', 'bar', 'baz']);
Expand Down Expand Up @@ -3147,6 +3179,14 @@ describe('unexpected', function () {
expect(NaN, 'to inspect as', 'NaN');
});

it('renders zero correctly', function () {
expect(0, 'to inspect as', '0');
});

it('renders negative zero correctly', function () {
expect(-0, 'to inspect as', '-0');
});

it('renders Infinity correctly', function () {
expect(Infinity, 'to inspect as', 'Infinity');
});
Expand Down

0 comments on commit 88565fb

Please sign in to comment.