Skip to content

Commit

Permalink
Merge pull request #108 from astorije/astorije/property-tests
Browse files Browse the repository at this point in the history
Tests and clean ups around `.property`
  • Loading branch information
astorije authored Nov 27, 2017
2 parents 29532f8 + d7aef22 commit e92c116
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 45 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ is equal to the given `val`. `val` can be an Immutable object.
expect(map).to.have.property('foo', 'bar');
```

Note that `deep.property` behaves exactly like `property` in the context of
immutable data structures.

Add `.nested` earlier in the chain to enable dot- and bracket-notation when
referencing nested properties.

Expand Down
4 changes: 4 additions & 0 deletions chai-immutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@
* expect(map).to.have.property('foo', 'bar');
* ```
*
* Note that `deep.property` behaves exactly like `property` in the context of
* immutable data structures.
*
* Add `.nested` earlier in the chain to enable dot- and bracket-notation when
* referencing nested properties.
*
Expand Down Expand Up @@ -452,6 +455,7 @@
* ```
*
* @name property
* @alias deep.equal
* @param {String|Array|Iterable} path
* @param {Mixed} val (optional)
* @returns value of property for chaining
Expand Down
168 changes: 123 additions & 45 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,121 +402,144 @@ describe('chai-immutable', function () { // eslint-disable-line prefer-arrow-cal
expect({ x: 1 }).not.to.have.property('z', 42);
});

// All following tests assert against regular `.property` and
// `.deep.property`. In the Immutable world, these are supposed to carry
// the same meaning (similar to `.equal` vs. `.deep.equal`).
const obj = Immutable.fromJS({ x: 1 });
const nestedObj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });

it('should fail given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
fail(() => expect(obj).to.have.property('z'));
fail(() => expect(obj).to.have.deep.property('z'));
});

it('should pass using `not` given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
expect(obj).not.to.have.property('z');
expect(obj).not.to.have.deep.property('z');
});

it('should pass using `not` given an inexisting property and value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
expect(obj).not.to.have.property('z', 42);
expect(obj).not.to.have.deep.property('z', 42);
});

it('should pass given an existing property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
expect(obj).to.have.property('x');
expect(obj).to.have.deep.property('x');
});

it('should fail using `not` given an existing property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
fail(() => expect(obj).not.to.have.property('x'));
fail(() => expect(obj).not.to.have.deep.property('x'));
});

it('should fail given a property with a bad value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
fail(() => expect(obj).to.have.property('x', 'different'));
fail(() => expect(obj).to.have.deep.property('x', 'different'));
});

it('should pass given a property with the good value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
expect(obj).to.have.property('x', 1);
expect(obj).to.have.deep.property('x', 1);
});

it('should pass given an immutable value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ foo: { bar: 42 } });
expect(obj).to.have.property('foo', new Map({ bar: 42 }));
const obj2 = Immutable.fromJS({ foo: { bar: 42 } });
expect(obj2).to.have.property('foo', new Map({ bar: 42 }));
expect(obj2).to.have.deep.property('foo', new Map({ bar: 42 }));
});

it('should change the subject to the value of that property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
const sub = obj.get('y');
expect(obj).to.have.property('y').that.equal(sub);
const sub = nestedObj.get('y');
expect(nestedObj).to.have.property('y').that.equal(sub);
expect(nestedObj).to.have.deep.property('y').that.equal(sub);
});

describe('using the `nested` flag', function () { // eslint-disable-line prefer-arrow-callback
it('should not affect the original assertion', function () { // eslint-disable-line prefer-arrow-callback
expect({ x: 1, y: { x: 2, y: 3 } }).to.have.nested.property('y.x', 2);
expect({ x: 1, y: { x: 2, y: 3 } })
.to.have.nested.deep.property('y.x', 2);
});

it('should not affect the original assertion using `not`', function () { // eslint-disable-line prefer-arrow-callback
expect({ x: 1, y: { x: 2 } }).not.to.have.nested.property('z.z');
expect({ x: 1, y: { x: 2 } }).not.to.have.nested.deep.property('z.z');
expect({ x: 1, y: { x: 2 } }).not.to.have.nested.property('z.z', 42);
expect({ x: 1, y: { x: 2 } })
.not.to.have.nested.deep.property('z.z', 42);
});

it('should fail given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
fail(() => expect(obj).to.have.nested.property(['y', 'z']));
fail(() => expect(nestedObj).to.have.nested.property(['y', 'z']));
fail(() => expect(nestedObj)
.to.have.nested.deep.property(['y', 'z']));
});

it('should pass using `not` given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
expect(obj).not.to.have.nested.property(['y', 'z']);
expect(nestedObj).not.to.have.nested.property(['y', 'z']);
expect(nestedObj).not.to.have.nested.deep.property(['y', 'z']);
});

it('should pass using `not` given an inexisting property and value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
expect(obj).not.to.have.nested.property(['y', 'x'], 'different');
expect(obj).not.to.have.nested.deep.property(['y', 'x'], 'different');
});

it('should pass given an existing property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
expect(obj).to.have.nested.property(['y', 'x']);
expect(nestedObj).to.have.nested.property(['y', 'x']);
expect(nestedObj).to.have.nested.deep.property(['y', 'x']);
});

it('should pass given an index', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ items: ['a', 'b', 'c'] });
expect(obj).to.have.nested.property(['items', 2], 'c');
const obj2 = Immutable.fromJS({ items: ['a', 'b', 'c'] });
expect(obj2).to.have.nested.property(['items', 2], 'c');
expect(obj2).to.have.nested.deep.property(['items', 2], 'c');
});

it('should fail using `not` given an existing property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
fail(() => expect(obj).not.to.have.nested.property(['y', 'x']));
fail(() => expect(nestedObj).not.to.have.nested.property(['y', 'x']));
fail(() => expect(nestedObj)
.not.to.have.nested.deep.property(['y', 'x']));
});

it('should fail given a property with a bad value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
fail(() => expect(obj)
fail(() => expect(nestedObj)
.to.have.nested.property(['y', 'x'], 'different'));
fail(() => expect(nestedObj)
.to.have.nested.deep.property(['y', 'x'], 'different'));
});

it('should pass given a property with the good value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
expect(obj).to.have.nested.property(['y', 'x'], 2);
expect(nestedObj).to.have.nested.property(['y', 'x'], 2);
expect(nestedObj).to.have.nested.deep.property(['y', 'x'], 2);
});

it('should fail using `not` given a property with good value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2 } });
fail(() => expect(obj).not.to.have.nested.property(['y', 'x'], 2));
fail(() => expect(nestedObj)
.not.to.have.nested.property(['y', 'x'], 2));
fail(() => expect(nestedObj)
.not.to.have.nested.deep.property(['y', 'x'], 2));
});

it('should pass using `not` given a property with a bad value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2 } });
expect(obj).not.to.have.nested.property(['y', 'x'], 'different');
expect(nestedObj)
.not.to.have.nested.property(['y', 'x'], 'different');
expect(nestedObj)
.not.to.have.nested.deep.property(['y', 'x'], 'different');
});

it('should pass given an immutable value', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ foo: [{ bar: 42 }] });
expect(obj).to.have.nested.property('foo[0]', new Map({ bar: 42 }));
const nestedObj2 = Immutable.fromJS({ foo: [{ bar: 42 }] });
expect(nestedObj2)
.to.have.nested.property('foo[0]', new Map({ bar: 42 }));
expect(nestedObj2)
.to.have.nested.deep.property('foo[0]', new Map({ bar: 42 }));
});
});

describe('given a string-based path', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({
const nestedObj2 = Immutable.fromJS({
items: [
{ name: 'Jane' },
{ name: 'John' },
Expand All @@ -525,12 +548,20 @@ describe('chai-immutable', function () { // eslint-disable-line prefer-arrow-cal
});

it('should pass using `nested` given a single index', function () { // eslint-disable-line prefer-arrow-callback
expect(obj.get('items')).to.have.nested.property('[1]')
expect(nestedObj2.get('items')).to.have.nested.property('[1]')
.that.equals(new Map({ name: 'John' }));
expect(nestedObj2.get('items')).to.have.nested.deep.property('[1]')
.that.equals(new Map({ name: 'John' }));
});

it('should pass using `nested` given a single key', function () { // eslint-disable-line prefer-arrow-callback
expect(obj).to.have.nested.property('items')
expect(nestedObj2).to.have.nested.property('items')
.that.equals(new List([
new Map({ name: 'Jane' }),
new Map({ name: 'John' }),
new Map({ name: 'Jim' }),
]));
expect(nestedObj2).to.have.nested.deep.property('items')
.that.equals(new List([
new Map({ name: 'Jane' }),
new Map({ name: 'John' }),
Expand All @@ -539,26 +570,36 @@ describe('chai-immutable', function () { // eslint-disable-line prefer-arrow-cal
});

it('should pass using `nested` starting with an index', function () { // eslint-disable-line prefer-arrow-callback
expect(obj.get('items')).to.have.nested.property('[0].name', 'Jane');
expect(nestedObj2.get('items'))
.to.have.nested.property('[0].name', 'Jane');
expect(nestedObj2.get('items'))
.to.have.nested.deep.property('[0].name', 'Jane');
});

it('should pass using `nested` ending with an index', function () { // eslint-disable-line prefer-arrow-callback
expect(obj).to.have.nested.property('items[1]')
expect(nestedObj2).to.have.nested.property('items[1]')
.that.equals(new Map({ name: 'John' }));
expect(nestedObj2).to.have.nested.deep.property('items[1]')
.that.equals(new Map({ name: 'John' }));
});

it('should pass using `nested` given mix of keys and indices', function () { // eslint-disable-line prefer-arrow-callback
expect(obj).to.have.nested.property('items[2].name', 'Jim');
expect(nestedObj2).to.have.nested.property('items[2].name', 'Jim');
expect(nestedObj2)
.to.have.nested.deep.property('items[2].name', 'Jim');
});

it('should expect unescaped path strings', function () { // eslint-disable-line prefer-arrow-callback
const css = new Map({ '.link[target]': 42 });
expect(css).to.have.property('.link[target]', 42);
expect(css).to.have.deep.property('.link[target]', 42);
});

it('should expect escaped path strings using `nested`', function () { // eslint-disable-line prefer-arrow-callback
const nestedCss = new Map({ '.link': new Map({ '[target]': 42 }) });
expect(nestedCss).to.have.nested.property('\\.link.\\[target\\]', 42);
expect(nestedCss)
.to.have.nested.deep.property('\\.link.\\[target\\]', 42);
});
});
});
Expand Down Expand Up @@ -861,19 +902,56 @@ describe('chai-immutable', function () { // eslint-disable-line prefer-arrow-cal
});

describe('property assertions', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
const nestedObj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });

it('should pass for existing property', function () { // eslint-disable-line prefer-arrow-callback
assert.property(obj, 'x');
});

it('should fail for missing property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1 });
fail(() => assert.property(obj, 'z'));
});

it('should pass for missing property using `not`', function () { // eslint-disable-line prefer-arrow-callback
assert.notProperty(obj, 'z');
});

it('should fail for existing property using `not`', function () { // eslint-disable-line prefer-arrow-callback
fail(() => assert.notProperty(obj, 'x'));
});

it('should pass for existing property and value', function () { // eslint-disable-line prefer-arrow-callback
assert.propertyVal(obj, 'x', 1);
assert.deepPropertyVal(obj, 'x', 1);
});

it('should fail for wrong property or value', function () { // eslint-disable-line prefer-arrow-callback
fail(() => assert.propertyVal(obj, 'z', 1));
fail(() => assert.deepPropertyVal(obj, 'z', 1));
fail(() => assert.propertyVal(obj, 'x', 42));
fail(() => assert.deepPropertyVal(obj, 'x', 42));
});

it('should pass for wrong property or value using `not`', function () { // eslint-disable-line prefer-arrow-callback
assert.notPropertyVal(obj, 'z', 1);
assert.notDeepPropertyVal(obj, 'z', 1);
assert.notPropertyVal(obj, 'x', 42);
assert.notDeepPropertyVal(obj, 'x', 42);
});

it('should fail for existing property and value using `not`', function () { // eslint-disable-line prefer-arrow-callback
fail(() => assert.notPropertyVal(obj, 'x', 1));
fail(() => assert.notDeepPropertyVal(obj, 'x', 1));
});

it('should succeed for equal nested property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
assert.nestedProperty(obj, ['y', 'x']);
assert.nestedProperty(nestedObj, ['y', 'x']);
});

it('should fail for unequal deep property', function () { // eslint-disable-line prefer-arrow-callback
const obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } });
fail(() => assert.nestedPropertyVal(obj, ['y', 'x'], 'different'));
it('should fail for unequal nested property', function () { // eslint-disable-line prefer-arrow-callback
fail(() => assert.nestedPropertyVal(nestedObj, ['y', 'x'], 42));
fail(() => assert.deepNestedPropertyVal(nestedObj, ['y', 'x'], 42));
});
});

Expand Down

0 comments on commit e92c116

Please sign in to comment.