UNPKG

direct-dev

Version:
1,808 lines (1,616 loc) 159 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chai = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ module.exports = require('./lib/chai'); },{"./lib/chai":2}],2:[function(require,module,exports){ /*! * chai * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ var used = [] , exports = module.exports = {}; /*! * Chai version */ exports.version = '3.5.0'; /*! * Assertion Error */ exports.AssertionError = require('assertion-error'); /*! * Utils for plugins (not exported) */ var util = require('./chai/utils'); /** * # .use(function) * * Provides a way to extend the internals of Chai * * @param {Function} * @returns {this} for chaining * @api public */ exports.use = function (fn) { if (!~used.indexOf(fn)) { fn(this, util); used.push(fn); } return this; }; /*! * Utility Functions */ exports.util = util; /*! * Configuration */ var config = require('./chai/config'); exports.config = config; /*! * Primary `Assertion` prototype */ var assertion = require('./chai/assertion'); exports.use(assertion); /*! * Core Assertions */ var core = require('./chai/core/assertions'); exports.use(core); /*! * Expect interface */ var expect = require('./chai/interface/expect'); exports.use(expect); /*! * Should interface */ var should = require('./chai/interface/should'); exports.use(should); /*! * Assert interface */ var assert = require('./chai/interface/assert'); exports.use(assert); },{"./chai/assertion":3,"./chai/config":4,"./chai/core/assertions":5,"./chai/interface/assert":6,"./chai/interface/expect":7,"./chai/interface/should":8,"./chai/utils":22,"assertion-error":30}],3:[function(require,module,exports){ /*! * chai * http://chaijs.com * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ var config = require('./config'); module.exports = function (_chai, util) { /*! * Module dependencies. */ var AssertionError = _chai.AssertionError , flag = util.flag; /*! * Module export. */ _chai.Assertion = Assertion; /*! * Assertion Constructor * * Creates object for chaining. * * @api private */ function Assertion (obj, msg, stack) { flag(this, 'ssfi', stack || arguments.callee); flag(this, 'object', obj); flag(this, 'message', msg); } Object.defineProperty(Assertion, 'includeStack', { get: function() { console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); return config.includeStack; }, set: function(value) { console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); config.includeStack = value; } }); Object.defineProperty(Assertion, 'showDiff', { get: function() { console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); return config.showDiff; }, set: function(value) { console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); config.showDiff = value; } }); Assertion.addProperty = function (name, fn) { util.addProperty(this.prototype, name, fn); }; Assertion.addMethod = function (name, fn) { util.addMethod(this.prototype, name, fn); }; Assertion.addChainableMethod = function (name, fn, chainingBehavior) { util.addChainableMethod(this.prototype, name, fn, chainingBehavior); }; Assertion.overwriteProperty = function (name, fn) { util.overwriteProperty(this.prototype, name, fn); }; Assertion.overwriteMethod = function (name, fn) { util.overwriteMethod(this.prototype, name, fn); }; Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); }; /** * ### .assert(expression, message, negateMessage, expected, actual, showDiff) * * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. * * @name assert * @param {Philosophical} expression to be tested * @param {String|Function} message or function that returns message to display if expression fails * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails * @param {Mixed} expected value (remember to check for negation) * @param {Mixed} actual (optional) will default to `this.obj` * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails * @api private */ Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { var ok = util.test(this, arguments); if (true !== showDiff) showDiff = false; if (true !== config.showDiff) showDiff = false; if (!ok) { var msg = util.getMessage(this, arguments) , actual = util.getActual(this, arguments); throw new AssertionError(msg, { actual: actual , expected: expected , showDiff: showDiff }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); } }; /*! * ### ._obj * * Quick reference to stored `actual` value for plugin developers. * * @api private */ Object.defineProperty(Assertion.prototype, '_obj', { get: function () { return flag(this, 'object'); } , set: function (val) { flag(this, 'object', val); } }); }; },{"./config":4}],4:[function(require,module,exports){ module.exports = { /** * ### config.includeStack * * User configurable property, influences whether stack trace * is included in Assertion error message. Default of false * suppresses stack trace in the error message. * * chai.config.includeStack = true; // enable stack on error * * @param {Boolean} * @api public */ includeStack: false, /** * ### config.showDiff * * User configurable property, influences whether or not * the `showDiff` flag should be included in the thrown * AssertionErrors. `false` will always be `false`; `true` * will be true when the assertion has requested a diff * be shown. * * @param {Boolean} * @api public */ showDiff: true, /** * ### config.truncateThreshold * * User configurable property, sets length threshold for actual and * expected values in assertion errors. If this threshold is exceeded, for * example for large data structures, the value is replaced with something * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. * * Set it to zero if you want to disable truncating altogether. * * This is especially userful when doing assertions on arrays: having this * set to a reasonable large value makes the failure messages readily * inspectable. * * chai.config.truncateThreshold = 0; // disable truncating * * @param {Number} * @api public */ truncateThreshold: 40 }; },{}],5:[function(require,module,exports){ /*! * chai * http://chaijs.com * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ module.exports = function (chai, _) { var Assertion = chai.Assertion , toString = Object.prototype.toString , flag = _.flag; /** * ### Language Chains * * The following are provided as chainable getters to * improve the readability of your assertions. They * do not provide testing capabilities unless they * have been overwritten by a plugin. * * **Chains** * * - to * - be * - been * - is * - that * - which * - and * - has * - have * - with * - at * - of * - same * * @name language chains * @namespace BDD * @api public */ [ 'to', 'be', 'been' , 'is', 'and', 'has', 'have' , 'with', 'that', 'which', 'at' , 'of', 'same' ].forEach(function (chain) { Assertion.addProperty(chain, function () { return this; }); }); /** * ### .not * * Negates any of assertions following in the chain. * * expect(foo).to.not.equal('bar'); * expect(goodFn).to.not.throw(Error); * expect({ foo: 'baz' }).to.have.property('foo') * .and.not.equal('bar'); * * @name not * @namespace BDD * @api public */ Assertion.addProperty('not', function () { flag(this, 'negate', true); }); /** * ### .deep * * Sets the `deep` flag, later used by the `equal` and * `property` assertions. * * expect(foo).to.deep.equal({ bar: 'baz' }); * expect({ foo: { bar: { baz: 'quux' } } }) * .to.have.deep.property('foo.bar.baz', 'quux'); * * `.deep.property` special characters can be escaped * by adding two slashes before the `.` or `[]`. * * var deepCss = { '.link': { '[target]': 42 }}; * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); * * @name deep * @namespace BDD * @api public */ Assertion.addProperty('deep', function () { flag(this, 'deep', true); }); /** * ### .any * * Sets the `any` flag, (opposite of the `all` flag) * later used in the `keys` assertion. * * expect(foo).to.have.any.keys('bar', 'baz'); * * @name any * @namespace BDD * @api public */ Assertion.addProperty('any', function () { flag(this, 'any', true); flag(this, 'all', false) }); /** * ### .all * * Sets the `all` flag (opposite of the `any` flag) * later used by the `keys` assertion. * * expect(foo).to.have.all.keys('bar', 'baz'); * * @name all * @namespace BDD * @api public */ Assertion.addProperty('all', function () { flag(this, 'all', true); flag(this, 'any', false); }); /** * ### .a(type) * * The `a` and `an` assertions are aliases that can be * used either as language chains or to assert a value's * type. * * // typeof * expect('test').to.be.a('string'); * expect({ foo: 'bar' }).to.be.an('object'); * expect(null).to.be.a('null'); * expect(undefined).to.be.an('undefined'); * expect(new Error).to.be.an('error'); * expect(new Promise).to.be.a('promise'); * expect(new Float32Array()).to.be.a('float32array'); * expect(Symbol()).to.be.a('symbol'); * * // es6 overrides * expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo'); * * // language chain * expect(foo).to.be.an.instanceof(Foo); * * @name a * @alias an * @param {String} type * @param {String} message _optional_ * @namespace BDD * @api public */ function an (type, msg) { if (msg) flag(this, 'message', msg); type = type.toLowerCase(); var obj = flag(this, 'object') , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; this.assert( type === _.type(obj) , 'expected #{this} to be ' + article + type , 'expected #{this} not to be ' + article + type ); } Assertion.addChainableMethod('an', an); Assertion.addChainableMethod('a', an); /** * ### .include(value) * * The `include` and `contain` assertions can be used as either property * based language chains or as methods to assert the inclusion of an object * in an array or a substring in a string. When used as language chains, * they toggle the `contains` flag for the `keys` assertion. * * expect([1,2,3]).to.include(2); * expect('foobar').to.contain('foo'); * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); * * @name include * @alias contain * @alias includes * @alias contains * @param {Object|String|Number} obj * @param {String} message _optional_ * @namespace BDD * @api public */ function includeChainingBehavior () { flag(this, 'contains', true); } function include (val, msg) { _.expectTypes(this, ['array', 'object', 'string']); if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); var expected = false; if (_.type(obj) === 'array' && _.type(val) === 'object') { for (var i in obj) { if (_.eql(obj[i], val)) { expected = true; break; } } } else if (_.type(val) === 'object') { if (!flag(this, 'negate')) { for (var k in val) new Assertion(obj).property(k, val[k]); return; } var subset = {}; for (var k in val) subset[k] = obj[k]; expected = _.eql(subset, val); } else { expected = (obj != undefined) && ~obj.indexOf(val); } this.assert( expected , 'expected #{this} to include ' + _.inspect(val) , 'expected #{this} to not include ' + _.inspect(val)); } Assertion.addChainableMethod('include', include, includeChainingBehavior); Assertion.addChainableMethod('contain', include, includeChainingBehavior); Assertion.addChainableMethod('contains', include, includeChainingBehavior); Assertion.addChainableMethod('includes', include, includeChainingBehavior); /** * ### .ok * * Asserts that the target is truthy. * * expect('everything').to.be.ok; * expect(1).to.be.ok; * expect(false).to.not.be.ok; * expect(undefined).to.not.be.ok; * expect(null).to.not.be.ok; * * @name ok * @namespace BDD * @api public */ Assertion.addProperty('ok', function () { this.assert( flag(this, 'object') , 'expected #{this} to be truthy' , 'expected #{this} to be falsy'); }); /** * ### .true * * Asserts that the target is `true`. * * expect(true).to.be.true; * expect(1).to.not.be.true; * * @name true * @namespace BDD * @api public */ Assertion.addProperty('true', function () { this.assert( true === flag(this, 'object') , 'expected #{this} to be true' , 'expected #{this} to be false' , this.negate ? false : true ); }); /** * ### .false * * Asserts that the target is `false`. * * expect(false).to.be.false; * expect(0).to.not.be.false; * * @name false * @namespace BDD * @api public */ Assertion.addProperty('false', function () { this.assert( false === flag(this, 'object') , 'expected #{this} to be false' , 'expected #{this} to be true' , this.negate ? true : false ); }); /** * ### .null * * Asserts that the target is `null`. * * expect(null).to.be.null; * expect(undefined).to.not.be.null; * * @name null * @namespace BDD * @api public */ Assertion.addProperty('null', function () { this.assert( null === flag(this, 'object') , 'expected #{this} to be null' , 'expected #{this} not to be null' ); }); /** * ### .undefined * * Asserts that the target is `undefined`. * * expect(undefined).to.be.undefined; * expect(null).to.not.be.undefined; * * @name undefined * @namespace BDD * @api public */ Assertion.addProperty('undefined', function () { this.assert( undefined === flag(this, 'object') , 'expected #{this} to be undefined' , 'expected #{this} not to be undefined' ); }); /** * ### .NaN * Asserts that the target is `NaN`. * * expect('foo').to.be.NaN; * expect(4).not.to.be.NaN; * * @name NaN * @namespace BDD * @api public */ Assertion.addProperty('NaN', function () { this.assert( isNaN(flag(this, 'object')) , 'expected #{this} to be NaN' , 'expected #{this} not to be NaN' ); }); /** * ### .exist * * Asserts that the target is neither `null` nor `undefined`. * * var foo = 'hi' * , bar = null * , baz; * * expect(foo).to.exist; * expect(bar).to.not.exist; * expect(baz).to.not.exist; * * @name exist * @namespace BDD * @api public */ Assertion.addProperty('exist', function () { this.assert( null != flag(this, 'object') , 'expected #{this} to exist' , 'expected #{this} to not exist' ); }); /** * ### .empty * * Asserts that the target's length is `0`. For arrays and strings, it checks * the `length` property. For objects, it gets the count of * enumerable keys. * * expect([]).to.be.empty; * expect('').to.be.empty; * expect({}).to.be.empty; * * @name empty * @namespace BDD * @api public */ Assertion.addProperty('empty', function () { var obj = flag(this, 'object') , expected = obj; if (Array.isArray(obj) || 'string' === typeof object) { expected = obj.length; } else if (typeof obj === 'object') { expected = Object.keys(obj).length; } this.assert( !expected , 'expected #{this} to be empty' , 'expected #{this} not to be empty' ); }); /** * ### .arguments * * Asserts that the target is an arguments object. * * function test () { * expect(arguments).to.be.arguments; * } * * @name arguments * @alias Arguments * @namespace BDD * @api public */ function checkArguments () { var obj = flag(this, 'object') , type = Object.prototype.toString.call(obj); this.assert( '[object Arguments]' === type , 'expected #{this} to be arguments but got ' + type , 'expected #{this} to not be arguments' ); } Assertion.addProperty('arguments', checkArguments); Assertion.addProperty('Arguments', checkArguments); /** * ### .equal(value) * * Asserts that the target is strictly equal (`===`) to `value`. * Alternately, if the `deep` flag is set, asserts that * the target is deeply equal to `value`. * * expect('hello').to.equal('hello'); * expect(42).to.equal(42); * expect(1).to.not.equal(true); * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); * * @name equal * @alias equals * @alias eq * @alias deep.equal * @param {Mixed} value * @param {String} message _optional_ * @namespace BDD * @api public */ function assertEqual (val, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); if (flag(this, 'deep')) { return this.eql(val); } else { this.assert( val === obj , 'expected #{this} to equal #{exp}' , 'expected #{this} to not equal #{exp}' , val , this._obj , true ); } } Assertion.addMethod('equal', assertEqual); Assertion.addMethod('equals', assertEqual); Assertion.addMethod('eq', assertEqual); /** * ### .eql(value) * * Asserts that the target is deeply equal to `value`. * * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); * * @name eql * @alias eqls * @param {Mixed} value * @param {String} message _optional_ * @namespace BDD * @api public */ function assertEql(obj, msg) { if (msg) flag(this, 'message', msg); this.assert( _.eql(obj, flag(this, 'object')) , 'expected #{this} to deeply equal #{exp}' , 'expected #{this} to not deeply equal #{exp}' , obj , this._obj , true ); } Assertion.addMethod('eql', assertEql); Assertion.addMethod('eqls', assertEql); /** * ### .above(value) * * Asserts that the target is greater than `value`. * * expect(10).to.be.above(5); * * Can also be used in conjunction with `length` to * assert a minimum length. The benefit being a * more informative error message than if the length * was supplied directly. * * expect('foo').to.have.length.above(2); * expect([ 1, 2, 3 ]).to.have.length.above(2); * * @name above * @alias gt * @alias greaterThan * @param {Number} value * @param {String} message _optional_ * @namespace BDD * @api public */ function assertAbove (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); if (flag(this, 'doLength')) { new Assertion(obj, msg).to.have.property('length'); var len = obj.length; this.assert( len > n , 'expected #{this} to have a length above #{exp} but got #{act}' , 'expected #{this} to not have a length above #{exp}' , n , len ); } else { this.assert( obj > n , 'expected #{this} to be above ' + n , 'expected #{this} to be at most ' + n ); } } Assertion.addMethod('above', assertAbove); Assertion.addMethod('gt', assertAbove); Assertion.addMethod('greaterThan', assertAbove); /** * ### .least(value) * * Asserts that the target is greater than or equal to `value`. * * expect(10).to.be.at.least(10); * * Can also be used in conjunction with `length` to * assert a minimum length. The benefit being a * more informative error message than if the length * was supplied directly. * * expect('foo').to.have.length.of.at.least(2); * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); * * @name least * @alias gte * @param {Number} value * @param {String} message _optional_ * @namespace BDD * @api public */ function assertLeast (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); if (flag(this, 'doLength')) { new Assertion(obj, msg).to.have.property('length'); var len = obj.length; this.assert( len >= n , 'expected #{this} to have a length at least #{exp} but got #{act}' , 'expected #{this} to have a length below #{exp}' , n , len ); } else { this.assert( obj >= n , 'expected #{this} to be at least ' + n , 'expected #{this} to be below ' + n ); } } Assertion.addMethod('least', assertLeast); Assertion.addMethod('gte', assertLeast); /** * ### .below(value) * * Asserts that the target is less than `value`. * * expect(5).to.be.below(10); * * Can also be used in conjunction with `length` to * assert a maximum length. The benefit being a * more informative error message than if the length * was supplied directly. * * expect('foo').to.have.length.below(4); * expect([ 1, 2, 3 ]).to.have.length.below(4); * * @name below * @alias lt * @alias lessThan * @param {Number} value * @param {String} message _optional_ * @namespace BDD * @api public */ function assertBelow (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); if (flag(this, 'doLength')) { new Assertion(obj, msg).to.have.property('length'); var len = obj.length; this.assert( len < n , 'expected #{this} to have a length below #{exp} but got #{act}' , 'expected #{this} to not have a length below #{exp}' , n , len ); } else { this.assert( obj < n , 'expected #{this} to be below ' + n , 'expected #{this} to be at least ' + n ); } } Assertion.addMethod('below', assertBelow); Assertion.addMethod('lt', assertBelow); Assertion.addMethod('lessThan', assertBelow); /** * ### .most(value) * * Asserts that the target is less than or equal to `value`. * * expect(5).to.be.at.most(5); * * Can also be used in conjunction with `length` to * assert a maximum length. The benefit being a * more informative error message than if the length * was supplied directly. * * expect('foo').to.have.length.of.at.most(4); * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); * * @name most * @alias lte * @param {Number} value * @param {String} message _optional_ * @namespace BDD * @api public */ function assertMost (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); if (flag(this, 'doLength')) { new Assertion(obj, msg).to.have.property('length'); var len = obj.length; this.assert( len <= n , 'expected #{this} to have a length at most #{exp} but got #{act}' , 'expected #{this} to have a length above #{exp}' , n , len ); } else { this.assert( obj <= n , 'expected #{this} to be at most ' + n , 'expected #{this} to be above ' + n ); } } Assertion.addMethod('most', assertMost); Assertion.addMethod('lte', assertMost); /** * ### .within(start, finish) * * Asserts that the target is within a range. * * expect(7).to.be.within(5,10); * * Can also be used in conjunction with `length` to * assert a length range. The benefit being a * more informative error message than if the length * was supplied directly. * * expect('foo').to.have.length.within(2,4); * expect([ 1, 2, 3 ]).to.have.length.within(2,4); * * @name within * @param {Number} start lowerbound inclusive * @param {Number} finish upperbound inclusive * @param {String} message _optional_ * @namespace BDD * @api public */ Assertion.addMethod('within', function (start, finish, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') , range = start + '..' + finish; if (flag(this, 'doLength')) { new Assertion(obj, msg).to.have.property('length'); var len = obj.length; this.assert( len >= start && len <= finish , 'expected #{this} to have a length within ' + range , 'expected #{this} to not have a length within ' + range ); } else { this.assert( obj >= start && obj <= finish , 'expected #{this} to be within ' + range , 'expected #{this} to not be within ' + range ); } }); /** * ### .instanceof(constructor) * * Asserts that the target is an instance of `constructor`. * * var Tea = function (name) { this.name = name; } * , Chai = new Tea('chai'); * * expect(Chai).to.be.an.instanceof(Tea); * expect([ 1, 2, 3 ]).to.be.instanceof(Array); * * @name instanceof * @param {Constructor} constructor * @param {String} message _optional_ * @alias instanceOf * @namespace BDD * @api public */ function assertInstanceOf (constructor, msg) { if (msg) flag(this, 'message', msg); var name = _.getName(constructor); this.assert( flag(this, 'object') instanceof constructor , 'expected #{this} to be an instance of ' + name , 'expected #{this} to not be an instance of ' + name ); }; Assertion.addMethod('instanceof', assertInstanceOf); Assertion.addMethod('instanceOf', assertInstanceOf); /** * ### .property(name, [value]) * * Asserts that the target has a property `name`, optionally asserting that * the value of that property is strictly equal to `value`. * If the `deep` flag is set, you can use dot- and bracket-notation for deep * references into objects and arrays. * * // simple referencing * var obj = { foo: 'bar' }; * expect(obj).to.have.property('foo'); * expect(obj).to.have.property('foo', 'bar'); * * // deep referencing * var deepObj = { * green: { tea: 'matcha' } * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] * }; * * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); * * You can also use an array as the starting point of a `deep.property` * assertion, or traverse nested arrays. * * var arr = [ * [ 'chai', 'matcha', 'konacha' ] * , [ { tea: 'chai' } * , { tea: 'matcha' } * , { tea: 'konacha' } ] * ]; * * expect(arr).to.have.deep.property('[0][1]', 'matcha'); * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); * * Furthermore, `property` changes the subject of the assertion * to be the value of that property from the original object. This * permits for further chainable assertions on that property. * * expect(obj).to.have.property('foo') * .that.is.a('string'); * expect(deepObj).to.have.property('green') * .that.is.an('object') * .that.deep.equals({ tea: 'matcha' }); * expect(deepObj).to.have.property('teas') * .that.is.an('array') * .with.deep.property('[2]') * .that.deep.equals({ tea: 'konacha' }); * * Note that dots and bracket in `name` must be backslash-escaped when * the `deep` flag is set, while they must NOT be escaped when the `deep` * flag is not set. * * // simple referencing * var css = { '.link[target]': 42 }; * expect(css).to.have.property('.link[target]', 42); * * // deep referencing * var deepCss = { '.link': { '[target]': 42 }}; * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); * * @name property * @alias deep.property * @param {String} name * @param {Mixed} value (optional) * @param {String} message _optional_ * @returns value of property for chaining * @namespace BDD * @api public */ Assertion.addMethod('property', function (name, val, msg) { if (msg) flag(this, 'message', msg); var isDeep = !!flag(this, 'deep') , descriptor = isDeep ? 'deep property ' : 'property ' , negate = flag(this, 'negate') , obj = flag(this, 'object') , pathInfo = isDeep ? _.getPathInfo(name, obj) : null , hasProperty = isDeep ? pathInfo.exists : _.hasProperty(name, obj) , value = isDeep ? pathInfo.value : obj[name]; if (negate && arguments.length > 1) { if (undefined === value) { msg = (msg != null) ? msg + ': ' : ''; throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); } } else { this.assert( hasProperty , 'expected #{this} to have a ' + descriptor + _.inspect(name) , 'expected #{this} to not have ' + descriptor + _.inspect(name)); } if (arguments.length > 1) { this.assert( val === value , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' , val , value ); } flag(this, 'object', value); }); /** * ### .ownProperty(name) * * Asserts that the target has an own property `name`. * * expect('test').to.have.ownProperty('length'); * * @name ownProperty * @alias haveOwnProperty * @param {String} name * @param {String} message _optional_ * @namespace BDD * @api public */ function assertOwnProperty (name, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); this.assert( obj.hasOwnProperty(name) , 'expected #{this} to have own property ' + _.inspect(name) , 'expected #{this} to not have own property ' + _.inspect(name) ); } Assertion.addMethod('ownProperty', assertOwnProperty); Assertion.addMethod('haveOwnProperty', assertOwnProperty); /** * ### .ownPropertyDescriptor(name[, descriptor[, message]]) * * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. * * expect('test').to.have.ownPropertyDescriptor('length'); * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); * * @name ownPropertyDescriptor * @alias haveOwnPropertyDescriptor * @param {String} name * @param {Object} descriptor _optional_ * @param {String} message _optional_ * @namespace BDD * @api public */ function assertOwnPropertyDescriptor (name, descriptor, msg) { if (typeof descriptor === 'string') { msg = descriptor; descriptor = null; } if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); if (actualDescriptor && descriptor) { this.assert( _.eql(descriptor, actualDescriptor) , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) , descriptor , actualDescriptor , true ); } else { this.assert( actualDescriptor , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) ); } flag(this, 'object', actualDescriptor); } Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); /** * ### .length * * Sets the `doLength` flag later used as a chain precursor to a value * comparison for the `length` property. * * expect('foo').to.have.length.above(2); * expect([ 1, 2, 3 ]).to.have.length.above(2); * expect('foo').to.have.length.below(4); * expect([ 1, 2, 3 ]).to.have.length.below(4); * expect('foo').to.have.length.within(2,4); * expect([ 1, 2, 3 ]).to.have.length.within(2,4); * * *Deprecation notice:* Using `length` as an assertion will be deprecated * in version 2.4.0 and removed in 3.0.0. Code using the old style of * asserting for `length` property value using `length(value)` should be * switched to use `lengthOf(value)` instead. * * @name length * @namespace BDD * @api public */ /** * ### .lengthOf(value[, message]) * * Asserts that the target's `length` property has * the expected value. * * expect([ 1, 2, 3]).to.have.lengthOf(3); * expect('foobar').to.have.lengthOf(6); * * @name lengthOf * @param {Number} length * @param {String} message _optional_ * @namespace BDD * @api public */ function assertLengthChain () { flag(this, 'doLength', true); } function assertLength (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); new Assertion(obj, msg).to.have.property('length'); var len = obj.length; this.assert( len == n , 'expected #{this} to have a length of #{exp} but got #{act}' , 'expected #{this} to not have a length of #{act}' , n , len ); } Assertion.addChainableMethod('length', assertLength, assertLengthChain); Assertion.addMethod('lengthOf', assertLength); /** * ### .match(regexp) * * Asserts that the target matches a regular expression. * * expect('foobar').to.match(/^foo/); * * @name match * @alias matches * @param {RegExp} RegularExpression * @param {String} message _optional_ * @namespace BDD * @api public */ function assertMatch(re, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); this.assert( re.exec(obj) , 'expected #{this} to match ' + re , 'expected #{this} not to match ' + re ); } Assertion.addMethod('match', assertMatch); Assertion.addMethod('matches', assertMatch); /** * ### .string(string) * * Asserts that the string target contains another string. * * expect('foobar').to.have.string('bar'); * * @name string * @param {String} string * @param {String} message _optional_ * @namespace BDD * @api public */ Assertion.addMethod('string', function (str, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); new Assertion(obj, msg).is.a('string'); this.assert( ~obj.indexOf(str) , 'expected #{this} to contain ' + _.inspect(str) , 'expected #{this} to not contain ' + _.inspect(str) ); }); /** * ### .keys(key1, [key2], [...]) * * Asserts that the target contains any or all of the passed-in keys. * Use in combination with `any`, `all`, `contains`, or `have` will affect * what will pass. * * When used in conjunction with `any`, at least one key that is passed * in must exist in the target object. This is regardless whether or not * the `have` or `contain` qualifiers are used. Note, either `any` or `all` * should be used in the assertion. If neither are used, the assertion is * defaulted to `all`. * * When both `all` and `contain` are used, the target object must have at * least all of the passed-in keys but may have more keys not listed. * * When both `all` and `have` are used, the target object must both contain * all of the passed-in keys AND the number of keys in the target object must * match the number of keys passed in (in other words, a target object must * have all and only all of the passed-in keys). * * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); * * * @name keys * @alias key * @param {...String|Array|Object} keys * @namespace BDD * @api public */ function assertKeys (keys) { var obj = flag(this, 'object') , str , ok = true , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; switch (_.type(keys)) { case "array": if (arguments.length > 1) throw (new Error(mixedArgsMsg)); break; case "object": if (arguments.length > 1) throw (new Error(mixedArgsMsg)); keys = Object.keys(keys); break; default: keys = Array.prototype.slice.call(arguments); } if (!keys.length) throw new Error('keys required'); var actual = Object.keys(obj) , expected = keys , len = keys.length , any = flag(this, 'any') , all = flag(this, 'all'); if (!any && !all) { all = true; } // Has any if (any) { var intersection = expected.filter(function(key) { return ~actual.indexOf(key); }); ok = intersection.length > 0; } // Has all if (all) { ok = keys.every(function(key){ return ~actual.indexOf(key); }); if (!flag(this, 'negate') && !flag(this, 'contains')) { ok = ok && keys.length == actual.length; } } // Key string if (len > 1) { keys = keys.map(function(key){ return _.inspect(key); }); var last = keys.pop(); if (all) { str = keys.join(', ') + ', and ' + last; } if (any) { str = keys.join(', ') + ', or ' + last; } } else { str = _.inspect(keys[0]); } // Form str = (len > 1 ? 'keys ' : 'key ') + str; // Have / include str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; // Assertion this.assert( ok , 'expected #{this} to ' + str , 'expected #{this} to not ' + str , expected.slice(0).sort() , actual.sort() , true ); } Assertion.addMethod('keys', assertKeys); Assertion.addMethod('key', assertKeys); /** * ### .throw(constructor) * * Asserts that the function target will throw a specific error, or specific type of error * (as determined using `instanceof`), optionally with a RegExp or string inclusion test * for the error's message. * * var err = new ReferenceError('This is a bad function.'); * var fn = function () { throw err; } * expect(fn).to.throw(ReferenceError); * expect(fn).to.throw(Error); * expect(fn).to.throw(/bad function/); * expect(fn).to.not.throw('good function'); * expect(fn).to.throw(ReferenceError, /bad function/); * expect(fn).to.throw(err); * * Please note that when a throw expectation is negated, it will check each * parameter independently, starting with error constructor type. The appropriate way * to check for the existence of a type of error but for a message that does not match * is to use `and`. * * expect(fn).to.throw(ReferenceError) * .and.not.throw(/good function/); * * @name throw * @alias throws * @alias Throw * @param {ErrorConstructor} constructor * @param {String|RegExp} expected error message * @param {String} message _optional_ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types * @returns error for chaining (null if no error) * @namespace BDD * @api public */ function assertThrows (constructor, errMsg, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); new Assertion(obj, msg).is.a('function'); var thrown = false , desiredError = null , name = null , thrownError = null; if (arguments.length === 0) { errMsg = null; constructor = null; } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { errMsg = constructor; constructor = null; } else if (constructor && constructor instanceof Error) { desiredError = constructor; constructor = null; errMsg = null; } else if (typeof constructor === 'function') { name = constructor.prototype.name; if (!name || (name === 'Error' && constructor !== Error)) { name = constructor.name || (new constructor()).name; } } else { constructor = null; } try { obj(); } catch (err) { // first, check desired error if (desiredError) { this.assert( err === desiredError , 'expected #{this} to throw #{exp} but #{act} was thrown' , 'expected #{this} to not throw #{exp}' , (desiredError instanceof Error ? desiredError.toString() : desiredError) , (err instanceof Error ? err.toString() : err) ); flag(this, 'object', err); return this; } // next, check constructor if (constructor) { this.assert( err instanceof constructor , 'expected #{this} to throw #{exp} but #{act} was thrown' , 'expected #{this} to not throw #{exp} but #{act} was thrown' , name , (err instanceof Error ? err.toString() : err) ); if (!errMsg) { flag(this, 'object', err); return this; } } // next, check message var message = 'error' === _.type(err) && "message" in err ? err.message : '' + err; if ((message != null) && errMsg && errMsg instanceof RegExp) { this.assert( errMsg.exec(message) , 'expected #{this} to throw error matching #{exp} but got #{act}' , 'expected #{this} to throw error not matching #{exp}' , errMsg , message ); flag(this, 'object', err); return this; } else if ((message != null) && errMsg && 'string' === typeof errMsg) { this.assert( ~message.indexOf(errMsg) , 'expected #{this} to throw error including #{exp} but got #{act}' , 'expected #{this} to throw error not including #{act}' , errMsg , message ); flag(this, 'object', err); return this; } else { thrown = true; thrownError = err; } } var actuallyGot = '' , expectedThrown = name !== null ? name : desiredError ? '#{exp}' //_.inspect(desiredError) : 'an error'; if (thrown) { actuallyGot = ' but #{act} was thrown' } this.assert( thrown === true , 'expected #{this} to throw ' + expectedThrown + actuallyGot , 'expected #{this} to not throw ' + expectedThrown + actuallyGot , (desiredError instanceof Error ? desiredError.toString() : desiredError) , (thrownError instanceof Error ? thrownError.toString() : thrownError) ); flag(this, 'object', thrownError); }; Assertion.addMethod('throw', assertThrows); Assertion.addMethod('throws', assertThrows); Assertion.addMethod('Throw', assertThrows); /** * ### .respondTo(method) * * Asserts that the object or class target will respond to a method. * * Klass.prototype.bar = function(){}; * expect(Klass).to.respondTo('bar'); * expect(obj).to.respondTo('bar'); * * To check if a constructor will respond to a static function, * set the `itself` flag. * * Klass.baz = function(){}; * expect(Klass).itself.to.respondTo('baz'); * * @name respondTo * @alias respondsTo * @param {String} method * @param {String} message _optional_ * @namespace BDD * @api public */ function respondTo (method, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') , itself = flag(this, 'itself') , context = ('function' === _.type(obj) && !itself) ? obj.prototype[method] : obj[method]; this.assert( 'function' === typeof context , 'expected #{this} to respond to ' + _.inspect(method) , 'expected #{this} to not respond to ' + _.inspect(method) ); } Assertion.addMethod('respondTo', respondTo); Assertion.addMethod('respondsTo', respondTo); /** * ### .itself * * Sets the `itself` flag, later used by the `respondTo` assertion. * * function Foo() {} * Foo.bar = function() {} * Foo.prototype.baz = function() {} * * expect(Foo).itself.to.respondTo('bar'); * expect(Foo).itself.not.to.respondTo('baz'); * * @name itself * @namespace BDD * @api public */ Assertion.addProperty('itself', function () { flag(this, 'itself', true); }); /** * ### .satisfy(method) * * Asserts that the target passes a given truth test. * * expect(1).to.satisfy(function(num) { return num > 0; }); * * @name satisfy * @alias satisfies * @param {Function} matcher * @param {String} message _optional_ * @namespace BDD * @api public */ function satisfy (matcher, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); var result = matcher(obj); this.assert( result , 'expected #{this} to satisfy ' + _.objDisplay(matcher) , 'expected #{this} to not satisfy' + _.objDisplay(matcher) , this.negate ? false : true , result ); } Assertion.addMethod('satisfy', satisfy); Assertion.addMethod('satisfies', satisfy); /** * ### .closeTo(expected, delta) * * Asserts that the target is equal `expected`, to within a +/- `delta` range. * * expect(1.5).to.be.closeTo(1, 0.5); * * @name closeTo * @alias approximately * @param {Number} expected * @param {Number} delta * @param {String} message _optional_ * @namespace BDD * @api public */ function closeTo(expected, delta, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); new Assertion(obj, msg).is.a('number'); if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { throw new Error('the arguments to closeTo or approximately must be numbers'); } this.assert( Math.abs(obj - expected) <= delta , 'expected #{this} to be close to ' + expected + ' +/- ' + delta , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta ); } Assertion.addMethod('closeTo', closeTo); Assertion.addMethod('approximately', closeTo); function isSub