Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement iterable assertion #1592

Merged
merged 4 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 38 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(
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,35 @@ Assertion.addMethod('members', function (subset, msg) {
);
});

/**
* ### .iterable
*
* Asserts that the target is an iterable, which means that it has a iterator.
*
* expect([1, 2]).to.be.iterable;
*
* Add `.not` earlier in the chain to negate `.iterable`.
*
* expect(1).to.not.be.iterable;
* expect(true).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
27 changes: 27 additions & 0 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -2375,6 +2375,33 @@ 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]));
assert.isIterable('hello');

err(function() {
assert.isIterable(42);
}, 'expected 42 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
27 changes: 27 additions & 0 deletions test/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3641,6 +3641,33 @@ 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;
expect('hello').to.be.iterable;

err(function() {
expect(42).to.be.iterable;
}, 'expected 42 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
19 changes: 19 additions & 0 deletions test/should.js
Original file line number Diff line number Diff line change
Expand Up @@ -2942,6 +2942,25 @@ 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;
('hello').should.be.iterable;

err(function() {
(42).should.be.iterable;
}, 'expected 42 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