Skip to content

Commit 00f72e7

Browse files
committed
Merge pull request #73 from cjihrig/master
change default comparison behavior
2 parents 6754c4b + 710aaf0 commit 00f72e7

File tree

3 files changed

+120
-41
lines changed

3 files changed

+120
-41
lines changed

API.md

+30-21
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,18 @@ expect(6).to.be.in.range(5, 6);
8888
### Flags
8989

9090
The following words toggle a status flag for the current assertion:
91-
- `deep` - performs a deep comparison instead of simple equality (`===`). Required when trying to compare
92-
objects to an identical copy that is not the same reference. Used by `equal()` and `include()`.
9391
- `not` - inverses the expected result of any assertion.
9492
- `once` - requires that inclusion matches appear only once in the provided value. Used by `include()`.
9593
- `only` - requires that only the provided elements appear in the provided value. Used by `include()`.
9694
- `part` - allows a partial match when asserting inclusion. Used by `include()`.
95+
- `shallow` - performs a comparison using strict equality (`===`). Code defaults to deep comparison. Used by `equal()` and `include()`.
9796

9897
```js
9998
const Code = require('code');
10099
const expect = Code.expect;
101100

102101
expect(10).to.not.be.above(20);
103-
expect([{ a: 1 }]).to.deep.include({ a: 1 });
102+
expect([1, 2, 3]).to.shallow.include(3);
104103
expect([1, 1, 2]).to.only.include([1, 2]);
105104
expect([1, 2]).to.once.include([1, 2]);
106105
expect([1, 2, 3]).to.part.include([1, 4]);
@@ -256,7 +255,7 @@ expect({ a: '1' }).to.be.an.object();
256255

257256
#### Values
258257

259-
Asserts that the reference value is equals to a predefined value.
258+
Asserts that the reference value is equal to a predefined value.
260259

261260
##### `true()`
262261

@@ -308,8 +307,7 @@ Aliases: `includes()`, `contain()`, `contains()`
308307

309308
Asserts that the reference value (a string, array, or object) includes the provided values where:
310309
- `values` - a single or array of values. If the reference value is a string, the values must be strings.
311-
If the reference value is an array, the values can be any array member (`deep` is required to compare
312-
non-literal types). If the reference value is an object, the values can be key names, or a single object
310+
If the reference value is an array, the values can be any array member. If the reference value is an object, the values can be key names, or a single object
313311
with key-value pairs to match.
314312

315313
```js
@@ -324,13 +322,13 @@ expect('abc').to.include(['a', 'c']);
324322
expect('abc').to.part.include(['a', 'd']);
325323

326324
expect([1, 2, 3]).to.include(1);
327-
expect([{ a: 1 }]).to.deep.include({ a: 1 });
325+
expect([{ a: 1 }]).to.include({ a: 1 });
328326
expect([1, 2, 3]).to.include([1, 2]);
329-
expect([{ a: 1 }]).to.deep.include([{ a: 1 }]);
327+
expect([{ a: 1 }]).to.include([{ a: 1 }]);
330328
expect([1, 1, 2]).to.only.include([1, 2]);
331329
expect([1, 2]).to.once.include([1, 2]);
332330
expect([1, 2, 3]).to.part.include([1, 4]);
333-
expect([[1], [2]]).to.deep.include([[1]]);
331+
expect([[1], [2]]).to.include([[1]]);
334332

335333
expect({ a: 1, b: 2, c: 3 }).to.include('a');
336334
expect({ a: 1, b: 2, c: 3 }).to.include(['a', 'c']);
@@ -339,7 +337,7 @@ expect({ a: 1, b: 2, c: 3 }).to.include({ a: 1 });
339337
expect({ a: 1, b: 2, c: 3 }).to.include({ a: 1, c: 3 });
340338
expect({ a: 1, b: 2, c: 3 }).to.part.include({ a: 1, d: 4 });
341339
expect({ a: 1, b: 2, c: 3 }).to.only.include({ a: 1, b: 2, c: 3 });
342-
expect({ a: [1], b: [2], c: [3] }).to.deep.include({ a: [1], c: [3] });
340+
expect({ a: [1], b: [2], c: [3] }).to.include({ a: [1], c: [3] });
343341
```
344342

345343
#### `startWith(value)`
@@ -417,21 +415,19 @@ expect('abcd').to.have.length(4);
417415

418416
Aliases: `equals()`
419417

420-
Asserts that the reference value equals the provided value (`deep` is required to compare non-literal
421-
types) where:
418+
Asserts that the reference value equals the provided value where:
422419
- `value` - the value to compare to.
423-
- `options` - optional object specifying comparison options. This is only used on
424-
deep comparisons, and is ignored otherwise.
420+
- `options` - optional object specifying comparison options. This is ignored on `shallow` comparisons.
425421

426422
```js
427423
const Code = require('code');
428424
const expect = Code.expect;
429425

