Skip to content

Commit

Permalink
Implement iterable assertion
Browse files Browse the repository at this point in the history
  • Loading branch information
koddsson committed Jan 28, 2024
1 parent 44b81df commit 77ca057
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 11 deletions.
37 changes: 36 additions & 1 deletion lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ function an (type, msg) {
, 'expected #{this} to be ' + article + type
, 'expected #{this} not to be ' + article + type
);
} else if (type === 'iterable') {
this.assert(
typeof obj !== 'string' && obj != undefined && obj[Symbol.iterator]
, 'expected #{this} to be ' + article + type
, 'expected #{this} not to be ' + article + type
);
} else {
this.assert(
type === detectedType
Expand Down Expand Up @@ -3133,7 +3139,6 @@ function isSubsetOf(subset, superset, cmp, contains, ordered) {
* @namespace BDD
* @api public
*/

Assertion.addMethod('members', function (subset, msg) {
if (msg) flag(this, 'message', msg);
var obj = flag(this, 'object')
Expand Down Expand Up @@ -3170,6 +3175,36 @@ Assertion.addMethod('members', function (subset, msg) {
);
});

/**
* ### .iterable
*
* Asserts that the target is an iterable, which means that it has a iterator
* with the exception of `String.`
*
* expect([1, 2]).to.be.iterable;
*
* Add `.not` earlier in the chain to negate `.iterable`.
*
* expect(1).to.not.be.iterable;
* expect("foobar").to.not.be.iterable;
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(1, 'nooo why fail??').to.be.iterable;
*
* @name iterable
* @namespace BDD
* @api public
*/
Assertion.addProperty('iterable', function(msg) {
if (msg) flag(this, 'message', msg);
var obj = flag(this, 'object')
, flagMsg = flag(this, 'message')
, ssfi = flag(this, 'ssfi');

new Assertion(obj, flagMsg, ssfi, true).to.be.an('iterable');
});

/**
* ### .oneOf(list[, msg])
*
Expand Down
18 changes: 17 additions & 1 deletion lib/chai/interface/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import * as chai from '../../../index.js';
import {Assertion} from '../assertion.js';
import {flag, inspect} from '../utils/index.js';
import {AssertionError} from 'assertion-error';
import {type} from '../utils/type-detect.js';

/**
* ### assert(expression, message)
Expand Down Expand Up @@ -2485,6 +2484,23 @@ assert.oneOf = function (inList, list, msg) {
new Assertion(inList, msg, assert.oneOf, true).to.be.oneOf(list);
}

/**
* ### isIterable(obj, [message])
*
* Asserts that the target is an iterable, which means that it has a iterator
* with the exception of `String.`
*
* assert.isIterable([1, 2]);
*
* @param {unknown} obj
* @param {string} [msg]
* @namespace Assert
* @api public
*/
assert.isIterable = function(obj, msg) {
new Assertion(obj, msg, assert.isIterable, true).to.be.an('iterable');
}

/**
* ### .changes(function, object, property, [message])
*
Expand Down
34 changes: 32 additions & 2 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -1979,11 +1979,11 @@ describe('assert', function () {

err(function () {
assert.sameMembers({}, [], 'blah');
}, 'blah: expected {} to be an array');
}, 'blah: expected {} to be an iterable');

err(function () {
assert.sameMembers([], {}, 'blah');
}, 'blah: expected {} to be an array');
}, 'blah: expected {} to be an iterable');
});

it('notSameMembers', function() {
Expand Down Expand Up @@ -2375,6 +2375,36 @@ describe('assert', function () {
}, 'blah: the argument to most must be a number');
});

it('iterable', function() {
assert.isIterable([1, 2, 3]);
assert.isIterable(new Map([[1, 'one'], [2, 'two'], [3, 'three']]));
assert.isIterable(new Set([1, 2, 3]));

err(function() {
assert.isIterable(42);
}, 'expected 42 to be an iterable');

err(function() {
assert.isIterable('hello');
}, "expected 'hello' to be an iterable");

err(function() {
assert.isIterable(undefined);
}, 'expected undefined to be an iterable');

err(function() {
assert.isIterable(null);
}, 'expected null to be an iterable');

err(function() {
assert.isIterable(true);
}, 'expected true to be an iterable');

err(function() {
assert.isIterable({ key: 'value' });
}, 'expected { key: \'value\' } to be an iterable');
});

it('change', function() {
var obj = { value: 10, str: 'foo' },
heroes = ['spiderman', 'superman'],
Expand Down
38 changes: 34 additions & 4 deletions test/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3508,19 +3508,19 @@ describe('expect', function () {

err(function () {
expect({}).members([], 'blah');
}, 'blah: expected {} to be an array');
}, 'blah: expected {} to be an iterable');

err(function () {
expect({}, 'blah').members([]);
}, 'blah: expected {} to be an array');
}, 'blah: expected {} to be an iterable');

err(function () {
expect([]).members({}, 'blah');
}, 'blah: expected {} to be an array');
}, 'blah: expected {} to be an iterable');

err(function () {
expect([], 'blah').members({});
}, 'blah: expected {} to be an array');
}, 'blah: expected {} to be an iterable');
});

it('deep.members', function() {
Expand Down Expand Up @@ -3641,6 +3641,36 @@ describe('expect', function () {
}, 'expected [ { a: 1 }, { b: 2 }, { c: 3 } ] to not be an ordered superset of [ { a: 1 }, { b: 2 } ]');
});

it('iterable', function() {
expect([1, 2, 3]).to.be.iterable;
expect(new Map([[1, 'one'], [2, 'two'], [3, 'three']])).to.be.iterable;
expect(new Set([1, 2, 3])).to.be.iterable;

err(function() {
expect(42).to.be.iterable;
}, 'expected 42 to be an iterable');

err(function() {
expect('hello').to.be.iterable;
}, "expected 'hello' to be an iterable");

err(function() {
expect(undefined).to.be.iterable;
}, 'expected undefined to be an iterable');

err(function() {
expect(null).to.be.iterable;
}, 'expected null to be an iterable');

err(function() {
expect(true).to.be.iterable;
}, 'expected true to be an iterable');

err(function() {
expect({ key: 'value' }).to.be.iterable;
}, 'expected { key: \'value\' } to be an iterable');
})

it('change', function() {
var obj = { value: 10, str: 'foo' },
heroes = ['spiderman', 'superman'],
Expand Down
28 changes: 25 additions & 3 deletions test/should.js
Original file line number Diff line number Diff line change
Expand Up @@ -2820,11 +2820,11 @@ describe('should', function() {

err(function() {
'foo'.should.include.members([12], 'blah');
}, "blah: expected 'foo' to be an array");
}, "blah: expected 'foo' to be an iterable");

err(function() {
[1, 2, 3].should.include.members('o', 'blah');
}, "blah: expected 'o' to be an array");
}, "blah: expected 'o' to be an iterable");
});

it('memberEquals', function() {
Expand All @@ -2845,7 +2845,7 @@ describe('should', function() {

err(function() {
[1, 2, 3].should.have.same.members(4, 'blah');
}, 'blah: expected 4 to be an array');
}, 'blah: expected 4 to be an iterable');
});

it('deep.members', function() {
Expand Down Expand Up @@ -2942,6 +2942,28 @@ describe('should', function() {
}, 'expected [ { a: 1 }, { b: 2 }, { c: 3 } ] to not be an ordered superset of [ { a: 1 }, { b: 2 } ]');
});

it ('iterable', function() {
([1, 2, 3]).should.be.iterable;
(new Map([[1, 'one'], [2, 'two'], [3, 'three']])).should.be.iterable;
(new Set([1, 2, 3])).should.be.iterable;

err(function() {
(42).should.be.iterable;
}, 'expected 42 to be an iterable');

err(function() {
('hello').should.be.iterable;
}, "expected 'hello' to be an iterable");

err(function() {
(true).should.be.iterable;
}, 'expected true to be an iterable');

err(function() {
({ key: 'value' }).should.be.iterable;
}, 'expected { key: \'value\' } to be an iterable');
})

it('change', function() {
var obj = { value: 10, str: 'foo' },
heroes = ['spiderman', 'superman'],
Expand Down

0 comments on commit 77ca057

Please sign in to comment.