Repository: chaijs/chai
Pull request #828 (2016-10-05 07:32:19)

Add .empty to assert interface
Follow-up to #812.

meeber: LGTM!
lucasfcosta: I just left a minor nitpicky comment about the accepted types of arguments for the method on the assert interface.

If you think it's not needed feel free to merge.

Despite that, LGTM! Awesome work @shvaikalesh! Thank you for this :smile:  
shvaikalesh: @lucasfcosta thanks for the review, fixed that.
lucasfcosta: LGTM.
I'll merge this since the only change since @meeber's LGTM were comments.
Thanks for you work, good job :smile: 

Patch:
diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js
index 5471b37..6a3f8ec 100644
--- a/lib/chai/core/assertions.js
+++ b/lib/chai/core/assertions.js
@@ -513,12 +513,15 @@ module.exports = function (chai, _) {
   /**
    * ### .empty
    *
-   * Asserts that the target's length is `0`. For arrays and strings, it checks
-   * the `length` property. For non-function objects, it gets the count of own
+   * Asserts that the target does not contain any values.
+   * For arrays and strings, it checks the `length` property.
+   * For `Map` and `Set` instances, it checks the `size` property.
+   * For non-function objects, it gets the count of own
    * enumerable string keys.
    *
    *     expect([]).to.be.empty;
    *     expect('').to.be.empty;
+   *     expect(new Map).to.be.empty;
    *     expect({}).to.be.empty;
    *
    * @name empty
diff --git a/lib/chai/interface/assert.js b/lib/chai/interface/assert.js
index edafc32..b010afa 100644
--- a/lib/chai/interface/assert.js
+++ b/lib/chai/interface/assert.js
@@ -2768,6 +2768,58 @@ module.exports = function (chai, util) {
     new Assertion(obj, msg).to.not.be.frozen;
   };
 
+  /**
+   * ### .isEmpty(target)
+   *
+   * Asserts that the target does not contain any values.
+   * For arrays and strings, it checks the `length` property.
+   * For `Map` and `Set` instances, it checks the `size` property.
+   * For non-function objects, it gets the count of own
+   * enumerable string keys.
+   *
+   *     assert.isEmpty([]);
+   *     assert.isEmpty('');
+   *     assert.isEmpty(new Map);
+   *     assert.isEmpty({});
+   *
+   * @name isEmpty
+   * @alias empty
+   * @param {Object|Array|String|Map|Set} target
+   * @param {String} message _optional_
+   * @namespace Assert
+   * @api public
+   */
+
+  assert.isEmpty = function(val, msg) {
+    new Assertion(val, msg).to.be.empty;
+  };
+
+  /**
+   * ### .isNotEmpty(target)
+   *
+   * Asserts that the target contains values.
+   * For arrays and strings, it checks the `length` property.
+   * For `Map` and `Set` instances, it checks the `size` property.
+   * For non-function objects, it gets the count of own
+   * enumerable string keys.
+   *
+   *     assert.isNotEmpty([1, 2]);
+   *     assert.isNotEmpty('34');
+   *     assert.isNotEmpty(new Set([5, 6]));
+   *     assert.isNotEmpty({ key: 7 });
+   *
+   * @name isNotEmpty
+   * @alias notEmpty
+   * @param {Object|Array|String|Map|Set} target
+   * @param {String} message _optional_
+   * @namespace Assert
+   * @api public
+   */
+
+  assert.isNotEmpty = function(val, msg) {
+    new Assertion(val, msg).to.not.be.empty;
+  };
+
   /*!
    * Aliases.
    */
@@ -2785,5 +2837,7 @@ module.exports = function (chai, util) {
   ('isSealed', 'sealed')
   ('isNotSealed', 'notSealed')
   ('isFrozen', 'frozen')
-  ('isNotFrozen', 'notFrozen');
+  ('isNotFrozen', 'notFrozen')
+  ('isEmpty', 'empty')
+  ('isNotEmpty', 'notEmpty');
 };


Test patch:
diff --git a/test/assert.js b/test/assert.js
index ed4b453..d8d3db0 100644
--- a/test/assert.js
+++ b/test/assert.js
@@ -2107,6 +2107,220 @@ describe('assert', function () {
     });
   });
 