430426
expect(5).to.equal(5);
431-
expect({ a: 1 }).to.deep.equal({ a: 1 });
427+
expect({ a: 1 }).to.equal({ a: 1 });
432428
```
433429

434-
Deep comparisons are performed using
430+
Deep comparisons (the default) are performed using
435431
[`Hoek.deepEqual()`](https://github.com/hapijs/hoek/blob/master/API.md#deepequalb-a-options). The
436432
optional `options` argument is passed directly to `Hoek.deepEqual()`. An example
437433
deep comparison which ignores object prototypes is shown below.
@@ -440,7 +436,17 @@ deep comparison which ignores object prototypes is shown below.
440436
const Code = require('code');
441437
const expect = Code.expect;
442438

443-
expect(Object.create(null)).to.deep.equal({}, { prototype: false });
439+
expect(Object.create(null)).to.equal({}, { prototype: false });
440+
```
441+
442+
Strict equality can be checked using the `shallow` modifier. This yields the same output as a `===` check.
443+
444+
```js
445+
const Code = require('code');
446+
const expect = Code.expect;
447+
448+
expect(5).to.shallow.equal(5);
449+
expect({ a: 1 }).to.shallow.equal({ a: 1 }); // fails as they are not the same reference
444450
```
445451

446452
#### `above(value)`
@@ -680,18 +686,21 @@ const expect = Code.expect;
680686
const foo = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
681687

682688
Code.settings.truncateMessages = false;
683-
expect(foo).to.deep.equal([]);
689+
expect(foo).to.equal([]);
684690
```
685691

686692
#### `comparePrototypes`
687693

688-
A boolean value that, when `false`, ignores object prototypes when doing a deep comparison. Defaults to `true`.
694+
A Boolean value that, when `false`, ignores object prototypes when doing a deep comparison. Defaults to `false`.
689695

690696
```js
691697
const Code = require('code');
692698
const expect = Code.expect;
693699
const foo = Object.create(null);
694700

