Skip to content

Commit

Permalink
Implement iterator assertion
Browse files Browse the repository at this point in the history
  • Loading branch information
koddsson committed Jan 28, 2024
1 parent 44b81df commit c0e6dd7
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 3 deletions.
41 changes: 39 additions & 2 deletions 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 @@ -3037,7 +3043,9 @@ Assertion.addMethod('closeTo', closeTo);
Assertion.addMethod('approximately', closeTo);

// Note: Duplicates are ignored if testing for inclusion instead of sameness.
function isSubsetOf(subset, superset, cmp, contains, ordered) {
function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
let superset = Array.from(_superset);
let subset = Array.from(_subset);
if (!contains) {
if (subset.length !== superset.length) return false;
superset = superset.slice();
Expand Down Expand Up @@ -3133,7 +3141,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 +3177,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
30 changes: 30 additions & 0 deletions test/assert.js
Original file line number Diff line number Diff line change
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
30 changes: 30 additions & 0 deletions test/expect.js
Original file line number Diff line number Diff line change
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
22 changes: 22 additions & 0 deletions test/should.js
Original file line number Diff line number Diff line change
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 c0e6dd7

Please sign in to comment.