Skip to content

Commit

Permalink
Adding operator attribute to assertion error (#1257)
Browse files Browse the repository at this point in the history
* feat: adding operator attribute to assertion error

You can set the operator as mentioned below.
flag(this, 'operator', MYOPERATOR).
for example,
flag(obj, 'operator', 'notEqual')
  • Loading branch information
rpgeeganage authored and vieiralucas committed Jun 25, 2019
1 parent 1958341 commit 8dc92d8
Show file tree
Hide file tree
Showing 5 changed files with 363 additions and 2 deletions.
14 changes: 12 additions & 2 deletions lib/chai/assertion.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,21 @@ module.exports = function (_chai, util) {
if (!ok) {
msg = util.getMessage(this, arguments);
var actual = util.getActual(this, arguments);
throw new AssertionError(msg, {
var assertionErrorObjectProperties = {
actual: actual
, expected: expected
, showDiff: showDiff
}, (config.includeStack) ? this.assert : flag(this, 'ssfi'));
};

var operator = util.getOperator(this, arguments);
if (operator) {
assertionErrorObjectProperties.operator = operator;
}

throw new AssertionError(
msg,
assertionErrorObjectProperties,
(config.includeStack) ? this.assert : flag(this, 'ssfi'));
}
};

Expand Down
55 changes: 55 additions & 0 deletions lib/chai/utils/getOperator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
var type = require('type-detect');

var flag = require('./flag');

function isObjectType(obj) {
var objectType = type(obj);
var objectTypes = ['Array', 'Object', 'function'];

return objectTypes.indexOf(objectType) !== -1;
}

/**
* ### .getOperator(message)
*
* Extract the operator from error message.
* Operator defined is based on below link
* https://nodejs.org/api/assert.html#assert_assert.
*
* Returns the `operator` or `undefined` value for an Assertion.
*
* @param {Object} object (constructed Assertion)
* @param {Arguments} chai.Assertion.prototype.assert arguments
* @namespace Utils
* @name getOperator
* @api public
*/

module.exports = function getOperator(obj, args) {
var operator = flag(obj, 'operator');
var negate = flag(obj, 'negate');
var expected = args[3];
var msg = negate ? args[2] : args[1];

if (operator) {
return operator;
}

if (typeof msg === 'function') msg = msg();

msg = msg || '';
if (!msg) {
return undefined;
}

if (/\shave\s/.test(msg)) {
return undefined;
}

var isObject = isObjectType(expected);
if (/\snot\s/.test(msg)) {
return isObject ? 'notDeepStrictEqual' : 'notStrictEqual';
}

return isObject ? 'deepStrictEqual' : 'strictEqual';
};
6 changes: 6 additions & 0 deletions lib/chai/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,9 @@ exports.isProxyEnabled = require('./isProxyEnabled');
*/

exports.isNaN = require('./isNaN');

/*!
* getOperator method
*/

exports.getOperator = require('./getOperator');
109 changes: 109 additions & 0 deletions test/globalErr.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,115 @@ describe('globalErr', function () {
});
});

it('should pass operator if possible during none object comparison', function () {
err(function () {
expect('cat').to.equal('dog');
}, {
message: 'expected \'cat\' to equal \'dog\''
, expected: 'dog'
, actual: 'cat'
, operator: 'strictEqual'
});

err(function () {
expect('cat').to.not.equal('cat');
}, {
message: 'expected \'cat\' to not equal \'cat\''
, expected: 'cat'
, actual: 'cat'
, operator: 'notStrictEqual'
});
});

it('should pass operator if possible during plain object comparison', function () {
var val1 = {
propVal1: 'val1'
};

var val2 = {
propVal2: 'val2'
};

err(function () {
expect(val1).to.equal(val2);
}, {
message: "expected { propVal1: 'val1' } to equal { propVal2: 'val2' }"
, expected: val2
, actual: val1
, operator: 'deepStrictEqual'
});

err(function () {
expect(val1).to.not.equal(val1);
}, {
message: "expected { propVal1: 'val1' } to not equal { propVal1: 'val1' }"
, expected: val1
, actual: val1
, operator: 'notDeepStrictEqual'
});
});

it('should pass operator if possible during function comparison', function () {
function f1 () {
this.propF1 = 'propF1';
}

function f2 () {
this.propF2 = 'propF2';
}

err(function () {
expect(f1).to.equal(f2);
}, {
message: "expected [Function: f1] to equal [Function: f2]"
, expected: f2
, actual: f1
, operator: 'deepStrictEqual'
});

err(function () {
expect(f1).to.not.equal(f1);
}, {
message: "expected [Function: f1] to not equal [Function: f1]"
, expected: f1
, actual: f1
, operator: 'notDeepStrictEqual'
});
});