+  it('isEmpty / empty', function() {
+    ['isEmpty', 'empty'].forEach(function (isEmpty) {
+      function FakeArgs() {};
+      FakeArgs.prototype.length = 0;
+
+      assert[isEmpty]('');
+      assert[isEmpty]([]);
+      assert[isEmpty](new FakeArgs);
+      assert[isEmpty]({});
+
+      if (typeof WeakMap === 'function') {
+        err(function(){
+          assert[isEmpty](new WeakMap);
+        }, ".empty was passed a weak collection");
+      }
+
+      if (typeof WeakSet === 'function') {
+        err(function(){
+          assert[isEmpty](new WeakSet);
+        }, ".empty was passed a weak collection");
+      }
+
+      if (typeof Map === 'function') {
+        assert[isEmpty](new Map);
+
+        var map = new Map;
+        map.key = 'val';
+        assert[isEmpty](map);
+      }
+
+      if (typeof Set === 'function') {
+        assert[isEmpty](new Set);
+
+        var set = new Set;
+        set.key = 'val';
+        assert[isEmpty](set);
+      }
+
+      err(function(){
+        assert[isEmpty]('foo');
+      }, "expected \'foo\' to be empty");
+
+      err(function(){
+        assert[isEmpty](['foo']);
+      }, "expected [ \'foo\' ] to be empty");
+
+      err(function(){
+        assert[isEmpty]({arguments: 0});
+      }, "expected { arguments: 0 } to be empty");
+
+      err(function(){
+        assert[isEmpty]({foo: 'bar'});
+      }, "expected { foo: \'bar\' } to be empty");
+
+      err(function(){
+        assert[isEmpty](null);
+      }, ".empty was passed non-string primitive null");
+
+      err(function(){
+        assert[isEmpty](undefined);
+      }, ".empty was passed non-string primitive undefined");
+
+      err(function(){
+        assert[isEmpty]();
+      }, ".empty was passed non-string primitive undefined");
+
+      err(function(){
+        assert[isEmpty](0);
+      }, ".empty was passed non-string primitive 0");
+
+      err(function(){
+        assert[isEmpty](1);
+      }, ".empty was passed non-string primitive 1");
+
+      err(function(){
+        assert[isEmpty](true);
+      }, ".empty was passed non-string primitive true");
+
+      err(function(){
+        assert[isEmpty](false);
+      }, ".empty was passed non-string primitive false");
+
+      if (typeof Symbol !== 'undefined') {
+        err(function(){
+          assert[isEmpty](Symbol());
+        }, ".empty was passed non-string primitive Symbol()");
+
+        err(function(){
+          assert[isEmpty](Symbol.iterator);
+        }, ".empty was passed non-string primitive Symbol(Symbol.iterator)");
+      }
+
+      err(function(){
+        assert[isEmpty](function() {});
+      }, ".empty was passed a function");
+
+      if (FakeArgs.name === 'FakeArgs') {
+        err(function(){
+          assert[isEmpty](FakeArgs);
+        }, ".empty was passed a function FakeArgs");
+      }
+    });
+  });
+
+  it('isNotEmpty / notEmpty', function() {
+    ['isNotEmpty', 'notEmpty'].forEach(function (isNotEmpty) {
+      function FakeArgs() {};
+      FakeArgs.prototype.length = 0;
+
+      assert[isNotEmpty]('foo');
+      assert[isNotEmpty](['foo']);
+      assert[isNotEmpty]({arguments: 0});
+      assert[isNotEmpty]({foo: 'bar'});
+
+      if (typeof WeakMap === 'function') {
+        err(function(){
+          assert[isNotEmpty](new WeakMap);
+        }, ".empty was passed a weak collection");
+      }
+
+      if (typeof WeakSet === 'function') {
+        err(function(){
+          assert[isNotEmpty](new WeakSet);
+        }, ".empty was passed a weak collection");
+      }
+
+      if (typeof Map === 'function') {
+        // Not using Map constructor args because not supported in IE 11.
+        var map = new Map;
+        map.set('a', 1);
+        assert[isNotEmpty](map);
+
+        err(function(){
+          assert[isNotEmpty](new Map);
+        }, "expected {} not to be empty");
+      }
+
+      if (typeof Set === 'function') {
+        // Not using Set constructor args because not supported in IE 11.
+        var set = new Set;
+        set.add(1);
+        assert[isNotEmpty](set);
+
+        err(function(){
+          assert[isNotEmpty](new Set);
+        }, "expected {} not to be empty");
+      }
+
+      err(function(){
+        assert[isNotEmpty]('');
+      }, "expected \'\' not to be empty");
+
+      err(function(){
+        assert[isNotEmpty]([]);
+      }, "expected [] not to be empty");
+
+      err(function(){
+        assert[isNotEmpty](new FakeArgs);
+      }, "expected { length: 0 } not to be empty");
+
+      err(function(){
+        assert[isNotEmpty]({});
+      }, "expected {} not to be empty");
+
+      err(function(){
+        assert[isNotEmpty](null);
+      }, ".empty was passed non-string primitive null");
+
+      err(function(){
+        assert[isNotEmpty](undefined);
+      }, ".empty was passed non-string primitive undefined");
+
+      err(function(){
+        assert[isNotEmpty]();
+      }, ".empty was passed non-string primitive undefined");
+
+      err(function(){
+        assert[isNotEmpty](0);
+      }, ".empty was passed non-string primitive 0");
+
+      err(function(){
+        assert[isNotEmpty](1);
+      }, ".empty was passed non-string primitive 1");
+
+      err(function(){
+        assert[isNotEmpty](true);
+      }, ".empty was passed non-string primitive true");
+
+      err(function(){
+        assert[isNotEmpty](false);
+      }, ".empty was passed non-string primitive false");
+
+      if (typeof Symbol !== 'undefined') {
+        err(function(){
+          assert[isNotEmpty](Symbol());
+        }, ".empty was passed non-string primitive Symbol()");
+
+        err(function(){
+          assert[isNotEmpty](Symbol.iterator);
+        }, ".empty was passed non-string primitive Symbol(Symbol.iterator)");
+      }
+
+      err(function(){
+        assert[isNotEmpty](function() {});
+      }, ".empty was passed a function");
+
+      if (FakeArgs.name === 'FakeArgs') {
+        err(function(){
+          assert[isNotEmpty](FakeArgs);
+        }, ".empty was passed a function FakeArgs");
+      }
+    });
+  });
+
   it('showDiff true with actual and expected args', function() {
     try {
       new chai.Assertion().assert(