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
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529
describe('utilities', function () { var 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 () { if (typeof Symbol !== 'function') return;
chai.use(function (_chai, _) { expect(_.inspect(Symbol())).to.equal('Symbol()'); expect(_.inspect(Symbol('cat'))).to.equal('Symbol(cat)'); }); });
it('inspect BigInt', function () { if (typeof BigInt !== 'function') return;
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);
if (typeof Symbol === 'function') { // "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 () { if (typeof Symbol !== 'function') return;
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 () { if (typeof Symbol !== 'function') return;
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 () { if (typeof Proxy === 'undefined' || typeof Reflect === 'undefined') return;
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; });
if (typeof Proxy !== 'undefined' && typeof Reflect !== 'undefined') { 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; }); } else { it("returns false if Proxy and/or Reflect are undefined, and useProxy is true", function () { expect(isProxyEnabled()).to.be.false; });
it("returns false if Proxy and/or Reflect are undefined, 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'); }); }); });});