Skip to content

Commit

Permalink
Merge pull request #728 from meeber/ordered-members
Browse files Browse the repository at this point in the history
Add ordered flag for members assertions
  • Loading branch information
keithamus authored Jun 13, 2016
2 parents fd2cc2b + adf2b6c commit c273846
Show file tree
Hide file tree
Showing 5 changed files with 606 additions and 76 deletions.
99 changes: 75 additions & 24 deletions lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ module.exports = function (chai, _) {
flag(this, 'deep', true);
});

/**
* ### .ordered
*
* Sets the `ordered` flag, later used by the `members`
* assertions.
*
* expect(foo).to.have.ordered.members([bar, baz]);
*
* @name ordered
* @namespace BDD
* @api public
*/

Assertion.addProperty('ordered', function () {
flag(this, 'ordered', true);
});

/**
* ### .any
*
Expand Down Expand Up @@ -1547,8 +1564,9 @@ module.exports = function (chai, _) {
Assertion.addMethod('closeTo', closeTo);
Assertion.addMethod('approximately', closeTo);

function isSubsetOf(subset, superset, cmp) {
return subset.every(function(elem) {
function isSubsetOf(subset, superset, cmp, ordered) {
return subset.every(function(elem, idx) {
if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx];
if (!cmp) return superset.indexOf(elem) !== -1;

return superset.some(function(elem2) {
Expand All @@ -1560,18 +1578,43 @@ module.exports = function (chai, _) {
/**
* ### .members(set)
*
* Asserts that the target is a superset of `set`,
* or that the target and `set` have the same strictly-equal (===) members.
* Alternately, if the `deep` flag is set, set members are compared for deep
* equality.
* Asserts that the target and `set` have the same members. By default,
* members are compared using strict equality (===), and order doesn't
* matter.
*
* expect([1, 2, 3]).to.have.members([2, 1, 3]);
* expect([1, 2, 3]).to.not.have.members([2, 1]);
* expect([1, 2, 3]).to.not.have.members([5, 1, 3]);
*
* If the `contains` flag is set via `.include` or `.contain`, instead asserts
* that the target is a superset of `set`.
*
* expect([1, 2, 3]).to.include.members([2, 1]);
* expect([1, 2, 3]).to.not.include.members([5, 1]);
*
* expect([1, 2, 3]).to.contain.members([2, 1]);
* expect([1, 2, 3]).to.not.contain.members([5, 1]);
*
* expect([1, 2, 3]).to.include.members([3, 2]);
* expect([1, 2, 3]).to.not.include.members([3, 2, 8]);
* If the `deep` flag is set, members are instead compared for deep equality.
*
* expect([4, 2]).to.have.members([2, 4]);
* expect([5, 2]).to.not.have.members([5, 2, 1]);
* expect([{ a: 1 }, { b: 2 }, { c: 3 }]).to.have.deep.members([{ b: 2 }, { a: 1 }, { c: 3 }]);
* expect([{ a: 1 }, { b: 2 }, { c: 3 }]).to.not.have.deep.members([{ b: 2 }, { a: 1 }, { f: 5 }]);
*
* expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]);
* If the `ordered` flag is set, members must instead appear in the same
* order.
*
* expect([1, 2, 3]).to.have.ordered.members([1, 2, 3]);
* expect([1, 2, 3]).to.not.have.ordered.members([2, 1, 3]);
*
* Any of the flags can be combined.
*
* expect([{ a: 1 }, { b: 2 }, { c: 3 }]).to.have.deep.ordered.members([{ a: 1 }, { b: 2 }, { c: 3 }]);
*
* If both the `contains` and `ordered` flag are set, the ordering begins
* with the first element in the target.
*
* expect([1, 2, 3]).to.include.ordered.members([1, 2]);
* expect([1, 2, 3]).to.not.include.ordered.members([2, 3]);
*
* @name members
* @param {Array} set
Expand All @@ -1587,24 +1630,32 @@ module.exports = function (chai, _) {
new Assertion(obj).to.be.an('array');
new Assertion(subset).to.be.an('array');

var cmp = flag(this, 'deep') ? _.eql : undefined;
var ordered = flag(this, 'ordered');

var failMsg, failNegateMsg, lengthCheck;

if (flag(this, 'contains')) {
return this.assert(
isSubsetOf(subset, obj, cmp)
, 'expected #{this} to be a superset of #{exp}'
, 'expected #{this} to not be a superset of #{exp}'
, subset
, obj
);
lengthCheck = true;

var subject = ordered ? 'an ordered superset' : 'a superset';
failMsg = 'expected #{this} to be ' + subject + ' of #{exp}';
failNegateMsg = 'expected #{this} to not be ' + subject + ' of #{exp}';
} else {
lengthCheck = obj.length === subset.length;

var subject = ordered ? 'ordered members' : 'members';
failMsg = 'expected #{this} to have the same ' + subject + ' as #{exp}';
failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}';
}

var cmp = flag(this, 'deep') ? _.eql : undefined;

this.assert(
isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp)
, 'expected #{this} to have the same members as #{exp}'
, 'expected #{this} to not have the same members as #{exp}'
, subset
, obj
lengthCheck && isSubsetOf(subset, obj, cmp, ordered)
, failMsg
, failNegateMsg
, subset
, obj
);
});

Expand Down
Loading

0 comments on commit c273846

Please sign in to comment.