Skip to main content
Module

x/chai/test/utilities.js

BDD / TDD assertion framework for node.js and the browser that can be paired with any testing framework.
Go to Latest
File
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507
import * as chai from '../index.js';
describe('utilities', function () { const expect = chai.expect;
after(function() { // Some clean-up so we can run tests in a --watch delete chai.Assertion.prototype.eqqqual; delete chai.Assertion.prototype.result; delete chai.Assertion.prototype.doesnotexist; });
it('_obj', function () { var foo = 'bar' , test = expect(foo);
expect(test).to.have.property('_obj', foo);
var bar = 'baz'; test._obj = bar;
expect(test).to.have.property('_obj', bar); test.equal(bar); });
it('transferFlags', function () { var foo = 'bar' , test = expect(foo).not;
chai.use(function (_chai, utils) { var obj = {}; utils.transferFlags(test, obj); expect(utils.flag(obj, 'object')).to.equal(foo); expect(utils.flag(obj, 'negate')).to.equal(true); }); });
it('transferFlags, includeAll = false', function () { var foo = 'bar';
chai.use(function (_chai, utils) { var target = {}; var test = function() {};
var assertion = new chai.Assertion(target, "message", test, true); var flag = {}; utils.flag(assertion, 'flagMe', flag); utils.flag(assertion, 'negate', true); var obj = {}; utils.transferFlags(assertion, obj, false);
expect(utils.flag(obj, 'object')).to.equal(undefined); expect(utils.flag(obj, 'message')).to.equal(undefined); expect(utils.flag(obj, 'ssfi')).to.equal(undefined); expect(utils.flag(obj, 'lockSsfi')).to.equal(undefined); expect(utils.flag(obj, 'negate')).to.equal(true); expect(utils.flag(obj, 'flagMe')).to.equal(flag); }); });
it('transferFlags, includeAll = true', function () { var foo = 'bar';
chai.use(function (_chai, utils) { var target = {}; var test = function() {};
var assertion = new chai.Assertion(target, "message", test, true); var flag = {}; utils.flag(assertion, 'flagMe', flag); utils.flag(assertion, 'negate', true); var obj = {}; utils.transferFlags(assertion, obj, true);
expect(utils.flag(obj, 'object')).to.equal(target); expect(utils.flag(obj, 'message')).to.equal("message"); expect(utils.flag(obj, 'ssfi')).to.equal(test); expect(utils.flag(obj, 'lockSsfi')).to.equal(true); expect(utils.flag(obj, 'negate')).to.equal(true); expect(utils.flag(obj, 'flagMe')).to.equal(flag); }); });
describe('addMethod', function() { var assertionConstructor, utils;
before(function() { chai.use(function(_chai, _utils) { utils = _utils; assertionConstructor = _chai.Assertion;
expect(_chai.Assertion).to.not.respondTo('eqqqual'); _chai.Assertion.addMethod('eqqqual', function (str) { var object = utils.flag(this, 'object'); new _chai.Assertion(object).to.be.eql(str); });
_chai.Assertion.addMethod('result', function () { return 'result'; })
_chai.Assertion.addMethod('returnNewAssertion', function () { utils.flag(this, 'mySpecificFlag', 'value1'); utils.flag(this, 'ultraSpecificFlag', 'value2'); });
_chai.Assertion.addMethod('checkFlags', function() { this.assert( utils.flag(this, 'mySpecificFlag') === 'value1' && utils.flag(this, 'ultraSpecificFlag') === 'value2' , 'expected assertion to have specific flags' , "this doesn't matter" ); }); }); });
after(function() { delete chai.Assertion.prototype.eqqqual;
delete chai.Assertion.prototype.result;
delete chai.Assertion.prototype.returnNewAssertion; delete chai.Assertion.prototype.checkFlags; });
it('addMethod', function () { expect(chai.Assertion).to.respondTo('eqqqual'); expect('spec').to.eqqqual('spec'); });
it('addMethod returning result', function () { expect(expect('foo').result()).to.equal('result'); });
it('addMethod returns new assertion with flags copied over', function () { var assertion1 = expect('foo'); var assertion2 = assertion1.to.returnNewAssertion();
// Checking if a new assertion was returned expect(assertion1).to.not.be.equal(assertion2);
// Check if flags were copied assertion2.checkFlags();
// Checking if it's really an instance of an Assertion expect(assertion2).to.be.instanceOf(assertionConstructor);
// Test chaining `.length` after a method to guarantee it's not a function's // `length`. Note: 'instanceof' cannot be used here because the test will // fail in IE 10 due to how addChainableMethod works without __proto__ // support. Therefore, test the constructor property of length instead. var anAssertion = expect([1, 2, 3]).to.be.an.instanceof(Array); expect(anAssertion.length.constructor).to.equal(assertionConstructor);
var anotherAssertion = expect([1, 2, 3]).to.have.a.lengthOf(3).and.to.be.ok; expect(anotherAssertion.length.constructor).to.equal(assertionConstructor); });
it('addMethod sets `ssfi` when `lockSsfi` isn\'t set', function () { var origAssertion = expect(1); var origSsfi = utils.flag(origAssertion, 'ssfi');
var newAssertion = origAssertion.eqqqual(1); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.not.equal(newSsfi); });
it('addMethod doesn\'t set `ssfi` when `lockSsfi` is set', function () { var origAssertion = expect(1); var origSsfi = utils.flag(origAssertion, 'ssfi');
utils.flag(origAssertion, 'lockSsfi', true);
var newAssertion = origAssertion.eqqqual(1); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.equal(newSsfi); }); });
describe('overwriteMethod', function () { var assertionConstructor, utils;
before(function() { chai.config.includeStack = false;
chai.use(function(_chai, _utils) { assertionConstructor = _chai.Assertion; utils = _utils;
_chai.Assertion.addMethod('four', function() { this.assert(this._obj === 4, 'expected #{this} to be 4', 'expected #{this} to not be 4', 4); });
_chai.Assertion.overwriteMethod('four', function(_super) { return function() { utils.flag(this, 'mySpecificFlag', 'value1'); utils.flag(this, 'ultraSpecificFlag', 'value2');
if (typeof this._obj === 'string') { this.assert(this._obj === 'four', 'expected #{this} to be \'four\'', 'expected #{this} to not be \'four\'', 'four'); } else { _super.call(this); } } });
_chai.Assertion.addMethod('checkFlags', function() { this.assert( utils.flag(this, 'mySpecificFlag') === 'value1' && utils.flag(this, 'ultraSpecificFlag') === 'value2' , 'expected assertion to have specific flags' , "this doesn't matter" ); }); }); });
after(function() { delete chai.Assertion.prototype.four; delete chai.Assertion.prototype.checkFlags; delete chai.Assertion.prototype.eqqqual; delete chai.Assertion.prototype.doesnotexist; delete chai.Assertion.prototype.doesnotexistfail; });
it('overwriteMethod', function () { chai.use(function (_chai, utils) { _chai.Assertion.addMethod('eqqqual', function (str) { var object = utils.flag(this, 'object'); new _chai.Assertion(object).to.be.eql(str); });
_chai.Assertion.overwriteMethod('eqqqual', function (_super) { return function (str) { var object = utils.flag(this, 'object'); if (object == 'cucumber' && str == 'cuke') { utils.flag(this, 'cucumber', true); } else { _super.apply(this, arguments); } }; }); });
var vege = expect('cucumber').to.eqqqual('cucumber'); expect(vege.__flags).to.not.have.property('cucumber'); var cuke = expect('cucumber').to.eqqqual('cuke'); expect(cuke.__flags).to.have.property('cucumber');
chai.use(function (_chai, _) { expect(_chai.Assertion).to.not.respondTo('doesnotexist'); _chai.Assertion.overwriteMethod('doesnotexist', function (_super) { expect(_super).to.be.a('function'); return function () { _.flag(this, 'doesnt', true); } }); });
var dne = expect('something').to.doesnotexist(); expect(dne.__flags).to.have.property('doesnt');
chai.use(function (_chai, _) { expect(_chai.Assertion).to.not.respondTo('doesnotexistfail'); _chai.Assertion.overwriteMethod('doesnotexistfail', function (_super) { expect(_super).to.be.a('function'); return function () { _.flag(this, 'doesnt', true); _super.apply(this, arguments); } }); });
var dneFail = expect('something'); var dneError; try { dneFail.doesnotexistfail(); } catch (e) { dneError = e; } expect(dneFail.__flags).to.have.property('doesnt'); expect(dneError.message).to.eql('doesnotexistfail is not a function'); });
it('overwriteMethod returning result', function () { chai.use(function (_chai, _) { _chai.Assertion.overwriteMethod('result', function (_super) { return function () { return 'result'; } }); });
expect(expect('foo').result()).to.equal('result'); });
it('calling _super has correct stack trace', function() { try { expect(5).to.be.four(); expect(false, 'should not get here because error thrown').to.be.ok; } catch (err) { // not all browsers support err.stack // Phantom does not include function names for getter exec if ('undefined' !== typeof err.stack && 'undefined' !== typeof Error.captureStackTrace) { expect(err.stack).to.include('utilities.js'); expect(err.stack).to.not.include('overwriteMethod'); } } });
it('overwritten behavior has correct stack trace', function() { try { expect('five').to.be.four(); expect(false, 'should not get here because error thrown').to.be.ok; } catch (err) { // not all browsers support err.stack // Phantom does not include function names for getter exec if ('undefined' !== typeof err.stack && 'undefined' !== typeof Error.captureStackTrace) { expect(err.stack).to.include('utilities.js'); expect(err.stack).to.not.include('overwriteMethod'); } } });
it('should return a new assertion with flags copied over', function () { var assertion1 = expect('four'); var assertion2 = assertion1.four();
// Checking if a new assertion was returned expect(assertion1).to.not.be.equal(assertion2);
// Check if flags were copied assertion2.checkFlags();
// Checking if it's really an instance of an Assertion expect(assertion2).to.be.instanceOf(assertionConstructor);
// Test chaining `.length` after a method to guarantee it is not a function's `length` expect('four').to.be.a.four().length.above(2);
// Ensure that foo returns an Assertion (not a function) expect(expect('four').four()).to.be.an.instanceOf(assertionConstructor); });
it('overwriteMethod sets `ssfi` when `lockSsfi` isn\'t set', function () { var origAssertion = expect(4); var origSsfi = utils.flag(origAssertion, 'ssfi');
var newAssertion = origAssertion.four(); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.not.equal(newSsfi); });
it('overwriteMethod doesn\'t set `ssfi` when `lockSsfi` is set', function () { var origAssertion = expect(4); var origSsfi = utils.flag(origAssertion, 'ssfi');
utils.flag(origAssertion, 'lockSsfi', true);
var newAssertion = origAssertion.four(); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.equal(newSsfi); }); });
describe('addProperty', function() { var assertionConstructor = chai.Assertion; var utils;
before(function() { chai.use(function (_chai, _utils) { utils = _utils; assertionConstructor = _chai.Assertion;
_chai.Assertion.addProperty('tea', function () { utils.flag(this, 'tea', 'chai'); });
_chai.Assertion.addProperty('result', function () { return 'result'; })
_chai.Assertion.addProperty('thing', function () { utils.flag(this, 'mySpecificFlag', 'value1'); utils.flag(this, 'ultraSpecificFlag', 'value2'); });
_chai.Assertion.addMethod('checkFlags', function() { this.assert( utils.flag(this, 'mySpecificFlag') === 'value1' && utils.flag(this, 'ultraSpecificFlag') === 'value2' , 'expected assertion to have specific flags' , "this doesn't matter" ); }); }); });
after(function() { delete chai.Assertion.prototype.tea; delete chai.Assertion.prototype.thing; delete chai.Assertion.prototype.checkFlags; delete chai.Assertion.prototype.result; });
it('addProperty', function () { var assert = expect('chai').to.be.tea; expect(assert.__flags.tea).to.equal('chai'); });
it('addProperty returning result', function () { expect(expect('foo').result).to.equal('result'); });
it('addProperty returns a new assertion with flags copied over', function () { var assertion1 = expect('foo'); var assertion2 = assertion1.is.thing;
// Checking if a new assertion was returned expect(assertion1).to.not.be.equal(assertion2);
// Check if flags were copied assertion2.checkFlags();
// If it is, calling length on it should return an assertion, not a function expect([1, 2, 3]).to.be.an.instanceof(Array);
// Checking if it's really an instance of an Assertion expect(assertion2).to.be.instanceOf(assertionConstructor);
// Test chaining `.length` after a property to guarantee it is not a function's `length` expect([1, 2, 3]).to.be.a.thing.with.length.above(2); expect([1, 2, 3]).to.be.an.instanceOf(Array).and.have.length.below(4);
expect(expect([1, 2, 3]).be).to.be.an.instanceOf(assertionConstructor); expect(expect([1, 2, 3]).thing).to.be.an.instanceOf(assertionConstructor); });
it('addProperty sets `ssfi` when `lockSsfi` isn\'t set', function () { var origAssertion = expect(1); var origSsfi = utils.flag(origAssertion, 'ssfi');
var newAssertion = origAssertion.to.be.tea; var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.not.equal(newSsfi); });
it('addProperty doesn\'t set `ssfi` when `lockSsfi` is set', function () { var origAssertion = expect(1); var origSsfi = utils.flag(origAssertion, 'ssfi');
utils.flag(origAssertion, 'lockSsfi', true);
var newAssertion = origAssertion.to.be.tea; var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.equal(newSsfi); }); });
describe('overwriteProperty', function () { var assertionConstructor, utils;
before(function() { chai.config.includeStack = false;
chai.use(function(_chai, _utils) { assertionConstructor = _chai.Assertion; utils = _utils;
_chai.Assertion.addProperty('tea', function () { utils.flag(this, 'tea', 'chai'); });
_chai.Assertion.overwriteProperty('tea', function (_super) { return function () { var act = utils.flag(this, 'object'); if (act === 'matcha') { utils.flag(this, 'tea', 'matcha'); } else { _super.call(this); } } });
_chai.Assertion.overwriteProperty('result', function (_super) { return function () { return 'result'; } });
_chai.Assertion.addProperty('four', function() { this.assert(this._obj === 4, 'expected #{this} to be 4', 'expected #{this} to not be 4', 4); });
_chai.Assertion.overwriteProperty('four', function(_super) { return function() { if (typeof this._obj === 'string') { this.assert(this._obj === 'four', 'expected #{this} to be \'four\'', 'expected #{this} to not be \'four\'', 'four'); } else { _super.call(this); } } });
_chai.Assertion.addProperty('foo');
_chai.Assertion.overwriteProperty('foo', function (_super) { return function blah () { utils.flag(this, 'mySpecificFlag', 'value1'); utils.flag(this, 'ultraSpecificFlag', 'value2'); _super.call(this); }; });
_chai.Assertion.addMethod('checkFlags', function() { this.assert( utils.flag(this, 'mySpecificFlag') === 'value1' && utils.flag(this, 'ultraSpecificFlag') === 'value2' , 'expected assertion to have specific flags' , "this doesn't matter" ); }); }); });
after(function() { delete chai.Assertion.prototype.tea; delete chai.Assertion.prototype.four; delete chai.Assertion.prototype.result; delete chai.Assertion.prototype.foo; delete chai.Assertion.prototype.checkFlags });
it('overwriteProperty', function () { var matcha = expect('matcha').to.be.tea; expect(matcha.__flags.tea).to.equal('matcha'); var assert = expect('something').to.be.tea; expect(assert.__flags.tea).to.equal('chai'); });
it('overwriteProperty returning result', function () { expect(expect('foo').result).to.equal('result'); });
it('calling _super has correct stack trace', function() { try { expect(5).to.be.four; expect(false, 'should not get here because error thrown').to.be.ok; } catch (err) { // not all browsers support err.stack // Phantom does not include function names for getter exec if ('undefined' !== typeof err.stack && 'undefined' !== typeof Error.captureStackTrace) { expect(err.stack).to.include('utilities.js'); expect(err.stack).to.not.include('overwriteProperty'); } } });
it('overwritten behavior has correct stack trace', function() { try { expect('five').to.be.four; expect(false, 'should not get here because error thrown').to.be.ok; } catch (err) { // not all browsers support err.stack // Phantom does not include function names for getter exec if ('undefined' !== typeof err.stack && 'undefined' !== typeof Error.captureStackTrace) { expect(err.stack).to.include('utilities.js'); expect(err.stack).to.not.include('overwriteProperty'); } } });
it('should return new assertion with flags copied over', function() { var assertion1 = expect('foo'); var assertion2 = assertion1.is.foo;
// Checking if a new assertion was returned expect(assertion1).to.not.be.equal(assertion2);
// Check if flags were copied assertion2.checkFlags();
// If it is, calling length on it should return an assertion, not a function expect([1, 2, 3]).to.be.an.foo.length.below(1000);
// Checking if it's really an instance of an Assertion expect(assertion2).to.be.instanceOf(assertionConstructor);
// Test chaining `.length` after a property to guarantee it is not a function's `length` expect([1, 2, 3]).to.be.a.foo.with.length.above(2); expect([1, 2, 3]).to.be.an.instanceOf(Array).and.have.length.below(4);
expect(expect([1, 2, 3]).be).to.be.an.instanceOf(assertionConstructor); expect(expect([1, 2, 3]).foo).to.be.an.instanceOf(assertionConstructor); });
describe('when useProxy is false', function () { before(function () { chai.config.useProxy = false; });
after(function () { chai.config.useProxy = true; });
it('overwriteProperty sets `ssfi` when `lockSsfi` isn\'t set', function () { var origAssertion = expect(4); var origSsfi = utils.flag(origAssertion, 'ssfi');
var newAssertion = origAssertion.to.be.four; var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.not.equal(newSsfi); }); });
it('overwriteProperty doesn\'t set `ssfi` when `lockSsfi` is set', function () { var origAssertion = expect(4); var origSsfi = utils.flag(origAssertion, 'ssfi');
utils.flag(origAssertion, 'lockSsfi', true);
var newAssertion = origAssertion.to.be.four; var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.equal(newSsfi); }); });
it('getMessage', function () { chai.use(function (_chai, _) { expect(_.getMessage({}, [])).to.equal(''); expect(_.getMessage({}, [null, null, null])).to.equal('');
var obj = {}; _.flag(obj, 'message', 'foo'); expect(_.getMessage(obj, [])).to.contain('foo'); }); });
it('getMessage passed message as function', function () { chai.use(function (_chai, _) { var obj = {}; var msg = function() { return "expected a to eql b"; } var negateMsg = function() { return "expected a not to eql b"; } expect(_.getMessage(obj, [null, msg, negateMsg])).to.equal("expected a to eql b"); _.flag(obj, 'negate', true); expect(_.getMessage(obj, [null, msg, negateMsg])).to.equal("expected a not to eql b"); }); });
it('getMessage template tag substitution', function () { chai.use(function (_chai, _) { var objName = 'trojan horse'; var actualValue = 'an actual value'; var expectedValue = 'an expected value'; [ // known template tags { template: 'one #{this} two', expected: 'one \'' + objName + '\' two' }, { template: 'one #{act} two', expected: 'one \'' + actualValue + '\' two' }, { template: 'one #{exp} two', expected: 'one \'' + expectedValue + '\' two' }, // unknown template tag { template: 'one #{unknown} two', expected: 'one #{unknown} two' }, // repeated template tag { template: '#{this}#{this}', expected: '\'' + objName + '\'\'' + objName + '\'' }, // multiple template tags in different order { template: '#{this}#{act}#{exp}#{act}#{this}', expected: '\'' + objName + '\'\'' + actualValue + '\'\'' + expectedValue + '\'\'' + actualValue + '\'\'' + objName + '\'' }, // immune to string.prototype.replace() `$` substitution { objName: '-$$-', template: '#{this}', expected: '\'-$$-\'' }, { actualValue: '-$$-', template: '#{act}', expected: '\'-$$-\'' }, { expectedValue: '-$$-', template: '#{exp}', expected: '\'-$$-\'' } ].forEach(function (config) { config.objName = config.objName || objName; config.actualValue = config.actualValue || actualValue; config.expectedValue = config.expectedValue || expectedValue; var obj = {_obj: config.actualValue}; _.flag(obj, 'object', config.objName); expect(_.getMessage(obj, [null, config.template, null, config.expectedValue])).to.equal(config.expected); }); }); });
it('inspect with custom stylize-calling inspect()s', function () { chai.use(function (_chai, _) { var obj = { outer: { inspect: function (depth, options) { return options.stylize('Object content', 'string'); } } }; expect(_.inspect(obj)).to.equal('{ outer: Object content }'); }); });
it('inspect with custom object-returning inspect()s', function () { chai.use(function (_chai, _) { var obj = { outer: { inspect: function () { return { foo: 'bar' }; } } };
expect(_.inspect(obj)).to.equal('{ outer: { foo: \'bar\' } }'); }); });
it('inspect negative zero', function () { chai.use(function (_chai, _) { expect(_.inspect(-0)).to.equal('-0'); expect(_.inspect([-0])).to.equal('[ -0 ]'); expect(_.inspect({ hp: -0 })).to.equal('{ hp: -0 }'); }); });
it('inspect Symbol', function () { chai.use(function (_chai, _) { expect(_.inspect(Symbol())).to.equal('Symbol()'); expect(_.inspect(Symbol('cat'))).to.equal('Symbol(cat)'); }); });
it('inspect BigInt', function () { chai.use(function (_chai, _) { expect(_.inspect(BigInt(0))).to.equal('0n'); expect(_.inspect(BigInt(1234))).to.equal('1234n'); expect(_.inspect(BigInt(-1234))).to.equal('-1234n'); }); });
it('inspect every kind of available TypedArray', function () { chai.use(function (_chai, _) { var arr = [1, 2, 3] , exp = 'Array[ 1, 2, 3 ]' , isNode = true;
if (typeof window !== 'undefined') { isNode = false; }
// Checks if engine supports common TypedArrays if ((!isNode && 'Int8Array' in window) || isNode && typeof 'Int8Array' !== undefined) { // Typed array inspections should work as array inspections do expect(_.inspect(new Int8Array(arr))).to.include(exp); expect(_.inspect(new Uint8Array(arr))).to.include(exp); expect(_.inspect(new Int16Array(arr))).to.include(exp); expect(_.inspect(new Uint16Array(arr))).to.include(exp); expect(_.inspect(new Int32Array(arr))).to.include(exp); expect(_.inspect(new Uint32Array(arr))).to.include(exp); expect(_.inspect(new Float32Array(arr))).to.include(exp); }
// These ones may not be available alongside the others above if ((!isNode && 'Uint8ClampedArray' in window) || isNode && typeof 'Uint8ClampedArray' !== undefined) { expect(_.inspect(new Uint8ClampedArray(arr))).to.include(exp); }
if ((!isNode && 'Float64Array' in window) || isNode && typeof 'Float64Array' !== undefined) { expect(_.inspect(new Float64Array(arr))).to.include(exp); } }); });
it('inspect an assertion', function () { chai.use(function (_chai, _) { var assertion = expect(1); var anInspectFn = function() { return _.inspect(assertion); };
expect(anInspectFn).to.not.throw(); }); });
it('truncate long TypedArray', function () { chai.use(function (_chai, _) {
var arr = [] , exp = 'Int8Array[ 1, 2, 3, 4, 5, 6, 7, …(993) ]' , isNode = true;
// Filling arr with lots of elements for (var i = 1; i <= 1000; i++) { arr.push(i); }
if (typeof window !== 'undefined') { isNode = false; }
if ((!isNode && 'Int8Array' in window) || isNode && typeof 'Int8Array' !== undefined) { expect(_.inspect(new Int8Array(arr))).to.include(exp); } }); });
describe('addChainableMethod', function() { var assertionConstructor, utils;
before(function() { chai.use(function (_chai, _utils) { assertionConstructor = _chai.Assertion; utils = _utils;
_chai.Assertion.addChainableMethod('x', function () { new chai.Assertion(this._obj).to.be.equal('x'); } , function () { if (this._obj === Object(this._obj)) { this._obj.__x = 'X!' } } );
_chai.Assertion.addChainableMethod('foo', function(str) { utils.flag(this, 'mySpecificFlag', 'value1'); utils.flag(this, 'ultraSpecificFlag', 'value2');
var obj = utils.flag(this, 'object'); new _chai.Assertion(obj).to.be.equal(str); });
_chai.Assertion.addMethod('checkFlags', function() { this.assert( utils.flag(this, 'mySpecificFlag') === 'value1' && utils.flag(this, 'ultraSpecificFlag') === 'value2' , 'expected assertion to have specific flags' , "this doesn't matter" ); }); }); });
after(function() { delete chai.Assertion.prototype.x; delete chai.Assertion.prototype.foo; delete chai.Assertion.prototype.checkFlags; });
it('addChainableMethod', function () { expect("foo").x.to.equal("foo"); expect("x").x();
expect(function () { expect("foo").x(); }).to.throw(chai.AssertionError);
// Verify whether the original Function properties are present. // see https://github.com/chaijs/chai/commit/514dd6ce4#commitcomment-2593383 var propertyDescriptor = Object.getOwnPropertyDescriptor(chai.Assertion.prototype, "x"); expect(propertyDescriptor.get).to.have.property("call", Function.prototype.call); expect(propertyDescriptor.get).to.have.property("apply", Function.prototype.apply); expect(propertyDescriptor.get()).to.have.property("call", Function.prototype.call); expect(propertyDescriptor.get()).to.have.property("apply", Function.prototype.apply);
var obj = {}; expect(obj).x.to.be.ok; expect(obj).to.have.property('__x', 'X!'); });
it('addChainableMethod should return a new assertion with flags copied over', function () { chai.config.proxyExcludedKeys.push('nodeType');
var assertion1 = expect('bar'); var assertion2 = assertion1.foo('bar');
// Checking if a new assertion was returned expect(assertion1).to.not.be.equal(assertion2);
// Check if flags were copied assertion2.checkFlags();
// Checking if it's really an instance of an Assertion expect(assertion2).to.be.instanceOf(assertionConstructor);
// Test chaining `.length` after a method to guarantee it is not a function's `length` expect('bar').to.be.a.foo('bar').length.above(2);
// Ensure that foo returns an Assertion (not a function) expect(expect('bar').foo('bar')).to.be.an.instanceOf(assertionConstructor); });
it('addChainableMethod sets `ssfi` when `lockSsfi` isn\'t set', function () { var origAssertion = expect('x'); var origSsfi = utils.flag(origAssertion, 'ssfi');
var newAssertion = origAssertion.to.be.x(); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.not.equal(newSsfi); });
it('addChainableMethod doesn\'t set `ssfi` when `lockSsfi` is set', function () { var origAssertion = expect('x'); var origSsfi = utils.flag(origAssertion, 'ssfi');
utils.flag(origAssertion, 'lockSsfi', true);
var newAssertion = origAssertion.to.be.x(); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.equal(newSsfi); }); });
describe('overwriteChainableMethod', function() { var assertionConstructor; var utils;
before(function() { chai.use(function (_chai, _utils) { assertionConstructor = _chai.Assertion; utils = _utils;
_chai.Assertion.addChainableMethod('x', function () { new chai.Assertion(this._obj).to.be.equal('x'); } , function () { if (this._obj === Object(this._obj)) { this._obj.__x = 'X!' } } );
_chai.Assertion.overwriteChainableMethod('x', function(_super) { return function() { utils.flag(this, 'mySpecificFlag', 'value1'); utils.flag(this, 'ultraSpecificFlag', 'value2');
if (utils.flag(this, 'marked')) { new chai.Assertion(this._obj).to.be.equal('spot'); } else { _super.apply(this, arguments); } }; } , function(_super) { return function() { utils.flag(this, 'message', 'x marks the spot'); _super.apply(this, arguments); }; } );
_chai.Assertion.addMethod('checkFlags', function() { this.assert( utils.flag(this, 'mySpecificFlag') === 'value1' && utils.flag(this, 'ultraSpecificFlag') === 'value2' && utils.flag(this, 'message') === 'x marks the spot' , 'expected assertion to have specific flags' , "this doesn't matter" ); }); }); });
after(function() { delete chai.Assertion.prototype.x; delete chai.Assertion.prototype.checkFlags; });
it('overwriteChainableMethod', function () { // Make sure the original behavior of 'x' remains the same expect('foo').x.to.equal("foo"); expect("x").x(); expect(function () { expect("foo").x(); }).to.throw(chai.AssertionError); var obj = {}; expect(obj).x.to.be.ok; expect(obj).to.have.property('__x', 'X!');
// Test the new behavior of 'x' var assertion = expect('foo').x.to.be.ok; expect(utils.flag(assertion, 'message')).to.equal('x marks the spot'); expect(function () { var assertion = expect('x'); utils.flag(assertion, 'marked', true); assertion.x() }).to.throw(chai.AssertionError); });
it('should return a new assertion with flags copied over', function () { var assertion1 = expect('x'); var assertion2 = assertion1.x();
chai.config.proxyExcludedKeys.push('nodeType');
// Checking if a new assertion was returned expect(assertion1).to.not.be.equal(assertion2);
// Check if flags were copied assertion2.checkFlags();
// Checking if it's really an instance of an Assertion expect(assertion2).to.be.instanceOf(assertionConstructor);
// Test chaining `.length` after a method to guarantee it is not a function's `length` expect('x').to.be.x().length.above(0);
// Ensure that foo returns an Assertion (not a function) expect(expect('x').x()).to.be.an.instanceOf(assertionConstructor);
if (typeof Object.setPrototypeOf === 'function') { expect(expect('x').x).to.be.an.instanceOf(assertionConstructor); } });
it('overwriteChainableMethod sets `ssfi` when `lockSsfi` isn\'t set', function () { var origAssertion = expect('x'); var origSsfi = utils.flag(origAssertion, 'ssfi');
var newAssertion = origAssertion.to.be.x(); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.not.equal(newSsfi); });
it('overwriteChainableMethod doesn\'t set `ssfi` when `lockSsfi` is set', function () { var origAssertion = expect('x'); var origSsfi = utils.flag(origAssertion, 'ssfi');
utils.flag(origAssertion, 'lockSsfi', true);
var newAssertion = origAssertion.to.be.x(); var newSsfi = utils.flag(newAssertion, 'ssfi');
expect(origSsfi).to.equal(newSsfi); }); });
it('compareByInspect', function () { chai.use(function (_chai, _) { var cbi = _.compareByInspect;
// "'c" is less than "'d" expect(cbi('cat', 'dog')).to.equal(-1); expect(cbi('dog', 'cat')).to.equal(1); expect(cbi('cat', 'cat')).to.equal(1);
// "{ cat: [ [ 'dog', 1" is less than "{ cat [ [ 'dog', 2" expect(cbi({'cat': [['dog', 1]]}, {'cat': [['dog', 2]]})).to.equal(-1); expect(cbi({'cat': [['dog', 2]]}, {'cat': [['dog', 1]]})).to.equal(1);
// "Symbol(c" is less than "Symbol(d" expect(cbi(Symbol('cat'), Symbol('dog'))).to.equal(-1); expect(cbi(Symbol('dog'), Symbol('cat'))).to.equal(1); }); });
describe('getOwnEnumerablePropertySymbols', function () { var gettem;
beforeEach(function () { chai.use(function (_chai, _) { gettem = _.getOwnEnumerablePropertySymbols; }); });
it('returns an empty array if no symbols', function () { var obj = {} , cat = 'cat';
obj[cat] = 42;
expect(gettem(obj)).to.not.include(cat); });
it('returns enumerable symbols only', function () { var cat = Symbol('cat') , dog = Symbol('dog') , frog = Symbol('frog') , cow = 'cow' , obj = {};
obj[cat] = 'meow'; obj[dog] = 'woof';
Object.defineProperty(obj, frog, { enumerable: false, value: 'ribbit' });
obj[cow] = 'moo';
expect(gettem(obj)).to.have.same.members([cat, dog]); }); });
describe('getOwnEnumerableProperties', function () { var gettem;
beforeEach(function () { chai.use(function (_chai, _) { gettem = _.getOwnEnumerableProperties; }); });
it('returns enumerable property names if no symbols', function () { var cat = 'cat' , dog = 'dog' , frog = 'frog' , obj = {};
obj[cat] = 'meow' obj[dog] = 'woof';
Object.defineProperty(obj, frog, { enumerable: false, value: 'ribbit' });
expect(gettem(obj)).to.have.same.members([cat, dog]); });
it('returns enumerable property names and symbols', function () { var cat = Symbol('cat') , dog = Symbol('dog') , frog = Symbol('frog') , bird = 'bird' , cow = 'cow' , obj = {};
obj[cat] = 'meow'; obj[dog] = 'woof'; obj[bird] = 'chirp';
Object.defineProperty(obj, frog, { enumerable: false, value: 'ribbit' });
Object.defineProperty(obj, cow, { enumerable: false, value: 'moo' });
expect(gettem(obj)).to.have.same.members([cat, dog, bird]); }); });
describe('proxified object', function () { var proxify;
beforeEach(function () { chai.use(function (_chai, _) { proxify = _.proxify; }); });
it('returns property value if an existing property is read', function () { var pizza = proxify({mushrooms: 42});
expect(pizza.mushrooms).to.equal(42); });
it('returns property value if an existing property is read when nonChainableMethodName is set', function () { var bake = function () {}; bake.numPizzas = 2;
var bakeProxy = proxify(bake, 'bake');
expect(bakeProxy.numPizzas).to.equal(2); });
it('throws invalid property error if a non-existent property is read', function () { var pizza = proxify({});
expect(function () { pizza.mushrooms; }).to.throw('Invalid Chai property: mushrooms'); });
it('throws invalid use error if a non-existent property is read when nonChainableMethodName is set', function () { var bake = proxify(function () {}, 'bake');
expect(function () { bake.numPizzas; }).to.throw('Invalid Chai property: bake.numPizzas. See docs for proper usage of "bake".'); });
it('suggests a fix if a non-existent prop looks like a typo', function () { var pizza = proxify({foo: 1, bar: 2, baz: 3});
expect(function () { pizza.phoo; }).to.throw('Invalid Chai property: phoo. Did you mean "foo"?'); });
it('doesn\'t take exponential time to find string distances', function () { var pizza = proxify({veryLongPropertyNameWithLotsOfLetters: 1});
expect(function () { pizza.extremelyLongPropertyNameWithManyLetters; }).to.throw( 'Invalid Chai property: extremelyLongPropertyNameWithManyLetters' ); });
it('doesn\'t suggest properties from Object.prototype', function () { var pizza = proxify({string: 5}); expect(function () { pizza.tostring; }).to.throw('Invalid Chai property: tostring. Did you mean "string"?'); });
it('doesn\'t suggest internally properties', function () { var pizza = proxify({flags: 5, __flags: 6}); expect(function () { pizza.___flags; // 3 underscores; closer to '__flags' than 'flags' }).to.throw('Invalid Chai property: ___flags. Did you mean "flags"?'); });
// .then is excluded from property validation for promise support it('doesn\'t throw error if non-existent `then` is read', function () { var pizza = proxify({});
expect(function () { pizza.then; }).to.not.throw(); }); });
describe('addLengthGuard', function () { var fnLengthDesc = Object.getOwnPropertyDescriptor(function () {}, 'length'); if (!fnLengthDesc.configurable) return;
var addLengthGuard;
beforeEach(function () { chai.use(function (_chai, _) { addLengthGuard = _.addLengthGuard; }); });
it('throws invalid use error if `.length` is read when `methodName` is defined and `isChainable` is false', function () { var hoagie = addLengthGuard({}, 'hoagie', false);
expect(function () { hoagie.length; }).to.throw('Invalid Chai property: hoagie.length. See docs for proper usage of "hoagie".'); });
it('throws incompatible `.length` error if `.length` is read when `methodName` is defined and `isChainable` is true', function () { var hoagie = addLengthGuard({}, 'hoagie', true);
expect(function () { hoagie.length; }).to.throw('Invalid Chai property: hoagie.length. Due to a compatibility issue, "length" cannot directly follow "hoagie". Use "hoagie.lengthOf" instead.'); }); });
describe("isProxyEnabled", function () { var origUseProxy, isProxyEnabled;
before(function () { chai.use(function (_chai, _) { isProxyEnabled = _.isProxyEnabled; });
origUseProxy = chai.config.useProxy; });
beforeEach(function () { chai.config.useProxy = true; });
after(function () { chai.config.useProxy = origUseProxy; });
it("returns true if Proxy and Reflect are defined, and useProxy is true", function () { expect(isProxyEnabled()).to.be.true; });
it("returns false if Proxy and Reflect are defined, and useProxy is false", function () { chai.config.useProxy = false;
expect(isProxyEnabled()).to.be.false; }); });
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'); }); }); });});