it('should pass operator if possible during object comparison', function () {
var val1 = [
'string1'
, 'string2'
, 'string3'
, 'string4'
];

var val2 = [
'string5'
, 'string6'
, 'string7'
, 'string8'
];
err(function () {
expect(val1).to.equal(val2);
}, {
message: 'expected [ Array(4) ] to equal [ Array(4) ]'
, expected: val2
, actual: val1
, operator: 'deepStrictEqual'
});

err(function () {
expect(val1).to.not.equal(val1);
}, {
message: 'expected [ Array(4) ] to not equal [ Array(4) ]'
, expected: val1
, actual: val1
, operator: 'notDeepStrictEqual'
});
});

it('should throw if regex val does not match error message', function () {
err(function () {
err(function () { throw new Err('cat') }, /dog/);
Expand Down
181 changes: 181 additions & 0 deletions test/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -1334,4 +1334,185 @@ describe('utilities', function () {
});
}
});

describe('getOperator', function() {
it('Must return operator if the "operator" flag is set', function() {
chai.use(function(_chai, _) {
expect(_.getOperator({}, [])).to.equal(undefined);
expect(_.getOperator({}, [null, null, null])).to.equal(undefined);

var obj = {};
_.flag(obj, 'operator', 'my-operator');
expect(_.getOperator(obj, [])).to.equal('my-operator');
});
});

it('Must return undefined if message is partial assertions', function() {
chai.use(function(_chai, _) {
expect(
_.getOperator({}, [null, 'to have the same ordered', null, 'test'])
).to.equal(undefined);
});
});

it('Must return deepStrictEqual if "expected" is a object and assertion is for equal', function() {
chai.use(function(_chai, _) {
var expected = Object.create({
dummyProperty1: 'dummyProperty1',
dummyProperty2: 'dummyProperty2',
dummyProperty3: 'dummyProperty3'
});

var obj = {};
_.flag(obj, 'negate', false);

expect(
_.getOperator(obj, [
null,
'expect #{this} deep equal to #{exp}',
'expect #{this} not deep equal to #{exp}',
expected
])
).to.equal('deepStrictEqual');
});
});

it('Must return deepStrictEqual if "expected" is a function and assertion is for equal', function() {
chai.use(function(_chai, _) {
function expected () {
this.prop = 'prop';
}

var obj = {};
_.flag(obj, 'negate', false);

expect(
_.getOperator(obj, [
null,
'expect #{this} deep equal to #{exp}',
'expect #{this} not deep equal to #{exp}',
expected
])
).to.equal('deepStrictEqual');
});
});

it('Must return deepStrictEqual if "expected" is an array and assertion is for equal', function() {
chai.use(function(_chai, _) {
var expected = [
'item 1'
];

var obj = {};
_.flag(obj, 'negate', false);

expect(
_.getOperator(obj, [
null,
'expect #{this} deep equal to #{exp}',
'expect #{this} not deep equal to #{exp}',
expected
])
).to.equal('deepStrictEqual');
});
});

it('Must return strictEqual if "expected" is a string and assertion is for equal', function() {
chai.use(function(_chai, _) {
var expected = 'someString';

var obj = {};
_.flag(obj, 'negate', false);

expect(
_.getOperator(obj, [
null,
'expect #{this} equal to #{exp}',
'expect #{this} not equal to #{exp}',
expected
])
).to.equal('strictEqual');
});
});

it('Must return notDeepStrictEqual if "expected" is a object and assertion is for inequality', function() {
chai.use(function(_chai, _) {
var expected = Object.create({
dummyProperty1: 'dummyProperty1',
dummyProperty2: 'dummyProperty2',
dummyProperty3: 'dummyProperty3'
});

var obj = {};
_.flag(obj, 'negate', true);

expect(
_.getOperator(obj, [
null,
'expect #{this} deep equal to #{exp}',
'expect #{this} not deep equal to #{exp}',
expected
])
).to.equal('notDeepStrictEqual');
});
});

it('Must return notDeepStrictEqual if "expected" is a function and assertion is for inequality', function() {
chai.use(function(_chai, _) {
function expected () {
this.prop = 'prop';
}

var obj = {};
_.flag(obj, 'negate', true);

expect(
_.getOperator(obj, [
null,
'expect #{this} deep equal to #{exp}',
'expect #{this} not deep equal to #{exp}',
expected
])
).to.equal('notDeepStrictEqual');
});
});

it('Must return notDeepStrictEqual if "expected" is an array and assertion is for inequality', function() {
chai.use(function(_chai, _) {
var expected = [
'item 1'
];

var obj = {};
_.flag(obj, 'negate', true);

expect(
_.getOperator(obj, [
null,
'expect #{this} deep equal to #{exp}',
'expect #{this} not deep equal to #{exp}',
expected
])
).to.equal('notDeepStrictEqual');
});
});

it('Must return notStrictEqual if "expected" is a string and assertion is for inequality', function() {
chai.use(function(_chai, _) {
var expected = 'someString';

var obj = {};
_.flag(obj, 'negate', true);

expect(
_.getOperator(obj, [
null,
'expect #{this} equal to #{exp}',
'expect #{this} not equal to #{exp}',
expected
])
).to.equal('notStrictEqual');
});
});
});
});

0 comments on commit 8dc92d8

Please sign in to comment.