Skip to content

Commit

Permalink
feat: allow dates for isBelow and isAbove assertions (#990)
Browse files Browse the repository at this point in the history
* Fixed most tests

* Fix date uniformity (UTC)

* Add comment

* Cleanup

* Change extra functions (WIP)

* Finished tests

* Add master chai.js back

* Uncomment failing tests

* Update master and tests

* Actual seconds, duh

* Refactor 'above'

* Update all methods

* More explicit error

* Documentation - articles consistency

* Custom message test in assert

* No parenthesis in should

* Custom message for isAbove
  • Loading branch information
v1adko authored and keithamus committed Jun 23, 2017
1 parent 3bcb21c commit 3c932e2
Show file tree
Hide file tree
Showing 5 changed files with 661 additions and 111 deletions.
171 changes: 109 additions & 62 deletions lib/chai/core/assertions.js
Expand Up @@ -1024,7 +1024,7 @@ module.exports = function (chai, _) {
/**
* ### .above(n[, msg])
*
* Asserts that the target is a number greater than the given number `n`.
* Asserts that the target is a number or a date greater than the given number or date `n` respectively.
* However, it's often best to assert that the target is equal to its expected
* value.
*
Expand Down Expand Up @@ -1069,21 +1069,29 @@ module.exports = function (chai, _) {
var obj = flag(this, 'object')
, doLength = flag(this, 'doLength')
, flagMsg = flag(this, 'message')
, ssfi = flag(this, 'ssfi');
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, shouldThrow = true;

if (doLength) {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}

if (!doLength && (objType === 'date' && nType !== 'date')) {
errorMessage = msgPrefix + 'the argument to above must be a date';
} else if (nType !== 'number' && (doLength || objType === 'number')) {
errorMessage = msgPrefix + 'the argument to above must be a number';
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
shouldThrow = false;
}

if (typeof n !== 'number') {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'the argument to above must be a number',
undefined,
ssfi
);
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}

if (doLength) {
Expand All @@ -1098,8 +1106,9 @@ module.exports = function (chai, _) {
} else {
this.assert(
obj > n
, 'expected #{this} to be above ' + n
, 'expected #{this} to be at most ' + n
, 'expected #{this} to be above #{exp}'
, 'expected #{this} to be at most #{exp}'
, n
);
}
}
Expand All @@ -1111,8 +1120,8 @@ module.exports = function (chai, _) {
/**
* ### .least(n[, msg])
*
* Asserts that the target is a number greater than or equal to the given
* number `n`. However, it's often best to assert that the target is equal to
* Asserts that the target is a number or a date greater than or equal to the given
* number or date `n` respectively. However, it's often best to assert that the target is equal to
* its expected value.
*
* expect(2).to.equal(2); // Recommended
Expand Down Expand Up @@ -1156,21 +1165,29 @@ module.exports = function (chai, _) {
var obj = flag(this, 'object')
, doLength = flag(this, 'doLength')
, flagMsg = flag(this, 'message')
, ssfi = flag(this, 'ssfi');
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, shouldThrow = true;

if (doLength) {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}

if (!doLength && (objType === 'date' && nType !== 'date')) {
errorMessage = msgPrefix + 'the argument to least must be a date';
} else if (nType !== 'number' && (doLength || objType === 'number')) {
errorMessage = msgPrefix + 'the argument to least must be a number';
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
shouldThrow = false;
}

if (typeof n !== 'number') {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'the argument to least must be a number',
undefined,
ssfi
);
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}

if (doLength) {
Expand All @@ -1185,8 +1202,9 @@ module.exports = function (chai, _) {
} else {
this.assert(
obj >= n
, 'expected #{this} to be at least ' + n
, 'expected #{this} to be below ' + n
, 'expected #{this} to be at least #{exp}'
, 'expected #{this} to be below #{exp}'
, n
);
}
}
Expand All @@ -1197,7 +1215,7 @@ module.exports = function (chai, _) {
/**
* ### .below(n[, msg])
*
* Asserts that the target is a number less than the given number `n`.
* Asserts that the target is a number or a date less than the given number or date `n` respectively.
* However, it's often best to assert that the target is equal to its expected
* value.
*
Expand Down Expand Up @@ -1242,21 +1260,29 @@ module.exports = function (chai, _) {
var obj = flag(this, 'object')
, doLength = flag(this, 'doLength')
, flagMsg = flag(this, 'message')
, ssfi = flag(this, 'ssfi');
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, shouldThrow = true;

if (doLength) {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}

if (!doLength && (objType === 'date' && nType !== 'date')) {
errorMessage = msgPrefix + 'the argument to below must be a date';
} else if (nType !== 'number' && (doLength || objType === 'number')) {
errorMessage = msgPrefix + 'the argument to below must be a number';
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
shouldThrow = false;
}

if (typeof n !== 'number') {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'the argument to below must be a number',
undefined,
ssfi
);
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}

if (doLength) {
Expand All @@ -1271,8 +1297,9 @@ module.exports = function (chai, _) {
} else {
this.assert(
obj < n
, 'expected #{this} to be below ' + n
, 'expected #{this} to be at least ' + n
, 'expected #{this} to be below #{exp}'
, 'expected #{this} to be at least #{exp}'
, n
);
}
}
Expand All @@ -1284,8 +1311,8 @@ module.exports = function (chai, _) {
/**
* ### .most(n[, msg])
*
* Asserts that the target is a number less than or equal to the given number
* `n`. However, it's often best to assert that the target is equal to its
* Asserts that the target is a number or a date less than or equal to the given number
* or date `n` respectively. However, it's often best to assert that the target is equal to its
* expected value.
*
* expect(1).to.equal(1); // Recommended
Expand Down Expand Up @@ -1328,21 +1355,29 @@ module.exports = function (chai, _) {
var obj = flag(this, 'object')
, doLength = flag(this, 'doLength')
, flagMsg = flag(this, 'message')
, ssfi = flag(this, 'ssfi');
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, shouldThrow = true;

if (doLength) {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}

if (!doLength && (objType === 'date' && nType !== 'date')) {
errorMessage = msgPrefix + 'the argument to most must be a date';
} else if (nType !== 'number' && (doLength || objType === 'number')) {
errorMessage = msgPrefix + 'the argument to most must be a number';
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
shouldThrow = false;
}

if (typeof n !== 'number') {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'the argument to most must be a number',
undefined,
ssfi
);
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}

if (doLength) {
Expand All @@ -1357,8 +1392,9 @@ module.exports = function (chai, _) {
} else {
this.assert(
obj <= n
, 'expected #{this} to be at most ' + n
, 'expected #{this} to be above ' + n
, 'expected #{this} to be at most #{exp}'
, 'expected #{this} to be above #{exp}'
, n
);
}
}
Expand All @@ -1369,8 +1405,8 @@ module.exports = function (chai, _) {
/**
* ### .within(start, finish[, msg])
*
* Asserts that the target is a number greater than or equal to the given
* number `start`, and less than or equal to the given number `finish`.
* Asserts that the target is a number or a date greater than or equal to the given
* number or date `start`, and less than or equal to the given number or date `finish` respectively.
* However, it's often best to assert that the target is equal to its expected
* value.
*
Expand Down Expand Up @@ -1412,24 +1448,35 @@ module.exports = function (chai, _) {
Assertion.addMethod('within', function (start, finish, msg) {
if (msg) flag(this, 'message', msg);
var obj = flag(this, 'object')
, range = start + '..' + finish
, doLength = flag(this, 'doLength')
, flagMsg = flag(this, 'message')
, ssfi = flag(this, 'ssfi');
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, startType = _.type(start).toLowerCase()
, finishType = _.type(finish).toLowerCase()
, shouldThrow = true
, range = (startType === 'date' && finishType === 'date')
? start.toUTCString() + '..' + finish.toUTCString()
: start + '..' + finish;

if (doLength) {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}

if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {
errorMessage = msgPrefix + 'the arguments to within must be dates';
} else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) {
errorMessage = msgPrefix + 'the arguments to within must be numbers';
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
shouldThrow = false;
}

if (typeof start !== 'number' || typeof finish !== 'number') {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'the arguments to within must be numbers',
undefined,
ssfi
);
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}

if (doLength) {
Expand Down
2 changes: 1 addition & 1 deletion lib/chai/utils/expectTypes.js
Expand Up @@ -32,7 +32,7 @@ module.exports = function expectTypes(obj, types) {
types = types.map(function (t) { return t.toLowerCase(); });
types.sort();

// Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum'
// Transforms ['lorem', 'ipsum'] into 'a lorem, or an ipsum'
var str = types.map(function (t, index) {
var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a';
var or = types.length > 1 && index === types.length - 1 ? 'or ' : '';
Expand Down

0 comments on commit 3c932e2

Please sign in to comment.