695-
Code.setting.comparePrototypes = false;
696-
expect(foo).to.deep.equal({});
701+
Code.settings.comparePrototypes = false;
702+
expect(foo).to.equal({});
703+
704+
Code.settings.comparePrototypes = true;
705+
expect(foo).to.equal({}); // fails
697706
```

lib/index.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Hoek = require('hoek');
99
// Declare internals
1010

1111
const internals = {
12-
flags: ['deep', 'not', 'once', 'only', 'part'],
12+
flags: ['not', 'once', 'only', 'part', 'shallow'],
1313
grammar: ['a', 'an', 'and', 'at', 'be', 'have', 'in', 'to'],
1414
locations: {},
1515
count: 0
@@ -18,7 +18,7 @@ const internals = {
1818

1919
exports.settings = {
2020
truncateMessages: false,
21-
comparePrototypes: true
21+
comparePrototypes: false
2222
};
2323

2424

@@ -197,6 +197,7 @@ internals.addMethod('error', function (/*type, message*/) {
197197

198198
internals.include = function (value) {
199199

200+
this._flags.deep = !this._flags.shallow;
200201
return this.assert(Hoek.contain(this._ref, value, this._flags), 'include ' + internals.display(value));
201202
};
202203

@@ -260,8 +261,8 @@ internals.equal = function (value, options) {
260261
options = options || {};
261262
const settings = Hoek.applyToDefaults({ prototype: exports.settings.comparePrototypes }, options);
262263

263-
const compare = this._flags.deep ? (a, b) => Hoek.deepEqual(a, b, settings)
264-
: (a, b) => a === b;
264+
const compare = this._flags.shallow ? (a, b) => a === b
265+
: (a, b) => Hoek.deepEqual(a, b, settings);
265266

266267
return this.assert(compare(this._ref, value), 'equal specified value', this._ref, value);
267268
};

test/index.js

+85-16
Original file line numberDiff line numberDiff line change
@@ -320,17 +320,30 @@ describe('expect()', () => {
320320
try {
321321

322322
const obj = Object.create(null);
323-
Code.expect({}).to.deep.equal(obj);
323+
Code.expect({}).to.equal(obj);
324324
obj.foo = 'bar';
325-
Code.expect({ foo: 'bar' }).to.deep.equal(obj);
326-
Code.expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
325+
Code.expect({ foo: 'bar' }).to.equal(obj);
326+
Code.expect({ foo: 'bar' }).to.equal({ foo: 'bar' });
327327
}
328328
catch (err) {
329329
exception = err;
330330
}
331331

332332
Code.settings.comparePrototypes = origPrototype;
333333
Hoek.assert(!exception, exception);
334+
Code.settings.comparePrototypes = true;
335+
336+
try {
337+
338+
const obj = Object.create(null);
339+
Code.expect({}).to.equal(obj);
340+
}
341+
catch (err) {
342+
exception = err;
343+
}
344+
345+
Code.settings.comparePrototypes = origPrototype;
346+
Hoek.assert(exception.message === 'Expected {} to equal specified value', exception);
334347
done();
335348
});
336349

@@ -985,11 +998,17 @@ describe('expect()', () => {
985998
let exception = false;
986999
try {
9871000
Code.expect('abc').to.include('ab');
1001+
Code.expect('abc').to.shallow.include('ab');
9881002
Code.expect('abc').to.only.include('abc');
1003+
Code.expect('abc').to.only.shallow.include('abc');
9891004
Code.expect('aaa').to.only.include('a');
1005+
Code.expect('aaa').to.only.shallow.include('a');
9901006
Code.expect('abc').to.once.include('b');
1007+
Code.expect('abc').to.once.shallow.include('b');
9911008
Code.expect('abc').to.include(['a', 'c']);
1009+
Code.expect('abc').to.shallow.include(['a', 'c']);
9921010
Code.expect('abc').to.part.include(['a', 'd']);
1011+
Code.expect('abc').to.part.shallow.include(['a', 'd']);
9931012
}
9941013
catch (err) {
9951014
exception = err;
@@ -1004,13 +1023,14 @@ describe('expect()', () => {
10041023
let exception = false;
10051024
try {
10061025
Code.expect([1, 2, 3]).to.include(1);
1007-
Code.expect([{ a: 1 }]).to.deep.include({ a: 1 });
1026+
Code.expect([1, 2, 3]).to.shallow.include(1);
1027+
Code.expect([{ a: 1 }]).to.include({ a: 1 });
10081028
Code.expect([1, 2, 3]).to.include([1, 2]);
1009-
Code.expect([{ a: 1 }]).to.deep.include([{ a: 1 }]);
1029+
Code.expect([{ a: 1 }]).to.include([{ a: 1 }]);
10101030
Code.expect([1, 1, 2]).to.only.include([1, 2]);
10111031
Code.expect([1, 2]).to.once.include([1, 2]);
10121032
Code.expect([1, 2, 3]).to.part.include([1, 4]);
1013-
Code.expect([[1], [2]]).to.deep.include([[1]]);
1033+
Code.expect([[1], [2]]).to.include([[1]]);
10141034
}
10151035
catch (err) {
10161036
exception = err;
@@ -1020,18 +1040,33 @@ describe('expect()', () => {
10201040
done();
10211041
});
10221042

1043+
it('invalidates arrays (shallow)', (done) => {
1044+
1045+
let exception = false;
1046+
try {
1047+
Code.expect([{ a: 1 }]).to.shallow.include({ a: 1 });
1048+
}
1049+
catch (err) {
1050+
exception = err;
1051+
}
1052+
1053+
Hoek.assert(exception.message === 'Expected [ { a: 1 } ] to include { a: 1 }', exception);
1054+
done();
1055+
});
1056+
10231057
it('validates objects', (done) => {
10241058

10251059
let exception = false;
10261060
try {
10271061
Code.expect({ a: 1, b: 2, c: 3 }).to.include('a');
1062+
Code.expect({ a: 1, b: 2, c: 3 }).to.shallow.include('a');
10281063
Code.expect({ a: 1, b: 2, c: 3 }).to.include(['a', 'c']);
10291064
Code.expect({ a: 1, b: 2, c: 3 }).to.only.include(['a', 'b', 'c']);
10301065
Code.expect({ a: 1, b: 2, c: 3 }).to.include({ a: 1 });
10311066
Code.expect({ a: 1, b: 2, c: 3 }).to.include({ a: 1, c: 3 });
10321067
Code.expect({ a: 1, b: 2, c: 3 }).to.part.include({ a: 1, d: 4 });
10331068
Code.expect({ a: 1, b: 2, c: 3 }).to.only.include({ a: 1, b: 2, c: 3 });
1034-
Code.expect({ a: [1], b: [2], c: [3] }).to.deep.include({ a: [1], c: [3] });
1069+
Code.expect({ a: [1], b: [2], c: [3] }).to.include({ a: [1], c: [3] });
10351070
}
10361071
catch (err) {
10371072
exception = err;
@@ -1041,6 +1076,20 @@ describe('expect()', () => {
10411076
done();
10421077
});
10431078

1079+
it('invalidates objects (shallow)', (done) => {
1080+
1081+
let exception = false;
1082+
try {
1083+
Code.expect({ a: [1] }).to.shallow.include({ a: [1] });
1084+
}
1085+
catch (err) {
1086+
exception = err;
1087+
}
1088+
1089+
Hoek.assert(exception.message === 'Expected { a: [ 1 ] } to include { a: [ 1 ] }', exception);
1090+
done();
1091+
});
1092+
10441093
it('validates aliases', (done) => {
10451094

10461095
let exception = false;
@@ -1386,6 +1435,13 @@ describe('expect()', () => {
13861435
let exception = false;
13871436
try {
13881437
Code.expect('abc').to.equal('abc');
1438+
Code.expect(['abc']).to.equal(['abc']);
1439+
Code.expect({ a: 1 }).to.equal({ a: 1 });
1440+
Code.expect({}).to.not.equal({ a: 1 });
1441+
Code.expect({ a: 1 }).to.not.equal({});
1442+
Code.expect(Object.create(null)).to.not.equal({}, { prototype: true });
1443+
Code.expect(Object.create(null)).to.equal({}, { prototype: false });
1444+
Code.expect(Object.create(null)).to.equal({});
13891445
}
13901446
catch (err) {
13911447
exception = err;
@@ -1409,16 +1465,29 @@ describe('expect()', () => {
14091465
done();
14101466
});
14111467

1412-
it('validates assertion (deep)', (done) => {
1468+
it('invalidates assertion', (done) => {
14131469

14141470
let exception = false;
14151471
try {
1416-
Code.expect(['abc']).to.deep.equal(['abc']);
1417-
Code.expect({ a: 1 }).to.deep.equal({ a: 1 });
1418-
Code.expect({}).to.not.deep.equal({ a: 1 });
1419-
Code.expect({ a: 1 }).to.not.deep.equal({});
1420-
Code.expect(Object.create(null)).to.not.deep.equal({});
1421-
Code.expect(Object.create(null)).to.deep.equal({}, { prototype: false });
1472+
Code.expect({ foo: 1 }).to.equal({ foo: 2 });
1473+
}
1474+
catch (err) {
1475+
exception = err;
1476+
}
1477+
1478+
Hoek.assert(exception.message === 'Expected { foo: 1 } to equal specified value', exception);
1479+
done();
1480+
});
1481+
1482+
it('validates assertion (shallow)', (done) => {
1483+
1484+
let exception = false;
1485+
try {
1486+
const foo = { bar: 'baz' };
1487+
1488+
Code.expect('a').to.shallow.equal('a');
1489+
Code.expect(1).to.shallow.equal(1);
1490+
Code.expect(foo).to.shallow.equal(foo);
14221491
}
14231492
catch (err) {
14241493
exception = err;
@@ -1428,11 +1497,11 @@ describe('expect()', () => {
14281497
done();
14291498
});
14301499

1431-
it('invalidates assertion', (done) => {
1500+
it('invalidates assertion (shallow)', (done) => {
14321501

14331502
let exception = false;
14341503
try {
1435-
Code.expect(['a']).to.equal(['a']);
1504+
Code.expect(['a']).to.shallow.equal(['a']);
14361505
}
14371506
catch (err) {
14381507
exception = err;

0 commit comments

Comments
 (0)