Skip to content

Commit c0e6dd7

Browse files
committed
Implement iterator assertion
1 parent 44b81df commit c0e6dd7

File tree

5 files changed

+138
-3
lines changed

5 files changed

+138
-3
lines changed

lib/chai/core/assertions.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,12 @@ function an (type, msg) {
319319
, 'expected #{this} to be ' + article + type
320320
, 'expected #{this} not to be ' + article + type
321321
);
322+
} else if (type === 'iterable') {
323+
this.assert(
324+
typeof obj !== 'string' && obj != undefined && obj[Symbol.iterator]
325+
, 'expected #{this} to be ' + article + type
326+
, 'expected #{this} not to be ' + article + type
327+
);
322328
} else {
323329
this.assert(
324330
type === detectedType
@@ -3037,7 +3043,9 @@ Assertion.addMethod('closeTo', closeTo);
30373043
Assertion.addMethod('approximately', closeTo);
30383044

30393045
// Note: Duplicates are ignored if testing for inclusion instead of sameness.
3040-
function isSubsetOf(subset, superset, cmp, contains, ordered) {
3046+
function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3047+
let superset = Array.from(_superset);
3048+
let subset = Array.from(_subset);
30413049
if (!contains) {
30423050
if (subset.length !== superset.length) return false;
30433051
superset = superset.slice();
@@ -3133,7 +3141,6 @@ function isSubsetOf(subset, superset, cmp, contains, ordered) {
31333141
* @namespace BDD
31343142
* @api public
31353143
*/
3136-
31373144
Assertion.addMethod('members', function (subset, msg) {
31383145
if (msg) flag(this, 'message', msg);
31393146
var obj = flag(this, 'object')
@@ -3170,6 +3177,36 @@ Assertion.addMethod('members', function (subset, msg) {
31703177
);
31713178
});
31723179

3180+
/**
3181+
* ### .iterable
3182+
*
3183+
* Asserts that the target is an iterable, which means that it has a iterator
3184+
* with the exception of `String.`
3185+
*
3186+
* expect([1, 2]).to.be.iterable;
3187+
*
3188+
* Add `.not` earlier in the chain to negate `.iterable`.
3189+
*
3190+
* expect(1).to.not.be.iterable;
3191+
* expect("foobar").to.not.be.iterable;
3192+
*
3193+
* A custom error message can be given as the second argument to `expect`.
3194+
*
3195+
* expect(1, 'nooo why fail??').to.be.iterable;
3196+
*
3197+
* @name iterable
3198+
* @namespace BDD
3199+
* @api public
3200+
*/
3201+
Assertion.addProperty('iterable', function(msg) {
3202+
if (msg) flag(this, 'message', msg);
3203+
var obj = flag(this, 'object')
3204+
, flagMsg = flag(this, 'message')
3205+
, ssfi = flag(this, 'ssfi');
3206+
3207+
new Assertion(obj, flagMsg, ssfi, true).to.be.an('iterable');
3208+
});
3209+
31733210
/**
31743211
* ### .oneOf(list[, msg])
31753212
*

lib/chai/interface/assert.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import * as chai from '../../../index.js';
88
import {Assertion} from '../assertion.js';
99
import {flag, inspect} from '../utils/index.js';
1010
import {AssertionError} from 'assertion-error';
11-
import {type} from '../utils/type-detect.js';
1211

1312
/**
1413
* ### assert(expression, message)
@@ -2485,6 +2484,23 @@ assert.oneOf = function (inList, list, msg) {
24852484
new Assertion(inList, msg, assert.oneOf, true).to.be.oneOf(list);
24862485
}
24872486

2487+
/**
2488+
* ### isIterable(obj, [message])
2489+
*
2490+
* Asserts that the target is an iterable, which means that it has a iterator
2491+
* with the exception of `String.`
2492+
*
2493+
* assert.isIterable([1, 2]);
2494+
*
2495+
* @param {unknown} obj
2496+
* @param {string} [msg]
2497+
* @namespace Assert
2498+
* @api public
2499+
*/
2500+
assert.isIterable = function(obj, msg) {
2501+
new Assertion(obj, msg, assert.isIterable, true).to.be.an('iterable');
2502+
}
2503+
24882504
/**
24892505
* ### .changes(function, object, property, [message])
24902506
*

test/assert.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,6 +2375,36 @@ describe('assert', function () {
23752375
}, 'blah: the argument to most must be a number');
23762376
});
23772377

2378+
it('iterable', function() {
2379+
assert.isIterable([1, 2, 3]);
2380+
assert.isIterable(new Map([[1, 'one'], [2, 'two'], [3, 'three']]));
2381+
assert.isIterable(new Set([1, 2, 3]));
2382+
2383+
err(function() {
2384+
assert.isIterable(42);
2385+
}, 'expected 42 to be an iterable');
2386+
2387+
err(function() {
2388+
assert.isIterable('hello');
2389+
}, "expected 'hello' to be an iterable");
2390+
2391+
err(function() {
2392+
assert.isIterable(undefined);
2393+
}, 'expected undefined to be an iterable');
2394+
2395+
err(function() {
2396+
assert.isIterable(null);
2397+
}, 'expected null to be an iterable');
2398+
2399+
err(function() {
2400+
assert.isIterable(true);
2401+
}, 'expected true to be an iterable');
2402+
2403+
err(function() {
2404+
assert.isIterable({ key: 'value' });
2405+
}, 'expected { key: \'value\' } to be an iterable');
2406+
});
2407+
23782408
it('change', function() {
23792409
var obj = { value: 10, str: 'foo' },
23802410
heroes = ['spiderman', 'superman'],

test/expect.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3641,6 +3641,36 @@ describe('expect', function () {
36413641
}, 'expected [ { a: 1 }, { b: 2 }, { c: 3 } ] to not be an ordered superset of [ { a: 1 }, { b: 2 } ]');
36423642
});
36433643

3644+
it('iterable', function() {
3645+
expect([1, 2, 3]).to.be.iterable;
3646+
expect(new Map([[1, 'one'], [2, 'two'], [3, 'three']])).to.be.iterable;
3647+
expect(new Set([1, 2, 3])).to.be.iterable;
3648+
3649+
err(function() {
3650+
expect(42).to.be.iterable;
3651+
}, 'expected 42 to be an iterable');
3652+
3653+
err(function() {
3654+
expect('hello').to.be.iterable;
3655+
}, "expected 'hello' to be an iterable");
3656+
3657+
err(function() {
3658+
expect(undefined).to.be.iterable;
3659+
}, 'expected undefined to be an iterable');
3660+
3661+
err(function() {
3662+
expect(null).to.be.iterable;
3663+
}, 'expected null to be an iterable');
3664+
3665+
err(function() {
3666+
expect(true).to.be.iterable;
3667+
}, 'expected true to be an iterable');
3668+
3669+
err(function() {
3670+
expect({ key: 'value' }).to.be.iterable;
3671+
}, 'expected { key: \'value\' } to be an iterable');
3672+
})
3673+
36443674
it('change', function() {
36453675
var obj = { value: 10, str: 'foo' },
36463676
heroes = ['spiderman', 'superman'],

test/should.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,28 @@ describe('should', function() {
29422942
}, 'expected [ { a: 1 }, { b: 2 }, { c: 3 } ] to not be an ordered superset of [ { a: 1 }, { b: 2 } ]');
29432943
});
29442944

2945+
it ('iterable', function() {
2946+
([1, 2, 3]).should.be.iterable;
2947+
(new Map([[1, 'one'], [2, 'two'], [3, 'three']])).should.be.iterable;
2948+
(new Set([1, 2, 3])).should.be.iterable;
2949+
2950+
err(function() {
2951+
(42).should.be.iterable;
2952+
}, 'expected 42 to be an iterable');
2953+
2954+
err(function() {
2955+
('hello').should.be.iterable;
2956+
}, "expected 'hello' to be an iterable");
2957+
2958+
err(function() {
2959+
(true).should.be.iterable;
2960+
}, 'expected true to be an iterable');
2961+
2962+
err(function() {
2963+
({ key: 'value' }).should.be.iterable;
2964+
}, 'expected { key: \'value\' } to be an iterable');
2965+
})
2966+
29452967
it('change', function() {
29462968
var obj = { value: 10, str: 'foo' },
29472969
heroes = ['spiderman', 'superman'],

0 commit comments

Comments
 (0)