├── .gitignore ├── README.md ├── render-slicer.js └── test ├── mocha ├── chai.js ├── mocha.css └── mocha.js ├── test-runner.html └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | render-slicer 2 | ============ 3 | render-slicer.js is a small utility for progressive rendering using requestAnimationFrame. 4 | 5 | It is based on a [small utility for progressive rendering](http://bl.ocks.org/syntagmatic/raw/3341641/). Since I use it a lot and want to expand it, 6 | I thought it deserved a proper home on GitHub, so users can modify it and share. My only contribution for now was to add a unit test suite and some minor mods. 7 | 8 | Here is an [example of progressive rendering](http://bl.ocks.org/biovisualize/f84111e34edc6d594216) on two line charts, each rendering 10K points. 9 | I set the rendering rate down so the progressive rendering is more visible. 10 | 11 | Documentation 12 | ------------- 13 | **renderSlicer() takes a function and returns a version wrapped with progressive rendering** 14 | var foo = function(){ /* render something */ } 15 | var fooWrapped = renderSlicer(foo); 16 | 17 | **The wrapped function takes an array and starts a loop to repeatedly call the function, passing each data point as argument** 18 | fooWrapped(data); 19 | 20 | **New data can be pushed to the render queue** 21 | fooWrapped.add(moreData); 22 | 23 | **The rate() setter will change the chunk size, or return the rate value when called without argument** 24 | var fooWrapped = renderSlicer(foo).rate(100); 25 | 26 | **It provides getters for the size of the remaining data to be processed. remaining() is decreasing by chunk size 27 | and count() is increasing every frame** 28 | fooWrapped.count(); 29 | fooWrapped.remaining(); 30 | 31 | **It also provides a series of callbacks** 32 | fooWrapped.onStart(function(){ console.log('queue is started'); }); 33 | fooWrapped.onChunkDone(function(){ console.log('chunk is done'); }); 34 | fooWrapped.onFrameDone(function(){ console.log('frame is done'); }); 35 | fooWrapped.onDone(function(){ console.log('queue is done'); }); -------------------------------------------------------------------------------- /render-slicer.js: -------------------------------------------------------------------------------- 1 | var renderSlicer = (function (func) { 2 | var _queue = [], // data to be rendered 3 | _rate = 1000, // number of calls per frame 4 | _invalidate = function () {}, // invalidate last render queue 5 | _onStartCallback = function () {}, // clearing function 6 | _isDone = false, 7 | _doneCallback, // all done 8 | _chunkDoneCallback, // chunk done 9 | _startQueueSize, 10 | _frameDoneCallback, 11 | _dataCountDone; // percent done 12 | 13 | var rq = function (data) { 14 | _isDone = false; 15 | if (data) rq.data(data); 16 | _invalidate(); 17 | _onStartCallback(); 18 | rq.render(); 19 | }; 20 | 21 | rq.render = function () { 22 | var valid = true; 23 | _invalidate = rq.invalidate = function () { 24 | valid = false; 25 | }; 26 | 27 | function doFrame() { 28 | if (!valid) return true; 29 | if (!_isDone && _queue.length === 0 && _doneCallback) { 30 | _isDone = true; 31 | _doneCallback(); 32 | } 33 | var chunk = _queue.splice(0, _rate); 34 | chunk.map(function(d){ 35 | _dataCountDone++; 36 | if(_frameDoneCallback) _frameDoneCallback(); 37 | func(d); 38 | }); 39 | if(chunk.length > 0 && _chunkDoneCallback){ 40 | _chunkDoneCallback(); 41 | } 42 | timer_frame(doFrame); 43 | } 44 | 45 | doFrame(); 46 | }; 47 | 48 | rq.onStart = function (onStartCallback) { 49 | _onStartCallback = onStartCallback; 50 | return rq; 51 | }; 52 | 53 | rq.onChunkDone = function (chunkDoneCallback) { 54 | _chunkDoneCallback = chunkDoneCallback; 55 | return rq; 56 | }; 57 | 58 | rq.onFrameDone = function (frameDoneCallback) { 59 | _frameDoneCallback = frameDoneCallback; 60 | return rq; 61 | }; 62 | 63 | rq.onDone = function (doneCallback) { 64 | _doneCallback = doneCallback; 65 | return rq; 66 | }; 67 | 68 | rq.data = function (data) { 69 | _startQueueSize = data.length; 70 | _dataCountDone = 0; 71 | _invalidate(); 72 | _queue = data.slice(0); // creates a copy of the data 73 | return rq; 74 | }; 75 | 76 | rq.add = function (data) { 77 | _queue = _queue.concat(data); 78 | }; 79 | 80 | rq.rate = function (value) { 81 | if (!arguments.length) return _rate; 82 | _rate = value; 83 | return rq; 84 | }; 85 | 86 | rq.remaining = function () { 87 | return _queue.length; 88 | }; 89 | 90 | rq.count = function(){ 91 | return _dataCountDone; 92 | }; 93 | 94 | rq.invalidate = _invalidate; 95 | 96 | var timer_frame = window.requestAnimationFrame 97 | || window.webkitRequestAnimationFrame 98 | || window.mozRequestAnimationFrame 99 | || window.oRequestAnimationFrame 100 | || window.msRequestAnimationFrame 101 | || function (callback) { setTimeout(callback, 17); }; 102 | 103 | return rq; 104 | }); -------------------------------------------------------------------------------- /test/mocha/chai.js: -------------------------------------------------------------------------------- 1 | ;(function(){ 2 | 3 | /** 4 | * Require the given path. 5 | * 6 | * @param {String} path 7 | * @return {Object} exports 8 | * @api public 9 | */ 10 | 11 | function require(path, parent, orig) { 12 | var resolved = require.resolve(path); 13 | 14 | // lookup failed 15 | if (null == resolved) { 16 | orig = orig || path; 17 | parent = parent || 'root'; 18 | var err = new Error('Failed to require "' + orig + '" from "' + parent + '"'); 19 | err.path = orig; 20 | err.parent = parent; 21 | err.require = true; 22 | throw err; 23 | } 24 | 25 | var module = require.modules[resolved]; 26 | 27 | // perform real require() 28 | // by invoking the module's 29 | // registered function 30 | if (!module._resolving && !module.exports) { 31 | var mod = {}; 32 | mod.exports = {}; 33 | mod.client = mod.component = true; 34 | module._resolving = true; 35 | module.call(this, mod.exports, require.relative(resolved), mod); 36 | delete module._resolving; 37 | module.exports = mod.exports; 38 | } 39 | 40 | return module.exports; 41 | } 42 | 43 | /** 44 | * Registered modules. 45 | */ 46 | 47 | require.modules = {}; 48 | 49 | /** 50 | * Registered aliases. 51 | */ 52 | 53 | require.aliases = {}; 54 | 55 | /** 56 | * Resolve `path`. 57 | * 58 | * Lookup: 59 | * 60 | * - PATH/index.js 61 | * - PATH.js 62 | * - PATH 63 | * 64 | * @param {String} path 65 | * @return {String} path or null 66 | * @api private 67 | */ 68 | 69 | require.resolve = function(path) { 70 | if (path.charAt(0) === '/') path = path.slice(1); 71 | 72 | var paths = [ 73 | path, 74 | path + '.js', 75 | path + '.json', 76 | path + '/index.js', 77 | path + '/index.json' 78 | ]; 79 | 80 | for (var i = 0; i < paths.length; i++) { 81 | var path = paths[i]; 82 | if (require.modules.hasOwnProperty(path)) return path; 83 | if (require.aliases.hasOwnProperty(path)) return require.aliases[path]; 84 | } 85 | }; 86 | 87 | /** 88 | * Normalize `path` relative to the current path. 89 | * 90 | * @param {String} curr 91 | * @param {String} path 92 | * @return {String} 93 | * @api private 94 | */ 95 | 96 | require.normalize = function(curr, path) { 97 | var segs = []; 98 | 99 | if ('.' != path.charAt(0)) return path; 100 | 101 | curr = curr.split('/'); 102 | path = path.split('/'); 103 | 104 | for (var i = 0; i < path.length; ++i) { 105 | if ('..' == path[i]) { 106 | curr.pop(); 107 | } else if ('.' != path[i] && '' != path[i]) { 108 | segs.push(path[i]); 109 | } 110 | } 111 | 112 | return curr.concat(segs).join('/'); 113 | }; 114 | 115 | /** 116 | * Register module at `path` with callback `definition`. 117 | * 118 | * @param {String} path 119 | * @param {Function} definition 120 | * @api private 121 | */ 122 | 123 | require.register = function(path, definition) { 124 | require.modules[path] = definition; 125 | }; 126 | 127 | /** 128 | * Alias a module definition. 129 | * 130 | * @param {String} from 131 | * @param {String} to 132 | * @api private 133 | */ 134 | 135 | require.alias = function(from, to) { 136 | if (!require.modules.hasOwnProperty(from)) { 137 | throw new Error('Failed to alias "' + from + '", it does not exist'); 138 | } 139 | require.aliases[to] = from; 140 | }; 141 | 142 | /** 143 | * Return a require function relative to the `parent` path. 144 | * 145 | * @param {String} parent 146 | * @return {Function} 147 | * @api private 148 | */ 149 | 150 | require.relative = function(parent) { 151 | var p = require.normalize(parent, '..'); 152 | 153 | /** 154 | * lastIndexOf helper. 155 | */ 156 | 157 | function lastIndexOf(arr, obj) { 158 | var i = arr.length; 159 | while (i--) { 160 | if (arr[i] === obj) return i; 161 | } 162 | return -1; 163 | } 164 | 165 | /** 166 | * The relative require() itself. 167 | */ 168 | 169 | function localRequire(path) { 170 | var resolved = localRequire.resolve(path); 171 | return require(resolved, parent, path); 172 | } 173 | 174 | /** 175 | * Resolve relative to the parent. 176 | */ 177 | 178 | localRequire.resolve = function(path) { 179 | var c = path.charAt(0); 180 | if ('/' == c) return path.slice(1); 181 | if ('.' == c) return require.normalize(p, path); 182 | 183 | // resolve deps by returning 184 | // the dep in the nearest "deps" 185 | // directory 186 | var segs = parent.split('/'); 187 | var i = lastIndexOf(segs, 'deps') + 1; 188 | if (!i) i = 0; 189 | path = segs.slice(0, i + 1).join('/') + '/deps/' + path; 190 | return path; 191 | }; 192 | 193 | /** 194 | * Check if module is defined at `path`. 195 | */ 196 | 197 | localRequire.exists = function(path) { 198 | return require.modules.hasOwnProperty(localRequire.resolve(path)); 199 | }; 200 | 201 | return localRequire; 202 | }; 203 | require.register("chaijs-assertion-error/index.js", function(exports, require, module){ 204 | /*! 205 | * assertion-error 206 | * Copyright(c) 2013 Jake Luer 207 | * MIT Licensed 208 | */ 209 | 210 | /*! 211 | * Return a function that will copy properties from 212 | * one object to another excluding any originally 213 | * listed. Returned function will create a new `{}`. 214 | * 215 | * @param {String} excluded properties ... 216 | * @return {Function} 217 | */ 218 | 219 | function exclude () { 220 | var excludes = [].slice.call(arguments); 221 | 222 | function excludeProps (res, obj) { 223 | Object.keys(obj).forEach(function (key) { 224 | if (!~excludes.indexOf(key)) res[key] = obj[key]; 225 | }); 226 | } 227 | 228 | return function extendExclude () { 229 | var args = [].slice.call(arguments) 230 | , i = 0 231 | , res = {}; 232 | 233 | for (; i < args.length; i++) { 234 | excludeProps(res, args[i]); 235 | } 236 | 237 | return res; 238 | }; 239 | }; 240 | 241 | /*! 242 | * Primary Exports 243 | */ 244 | 245 | module.exports = AssertionError; 246 | 247 | /** 248 | * ### AssertionError 249 | * 250 | * An extension of the JavaScript `Error` constructor for 251 | * assertion and validation scenarios. 252 | * 253 | * @param {String} message 254 | * @param {Object} properties to include (optional) 255 | * @param {callee} start stack function (optional) 256 | */ 257 | 258 | function AssertionError (message, _props, ssf) { 259 | var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') 260 | , props = extend(_props || {}); 261 | 262 | // default values 263 | this.message = message || 'Unspecified AssertionError'; 264 | this.showDiff = false; 265 | 266 | // copy from properties 267 | for (var key in props) { 268 | this[key] = props[key]; 269 | } 270 | 271 | // capture stack trace 272 | ssf = ssf || arguments.callee; 273 | if (ssf && Error.captureStackTrace) { 274 | Error.captureStackTrace(this, ssf); 275 | } 276 | } 277 | 278 | /*! 279 | * Inherit from Error.prototype 280 | */ 281 | 282 | AssertionError.prototype = Object.create(Error.prototype); 283 | 284 | /*! 285 | * Statically set name 286 | */ 287 | 288 | AssertionError.prototype.name = 'AssertionError'; 289 | 290 | /*! 291 | * Ensure correct constructor 292 | */ 293 | 294 | AssertionError.prototype.constructor = AssertionError; 295 | 296 | /** 297 | * Allow errors to be converted to JSON for static transfer. 298 | * 299 | * @param {Boolean} include stack (default: `true`) 300 | * @return {Object} object that can be `JSON.stringify` 301 | */ 302 | 303 | AssertionError.prototype.toJSON = function (stack) { 304 | var extend = exclude('constructor', 'toJSON', 'stack') 305 | , props = extend({ name: this.name }, this); 306 | 307 | // include stack if exists and not turned off 308 | if (false !== stack && this.stack) { 309 | props.stack = this.stack; 310 | } 311 | 312 | return props; 313 | }; 314 | 315 | }); 316 | require.register("chaijs-type-detect/lib/type.js", function(exports, require, module){ 317 | /*! 318 | * type-detect 319 | * Copyright(c) 2013 jake luer 320 | * MIT Licensed 321 | */ 322 | 323 | /*! 324 | * Primary Exports 325 | */ 326 | 327 | var exports = module.exports = getType; 328 | 329 | /*! 330 | * Detectable javascript natives 331 | */ 332 | 333 | var natives = { 334 | '[object Array]': 'array' 335 | , '[object RegExp]': 'regexp' 336 | , '[object Function]': 'function' 337 | , '[object Arguments]': 'arguments' 338 | , '[object Date]': 'date' 339 | }; 340 | 341 | /** 342 | * ### typeOf (obj) 343 | * 344 | * Use several different techniques to determine 345 | * the type of object being tested. 346 | * 347 | * 348 | * @param {Mixed} object 349 | * @return {String} object type 350 | * @api public 351 | */ 352 | 353 | function getType (obj) { 354 | var str = Object.prototype.toString.call(obj); 355 | if (natives[str]) return natives[str]; 356 | if (obj === null) return 'null'; 357 | if (obj === undefined) return 'undefined'; 358 | if (obj === Object(obj)) return 'object'; 359 | return typeof obj; 360 | } 361 | 362 | exports.Library = Library; 363 | 364 | /** 365 | * ### Library 366 | * 367 | * Create a repository for custom type detection. 368 | * 369 | * ```js 370 | * var lib = new type.Library; 371 | * ``` 372 | * 373 | */ 374 | 375 | function Library () { 376 | this.tests = {}; 377 | } 378 | 379 | /** 380 | * #### .of (obj) 381 | * 382 | * Expose replacement `typeof` detection to the library. 383 | * 384 | * ```js 385 | * if ('string' === lib.of('hello world')) { 386 | * // ... 387 | * } 388 | * ``` 389 | * 390 | * @param {Mixed} object to test 391 | * @return {String} type 392 | */ 393 | 394 | Library.prototype.of = getType; 395 | 396 | /** 397 | * #### .define (type, test) 398 | * 399 | * Add a test to for the `.test()` assertion. 400 | * 401 | * Can be defined as a regular expression: 402 | * 403 | * ```js 404 | * lib.define('int', /^[0-9]+$/); 405 | * ``` 406 | * 407 | * ... or as a function: 408 | * 409 | * ```js 410 | * lib.define('bln', function (obj) { 411 | * if ('boolean' === lib.of(obj)) return true; 412 | * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; 413 | * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); 414 | * return !! ~blns.indexOf(obj); 415 | * }); 416 | * ``` 417 | * 418 | * @param {String} type 419 | * @param {RegExp|Function} test 420 | * @api public 421 | */ 422 | 423 | Library.prototype.define = function (type, test) { 424 | if (arguments.length === 1) return this.tests[type]; 425 | this.tests[type] = test; 426 | return this; 427 | }; 428 | 429 | /** 430 | * #### .test (obj, test) 431 | * 432 | * Assert that an object is of type. Will first 433 | * check natives, and if that does not pass it will 434 | * use the user defined custom tests. 435 | * 436 | * ```js 437 | * assert(lib.test('1', 'int')); 438 | * assert(lib.test('yes', 'bln')); 439 | * ``` 440 | * 441 | * @param {Mixed} object 442 | * @param {String} type 443 | * @return {Boolean} result 444 | * @api public 445 | */ 446 | 447 | Library.prototype.test = function (obj, type) { 448 | if (type === getType(obj)) return true; 449 | var test = this.tests[type]; 450 | 451 | if (test && 'regexp' === getType(test)) { 452 | return test.test(obj); 453 | } else if (test && 'function' === getType(test)) { 454 | return test(obj); 455 | } else { 456 | throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); 457 | } 458 | }; 459 | 460 | }); 461 | require.register("chaijs-deep-eql/lib/eql.js", function(exports, require, module){ 462 | /*! 463 | * deep-eql 464 | * Copyright(c) 2013 Jake Luer 465 | * MIT Licensed 466 | */ 467 | 468 | /*! 469 | * Module dependencies 470 | */ 471 | 472 | var type = require('type-detect'); 473 | 474 | /*! 475 | * Buffer.isBuffer browser shim 476 | */ 477 | 478 | var Buffer; 479 | try { Buffer = require('buffer').Buffer; } 480 | catch(ex) { 481 | Buffer = {}; 482 | Buffer.isBuffer = function() { return false; } 483 | } 484 | 485 | /*! 486 | * Primary Export 487 | */ 488 | 489 | module.exports = deepEqual; 490 | 491 | /** 492 | * Assert super-strict (egal) equality between 493 | * two objects of any type. 494 | * 495 | * @param {Mixed} a 496 | * @param {Mixed} b 497 | * @param {Array} memoised (optional) 498 | * @return {Boolean} equal match 499 | */ 500 | 501 | function deepEqual(a, b, m) { 502 | if (sameValue(a, b)) { 503 | return true; 504 | } else if ('date' === type(a)) { 505 | return dateEqual(a, b); 506 | } else if ('regexp' === type(a)) { 507 | return regexpEqual(a, b); 508 | } else if (Buffer.isBuffer(a)) { 509 | return bufferEqual(a, b); 510 | } else if ('arguments' === type(a)) { 511 | return argumentsEqual(a, b, m); 512 | } else if (!typeEqual(a, b)) { 513 | return false; 514 | } else if (('object' !== type(a) && 'object' !== type(b)) 515 | && ('array' !== type(a) && 'array' !== type(b))) { 516 | return sameValue(a, b); 517 | } else { 518 | return objectEqual(a, b, m); 519 | } 520 | } 521 | 522 | /*! 523 | * Strict (egal) equality test. Ensures that NaN always 524 | * equals NaN and `-0` does not equal `+0`. 525 | * 526 | * @param {Mixed} a 527 | * @param {Mixed} b 528 | * @return {Boolean} equal match 529 | */ 530 | 531 | function sameValue(a, b) { 532 | if (a === b) return a !== 0 || 1 / a === 1 / b; 533 | return a !== a && b !== b; 534 | } 535 | 536 | /*! 537 | * Compare the types of two given objects and 538 | * return if they are equal. Note that an Array 539 | * has a type of `array` (not `object`) and arguments 540 | * have a type of `arguments` (not `array`/`object`). 541 | * 542 | * @param {Mixed} a 543 | * @param {Mixed} b 544 | * @return {Boolean} result 545 | */ 546 | 547 | function typeEqual(a, b) { 548 | return type(a) === type(b); 549 | } 550 | 551 | /*! 552 | * Compare two Date objects by asserting that 553 | * the time values are equal using `saveValue`. 554 | * 555 | * @param {Date} a 556 | * @param {Date} b 557 | * @return {Boolean} result 558 | */ 559 | 560 | function dateEqual(a, b) { 561 | if ('date' !== type(b)) return false; 562 | return sameValue(a.getTime(), b.getTime()); 563 | } 564 | 565 | /*! 566 | * Compare two regular expressions by converting them 567 | * to string and checking for `sameValue`. 568 | * 569 | * @param {RegExp} a 570 | * @param {RegExp} b 571 | * @return {Boolean} result 572 | */ 573 | 574 | function regexpEqual(a, b) { 575 | if ('regexp' !== type(b)) return false; 576 | return sameValue(a.toString(), b.toString()); 577 | } 578 | 579 | /*! 580 | * Assert deep equality of two `arguments` objects. 581 | * Unfortunately, these must be sliced to arrays 582 | * prior to test to ensure no bad behavior. 583 | * 584 | * @param {Arguments} a 585 | * @param {Arguments} b 586 | * @param {Array} memoize (optional) 587 | * @return {Boolean} result 588 | */ 589 | 590 | function argumentsEqual(a, b, m) { 591 | if ('arguments' !== type(b)) return false; 592 | a = [].slice.call(a); 593 | b = [].slice.call(b); 594 | return deepEqual(a, b, m); 595 | } 596 | 597 | /*! 598 | * Get enumerable properties of a given object. 599 | * 600 | * @param {Object} a 601 | * @return {Array} property names 602 | */ 603 | 604 | function enumerable(a) { 605 | var res = []; 606 | for (var key in a) res.push(key); 607 | return res; 608 | } 609 | 610 | /*! 611 | * Simple equality for flat iterable objects 612 | * such as Arrays or Node.js buffers. 613 | * 614 | * @param {Iterable} a 615 | * @param {Iterable} b 616 | * @return {Boolean} result 617 | */ 618 | 619 | function iterableEqual(a, b) { 620 | if (a.length !== b.length) return false; 621 | 622 | var i = 0; 623 | var match = true; 624 | 625 | for (; i < a.length; i++) { 626 | if (a[i] !== b[i]) { 627 | match = false; 628 | break; 629 | } 630 | } 631 | 632 | return match; 633 | } 634 | 635 | /*! 636 | * Extension to `iterableEqual` specifically 637 | * for Node.js Buffers. 638 | * 639 | * @param {Buffer} a 640 | * @param {Mixed} b 641 | * @return {Boolean} result 642 | */ 643 | 644 | function bufferEqual(a, b) { 645 | if (!Buffer.isBuffer(b)) return false; 646 | return iterableEqual(a, b); 647 | } 648 | 649 | /*! 650 | * Block for `objectEqual` ensuring non-existing 651 | * values don't get in. 652 | * 653 | * @param {Mixed} object 654 | * @return {Boolean} result 655 | */ 656 | 657 | function isValue(a) { 658 | return a !== null && a !== undefined; 659 | } 660 | 661 | /*! 662 | * Recursively check the equality of two objects. 663 | * Once basic sameness has been established it will 664 | * defer to `deepEqual` for each enumerable key 665 | * in the object. 666 | * 667 | * @param {Mixed} a 668 | * @param {Mixed} b 669 | * @return {Boolean} result 670 | */ 671 | 672 | function objectEqual(a, b, m) { 673 | if (!isValue(a) || !isValue(b)) { 674 | return false; 675 | } 676 | 677 | if (a.prototype !== b.prototype) { 678 | return false; 679 | } 680 | 681 | var i; 682 | if (m) { 683 | for (i = 0; i < m.length; i++) { 684 | if ((m[i][0] === a && m[i][1] === b) 685 | || (m[i][0] === b && m[i][1] === a)) { 686 | return true; 687 | } 688 | } 689 | } else { 690 | m = []; 691 | } 692 | 693 | try { 694 | var ka = enumerable(a); 695 | var kb = enumerable(b); 696 | } catch (ex) { 697 | return false; 698 | } 699 | 700 | ka.sort(); 701 | kb.sort(); 702 | 703 | if (!iterableEqual(ka, kb)) { 704 | return false; 705 | } 706 | 707 | m.push([ a, b ]); 708 | 709 | var key; 710 | for (i = ka.length - 1; i >= 0; i--) { 711 | key = ka[i]; 712 | if (!deepEqual(a[key], b[key], m)) { 713 | return false; 714 | } 715 | } 716 | 717 | return true; 718 | } 719 | 720 | }); 721 | require.register("chai/index.js", function(exports, require, module){ 722 | module.exports = require('./lib/chai'); 723 | 724 | }); 725 | require.register("chai/lib/chai.js", function(exports, require, module){ 726 | /*! 727 | * chai 728 | * Copyright(c) 2011-2014 Jake Luer 729 | * MIT Licensed 730 | */ 731 | 732 | var used = [] 733 | , exports = module.exports = {}; 734 | 735 | /*! 736 | * Chai version 737 | */ 738 | 739 | exports.version = '1.9.2'; 740 | 741 | /*! 742 | * Assertion Error 743 | */ 744 | 745 | exports.AssertionError = require('assertion-error'); 746 | 747 | /*! 748 | * Utils for plugins (not exported) 749 | */ 750 | 751 | var util = require('./chai/utils'); 752 | 753 | /** 754 | * # .use(function) 755 | * 756 | * Provides a way to extend the internals of Chai 757 | * 758 | * @param {Function} 759 | * @returns {this} for chaining 760 | * @api public 761 | */ 762 | 763 | exports.use = function (fn) { 764 | if (!~used.indexOf(fn)) { 765 | fn(this, util); 766 | used.push(fn); 767 | } 768 | 769 | return this; 770 | }; 771 | 772 | /*! 773 | * Configuration 774 | */ 775 | 776 | var config = require('./chai/config'); 777 | exports.config = config; 778 | 779 | /*! 780 | * Primary `Assertion` prototype 781 | */ 782 | 783 | var assertion = require('./chai/assertion'); 784 | exports.use(assertion); 785 | 786 | /*! 787 | * Core Assertions 788 | */ 789 | 790 | var core = require('./chai/core/assertions'); 791 | exports.use(core); 792 | 793 | /*! 794 | * Expect interface 795 | */ 796 | 797 | var expect = require('./chai/interface/expect'); 798 | exports.use(expect); 799 | 800 | /*! 801 | * Should interface 802 | */ 803 | 804 | var should = require('./chai/interface/should'); 805 | exports.use(should); 806 | 807 | /*! 808 | * Assert interface 809 | */ 810 | 811 | var assert = require('./chai/interface/assert'); 812 | exports.use(assert); 813 | 814 | }); 815 | require.register("chai/lib/chai/assertion.js", function(exports, require, module){ 816 | /*! 817 | * chai 818 | * http://chaijs.com 819 | * Copyright(c) 2011-2014 Jake Luer 820 | * MIT Licensed 821 | */ 822 | 823 | var config = require('./config'); 824 | 825 | module.exports = function (_chai, util) { 826 | /*! 827 | * Module dependencies. 828 | */ 829 | 830 | var AssertionError = _chai.AssertionError 831 | , flag = util.flag; 832 | 833 | /*! 834 | * Module export. 835 | */ 836 | 837 | _chai.Assertion = Assertion; 838 | 839 | /*! 840 | * Assertion Constructor 841 | * 842 | * Creates object for chaining. 843 | * 844 | * @api private 845 | */ 846 | 847 | function Assertion (obj, msg, stack) { 848 | flag(this, 'ssfi', stack || arguments.callee); 849 | flag(this, 'object', obj); 850 | flag(this, 'message', msg); 851 | } 852 | 853 | Object.defineProperty(Assertion, 'includeStack', { 854 | get: function() { 855 | console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); 856 | return config.includeStack; 857 | }, 858 | set: function(value) { 859 | console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); 860 | config.includeStack = value; 861 | } 862 | }); 863 | 864 | Object.defineProperty(Assertion, 'showDiff', { 865 | get: function() { 866 | console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); 867 | return config.showDiff; 868 | }, 869 | set: function(value) { 870 | console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); 871 | config.showDiff = value; 872 | } 873 | }); 874 | 875 | Assertion.addProperty = function (name, fn) { 876 | util.addProperty(this.prototype, name, fn); 877 | }; 878 | 879 | Assertion.addMethod = function (name, fn) { 880 | util.addMethod(this.prototype, name, fn); 881 | }; 882 | 883 | Assertion.addChainableMethod = function (name, fn, chainingBehavior) { 884 | util.addChainableMethod(this.prototype, name, fn, chainingBehavior); 885 | }; 886 | 887 | Assertion.overwriteProperty = function (name, fn) { 888 | util.overwriteProperty(this.prototype, name, fn); 889 | }; 890 | 891 | Assertion.overwriteMethod = function (name, fn) { 892 | util.overwriteMethod(this.prototype, name, fn); 893 | }; 894 | 895 | Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { 896 | util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); 897 | }; 898 | 899 | /*! 900 | * ### .assert(expression, message, negateMessage, expected, actual) 901 | * 902 | * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. 903 | * 904 | * @name assert 905 | * @param {Philosophical} expression to be tested 906 | * @param {String or Function} message or function that returns message to display if fails 907 | * @param {String or Function} negatedMessage or function that returns negatedMessage to display if negated expression fails 908 | * @param {Mixed} expected value (remember to check for negation) 909 | * @param {Mixed} actual (optional) will default to `this.obj` 910 | * @api private 911 | */ 912 | 913 | Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { 914 | var ok = util.test(this, arguments); 915 | if (true !== showDiff) showDiff = false; 916 | if (true !== config.showDiff) showDiff = false; 917 | 918 | if (!ok) { 919 | var msg = util.getMessage(this, arguments) 920 | , actual = util.getActual(this, arguments); 921 | throw new AssertionError(msg, { 922 | actual: actual 923 | , expected: expected 924 | , showDiff: showDiff 925 | }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); 926 | } 927 | }; 928 | 929 | /*! 930 | * ### ._obj 931 | * 932 | * Quick reference to stored `actual` value for plugin developers. 933 | * 934 | * @api private 935 | */ 936 | 937 | Object.defineProperty(Assertion.prototype, '_obj', 938 | { get: function () { 939 | return flag(this, 'object'); 940 | } 941 | , set: function (val) { 942 | flag(this, 'object', val); 943 | } 944 | }); 945 | }; 946 | 947 | }); 948 | require.register("chai/lib/chai/config.js", function(exports, require, module){ 949 | module.exports = { 950 | 951 | /** 952 | * ### config.includeStack 953 | * 954 | * User configurable property, influences whether stack trace 955 | * is included in Assertion error message. Default of false 956 | * suppresses stack trace in the error message. 957 | * 958 | * chai.config.includeStack = true; // enable stack on error 959 | * 960 | * @param {Boolean} 961 | * @api public 962 | */ 963 | 964 | includeStack: false, 965 | 966 | /** 967 | * ### config.showDiff 968 | * 969 | * User configurable property, influences whether or not 970 | * the `showDiff` flag should be included in the thrown 971 | * AssertionErrors. `false` will always be `false`; `true` 972 | * will be true when the assertion has requested a diff 973 | * be shown. 974 | * 975 | * @param {Boolean} 976 | * @api public 977 | */ 978 | 979 | showDiff: true, 980 | 981 | /** 982 | * ### config.truncateThreshold 983 | * 984 | * User configurable property, sets length threshold for actual and 985 | * expected values in assertion errors. If this threshold is exceeded, 986 | * the value is truncated. 987 | * 988 | * Set it to zero if you want to disable truncating altogether. 989 | * 990 | * chai.config.truncateThreshold = 0; // disable truncating 991 | * 992 | * @param {Number} 993 | * @api public 994 | */ 995 | 996 | truncateThreshold: 40 997 | 998 | }; 999 | 1000 | }); 1001 | require.register("chai/lib/chai/core/assertions.js", function(exports, require, module){ 1002 | /*! 1003 | * chai 1004 | * http://chaijs.com 1005 | * Copyright(c) 2011-2014 Jake Luer 1006 | * MIT Licensed 1007 | */ 1008 | 1009 | module.exports = function (chai, _) { 1010 | var Assertion = chai.Assertion 1011 | , toString = Object.prototype.toString 1012 | , flag = _.flag; 1013 | 1014 | /** 1015 | * ### Language Chains 1016 | * 1017 | * The following are provided as chainable getters to 1018 | * improve the readability of your assertions. They 1019 | * do not provide testing capabilities unless they 1020 | * have been overwritten by a plugin. 1021 | * 1022 | * **Chains** 1023 | * 1024 | * - to 1025 | * - be 1026 | * - been 1027 | * - is 1028 | * - that 1029 | * - and 1030 | * - has 1031 | * - have 1032 | * - with 1033 | * - at 1034 | * - of 1035 | * - same 1036 | * 1037 | * @name language chains 1038 | * @api public 1039 | */ 1040 | 1041 | [ 'to', 'be', 'been' 1042 | , 'is', 'and', 'has', 'have' 1043 | , 'with', 'that', 'at' 1044 | , 'of', 'same' ].forEach(function (chain) { 1045 | Assertion.addProperty(chain, function () { 1046 | return this; 1047 | }); 1048 | }); 1049 | 1050 | /** 1051 | * ### .not 1052 | * 1053 | * Negates any of assertions following in the chain. 1054 | * 1055 | * expect(foo).to.not.equal('bar'); 1056 | * expect(goodFn).to.not.throw(Error); 1057 | * expect({ foo: 'baz' }).to.have.property('foo') 1058 | * .and.not.equal('bar'); 1059 | * 1060 | * @name not 1061 | * @api public 1062 | */ 1063 | 1064 | Assertion.addProperty('not', function () { 1065 | flag(this, 'negate', true); 1066 | }); 1067 | 1068 | /** 1069 | * ### .deep 1070 | * 1071 | * Sets the `deep` flag, later used by the `equal` and 1072 | * `property` assertions. 1073 | * 1074 | * expect(foo).to.deep.equal({ bar: 'baz' }); 1075 | * expect({ foo: { bar: { baz: 'quux' } } }) 1076 | * .to.have.deep.property('foo.bar.baz', 'quux'); 1077 | * 1078 | * @name deep 1079 | * @api public 1080 | */ 1081 | 1082 | Assertion.addProperty('deep', function () { 1083 | flag(this, 'deep', true); 1084 | }); 1085 | 1086 | /** 1087 | * ### .a(type) 1088 | * 1089 | * The `a` and `an` assertions are aliases that can be 1090 | * used either as language chains or to assert a value's 1091 | * type. 1092 | * 1093 | * // typeof 1094 | * expect('test').to.be.a('string'); 1095 | * expect({ foo: 'bar' }).to.be.an('object'); 1096 | * expect(null).to.be.a('null'); 1097 | * expect(undefined).to.be.an('undefined'); 1098 | * 1099 | * // language chain 1100 | * expect(foo).to.be.an.instanceof(Foo); 1101 | * 1102 | * @name a 1103 | * @alias an 1104 | * @param {String} type 1105 | * @param {String} message _optional_ 1106 | * @api public 1107 | */ 1108 | 1109 | function an (type, msg) { 1110 | if (msg) flag(this, 'message', msg); 1111 | type = type.toLowerCase(); 1112 | var obj = flag(this, 'object') 1113 | , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; 1114 | 1115 | this.assert( 1116 | type === _.type(obj) 1117 | , 'expected #{this} to be ' + article + type 1118 | , 'expected #{this} not to be ' + article + type 1119 | ); 1120 | } 1121 | 1122 | Assertion.addChainableMethod('an', an); 1123 | Assertion.addChainableMethod('a', an); 1124 | 1125 | /** 1126 | * ### .include(value) 1127 | * 1128 | * The `include` and `contain` assertions can be used as either property 1129 | * based language chains or as methods to assert the inclusion of an object 1130 | * in an array or a substring in a string. When used as language chains, 1131 | * they toggle the `contain` flag for the `keys` assertion. 1132 | * 1133 | * expect([1,2,3]).to.include(2); 1134 | * expect('foobar').to.contain('foo'); 1135 | * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); 1136 | * 1137 | * @name include 1138 | * @alias contain 1139 | * @param {Object|String|Number} obj 1140 | * @param {String} message _optional_ 1141 | * @api public 1142 | */ 1143 | 1144 | function includeChainingBehavior () { 1145 | flag(this, 'contains', true); 1146 | } 1147 | 1148 | function include (val, msg) { 1149 | if (msg) flag(this, 'message', msg); 1150 | var obj = flag(this, 'object'); 1151 | var expected = false; 1152 | if (_.type(obj) === 'array' && _.type(val) === 'object') { 1153 | for (var i in obj) { 1154 | if (_.eql(obj[i], val)) { 1155 | expected = true; 1156 | break; 1157 | } 1158 | } 1159 | } else if (_.type(val) === 'object') { 1160 | if (!flag(this, 'negate')) { 1161 | for (var k in val) new Assertion(obj).property(k, val[k]); 1162 | return; 1163 | } 1164 | var subset = {} 1165 | for (var k in val) subset[k] = obj[k] 1166 | expected = _.eql(subset, val); 1167 | } else { 1168 | expected = obj && ~obj.indexOf(val) 1169 | } 1170 | this.assert( 1171 | expected 1172 | , 'expected #{this} to include ' + _.inspect(val) 1173 | , 'expected #{this} to not include ' + _.inspect(val)); 1174 | } 1175 | 1176 | Assertion.addChainableMethod('include', include, includeChainingBehavior); 1177 | Assertion.addChainableMethod('contain', include, includeChainingBehavior); 1178 | 1179 | /** 1180 | * ### .ok 1181 | * 1182 | * Asserts that the target is truthy. 1183 | * 1184 | * expect('everthing').to.be.ok; 1185 | * expect(1).to.be.ok; 1186 | * expect(false).to.not.be.ok; 1187 | * expect(undefined).to.not.be.ok; 1188 | * expect(null).to.not.be.ok; 1189 | * 1190 | * @name ok 1191 | * @api public 1192 | */ 1193 | 1194 | Assertion.addProperty('ok', function () { 1195 | this.assert( 1196 | flag(this, 'object') 1197 | , 'expected #{this} to be truthy' 1198 | , 'expected #{this} to be falsy'); 1199 | }); 1200 | 1201 | /** 1202 | * ### .true 1203 | * 1204 | * Asserts that the target is `true`. 1205 | * 1206 | * expect(true).to.be.true; 1207 | * expect(1).to.not.be.true; 1208 | * 1209 | * @name true 1210 | * @api public 1211 | */ 1212 | 1213 | Assertion.addProperty('true', function () { 1214 | this.assert( 1215 | true === flag(this, 'object') 1216 | , 'expected #{this} to be true' 1217 | , 'expected #{this} to be false' 1218 | , this.negate ? false : true 1219 | ); 1220 | }); 1221 | 1222 | /** 1223 | * ### .false 1224 | * 1225 | * Asserts that the target is `false`. 1226 | * 1227 | * expect(false).to.be.false; 1228 | * expect(0).to.not.be.false; 1229 | * 1230 | * @name false 1231 | * @api public 1232 | */ 1233 | 1234 | Assertion.addProperty('false', function () { 1235 | this.assert( 1236 | false === flag(this, 'object') 1237 | , 'expected #{this} to be false' 1238 | , 'expected #{this} to be true' 1239 | , this.negate ? true : false 1240 | ); 1241 | }); 1242 | 1243 | /** 1244 | * ### .null 1245 | * 1246 | * Asserts that the target is `null`. 1247 | * 1248 | * expect(null).to.be.null; 1249 | * expect(undefined).not.to.be.null; 1250 | * 1251 | * @name null 1252 | * @api public 1253 | */ 1254 | 1255 | Assertion.addProperty('null', function () { 1256 | this.assert( 1257 | null === flag(this, 'object') 1258 | , 'expected #{this} to be null' 1259 | , 'expected #{this} not to be null' 1260 | ); 1261 | }); 1262 | 1263 | /** 1264 | * ### .undefined 1265 | * 1266 | * Asserts that the target is `undefined`. 1267 | * 1268 | * expect(undefined).to.be.undefined; 1269 | * expect(null).to.not.be.undefined; 1270 | * 1271 | * @name undefined 1272 | * @api public 1273 | */ 1274 | 1275 | Assertion.addProperty('undefined', function () { 1276 | this.assert( 1277 | undefined === flag(this, 'object') 1278 | , 'expected #{this} to be undefined' 1279 | , 'expected #{this} not to be undefined' 1280 | ); 1281 | }); 1282 | 1283 | /** 1284 | * ### .exist 1285 | * 1286 | * Asserts that the target is neither `null` nor `undefined`. 1287 | * 1288 | * var foo = 'hi' 1289 | * , bar = null 1290 | * , baz; 1291 | * 1292 | * expect(foo).to.exist; 1293 | * expect(bar).to.not.exist; 1294 | * expect(baz).to.not.exist; 1295 | * 1296 | * @name exist 1297 | * @api public 1298 | */ 1299 | 1300 | Assertion.addProperty('exist', function () { 1301 | this.assert( 1302 | null != flag(this, 'object') 1303 | , 'expected #{this} to exist' 1304 | , 'expected #{this} to not exist' 1305 | ); 1306 | }); 1307 | 1308 | 1309 | /** 1310 | * ### .empty 1311 | * 1312 | * Asserts that the target's length is `0`. For arrays, it checks 1313 | * the `length` property. For objects, it gets the count of 1314 | * enumerable keys. 1315 | * 1316 | * expect([]).to.be.empty; 1317 | * expect('').to.be.empty; 1318 | * expect({}).to.be.empty; 1319 | * 1320 | * @name empty 1321 | * @api public 1322 | */ 1323 | 1324 | Assertion.addProperty('empty', function () { 1325 | var obj = flag(this, 'object') 1326 | , expected = obj; 1327 | 1328 | if (Array.isArray(obj) || 'string' === typeof object) { 1329 | expected = obj.length; 1330 | } else if (typeof obj === 'object') { 1331 | expected = Object.keys(obj).length; 1332 | } 1333 | 1334 | this.assert( 1335 | !expected 1336 | , 'expected #{this} to be empty' 1337 | , 'expected #{this} not to be empty' 1338 | ); 1339 | }); 1340 | 1341 | /** 1342 | * ### .arguments 1343 | * 1344 | * Asserts that the target is an arguments object. 1345 | * 1346 | * function test () { 1347 | * expect(arguments).to.be.arguments; 1348 | * } 1349 | * 1350 | * @name arguments 1351 | * @alias Arguments 1352 | * @api public 1353 | */ 1354 | 1355 | function checkArguments () { 1356 | var obj = flag(this, 'object') 1357 | , type = Object.prototype.toString.call(obj); 1358 | this.assert( 1359 | '[object Arguments]' === type 1360 | , 'expected #{this} to be arguments but got ' + type 1361 | , 'expected #{this} to not be arguments' 1362 | ); 1363 | } 1364 | 1365 | Assertion.addProperty('arguments', checkArguments); 1366 | Assertion.addProperty('Arguments', checkArguments); 1367 | 1368 | /** 1369 | * ### .equal(value) 1370 | * 1371 | * Asserts that the target is strictly equal (`===`) to `value`. 1372 | * Alternately, if the `deep` flag is set, asserts that 1373 | * the target is deeply equal to `value`. 1374 | * 1375 | * expect('hello').to.equal('hello'); 1376 | * expect(42).to.equal(42); 1377 | * expect(1).to.not.equal(true); 1378 | * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); 1379 | * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); 1380 | * 1381 | * @name equal 1382 | * @alias equals 1383 | * @alias eq 1384 | * @alias deep.equal 1385 | * @param {Mixed} value 1386 | * @param {String} message _optional_ 1387 | * @api public 1388 | */ 1389 | 1390 | function assertEqual (val, msg) { 1391 | if (msg) flag(this, 'message', msg); 1392 | var obj = flag(this, 'object'); 1393 | if (flag(this, 'deep')) { 1394 | return this.eql(val); 1395 | } else { 1396 | this.assert( 1397 | val === obj 1398 | , 'expected #{this} to equal #{exp}' 1399 | , 'expected #{this} to not equal #{exp}' 1400 | , val 1401 | , this._obj 1402 | , true 1403 | ); 1404 | } 1405 | } 1406 | 1407 | Assertion.addMethod('equal', assertEqual); 1408 | Assertion.addMethod('equals', assertEqual); 1409 | Assertion.addMethod('eq', assertEqual); 1410 | 1411 | /** 1412 | * ### .eql(value) 1413 | * 1414 | * Asserts that the target is deeply equal to `value`. 1415 | * 1416 | * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); 1417 | * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); 1418 | * 1419 | * @name eql 1420 | * @alias eqls 1421 | * @param {Mixed} value 1422 | * @param {String} message _optional_ 1423 | * @api public 1424 | */ 1425 | 1426 | function assertEql(obj, msg) { 1427 | if (msg) flag(this, 'message', msg); 1428 | this.assert( 1429 | _.eql(obj, flag(this, 'object')) 1430 | , 'expected #{this} to deeply equal #{exp}' 1431 | , 'expected #{this} to not deeply equal #{exp}' 1432 | , obj 1433 | , this._obj 1434 | , true 1435 | ); 1436 | } 1437 | 1438 | Assertion.addMethod('eql', assertEql); 1439 | Assertion.addMethod('eqls', assertEql); 1440 | 1441 | /** 1442 | * ### .above(value) 1443 | * 1444 | * Asserts that the target is greater than `value`. 1445 | * 1446 | * expect(10).to.be.above(5); 1447 | * 1448 | * Can also be used in conjunction with `length` to 1449 | * assert a minimum length. The benefit being a 1450 | * more informative error message than if the length 1451 | * was supplied directly. 1452 | * 1453 | * expect('foo').to.have.length.above(2); 1454 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 1455 | * 1456 | * @name above 1457 | * @alias gt 1458 | * @alias greaterThan 1459 | * @param {Number} value 1460 | * @param {String} message _optional_ 1461 | * @api public 1462 | */ 1463 | 1464 | function assertAbove (n, msg) { 1465 | if (msg) flag(this, 'message', msg); 1466 | var obj = flag(this, 'object'); 1467 | if (flag(this, 'doLength')) { 1468 | new Assertion(obj, msg).to.have.property('length'); 1469 | var len = obj.length; 1470 | this.assert( 1471 | len > n 1472 | , 'expected #{this} to have a length above #{exp} but got #{act}' 1473 | , 'expected #{this} to not have a length above #{exp}' 1474 | , n 1475 | , len 1476 | ); 1477 | } else { 1478 | this.assert( 1479 | obj > n 1480 | , 'expected #{this} to be above ' + n 1481 | , 'expected #{this} to be at most ' + n 1482 | ); 1483 | } 1484 | } 1485 | 1486 | Assertion.addMethod('above', assertAbove); 1487 | Assertion.addMethod('gt', assertAbove); 1488 | Assertion.addMethod('greaterThan', assertAbove); 1489 | 1490 | /** 1491 | * ### .least(value) 1492 | * 1493 | * Asserts that the target is greater than or equal to `value`. 1494 | * 1495 | * expect(10).to.be.at.least(10); 1496 | * 1497 | * Can also be used in conjunction with `length` to 1498 | * assert a minimum length. The benefit being a 1499 | * more informative error message than if the length 1500 | * was supplied directly. 1501 | * 1502 | * expect('foo').to.have.length.of.at.least(2); 1503 | * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); 1504 | * 1505 | * @name least 1506 | * @alias gte 1507 | * @param {Number} value 1508 | * @param {String} message _optional_ 1509 | * @api public 1510 | */ 1511 | 1512 | function assertLeast (n, msg) { 1513 | if (msg) flag(this, 'message', msg); 1514 | var obj = flag(this, 'object'); 1515 | if (flag(this, 'doLength')) { 1516 | new Assertion(obj, msg).to.have.property('length'); 1517 | var len = obj.length; 1518 | this.assert( 1519 | len >= n 1520 | , 'expected #{this} to have a length at least #{exp} but got #{act}' 1521 | , 'expected #{this} to have a length below #{exp}' 1522 | , n 1523 | , len 1524 | ); 1525 | } else { 1526 | this.assert( 1527 | obj >= n 1528 | , 'expected #{this} to be at least ' + n 1529 | , 'expected #{this} to be below ' + n 1530 | ); 1531 | } 1532 | } 1533 | 1534 | Assertion.addMethod('least', assertLeast); 1535 | Assertion.addMethod('gte', assertLeast); 1536 | 1537 | /** 1538 | * ### .below(value) 1539 | * 1540 | * Asserts that the target is less than `value`. 1541 | * 1542 | * expect(5).to.be.below(10); 1543 | * 1544 | * Can also be used in conjunction with `length` to 1545 | * assert a maximum length. The benefit being a 1546 | * more informative error message than if the length 1547 | * was supplied directly. 1548 | * 1549 | * expect('foo').to.have.length.below(4); 1550 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 1551 | * 1552 | * @name below 1553 | * @alias lt 1554 | * @alias lessThan 1555 | * @param {Number} value 1556 | * @param {String} message _optional_ 1557 | * @api public 1558 | */ 1559 | 1560 | function assertBelow (n, msg) { 1561 | if (msg) flag(this, 'message', msg); 1562 | var obj = flag(this, 'object'); 1563 | if (flag(this, 'doLength')) { 1564 | new Assertion(obj, msg).to.have.property('length'); 1565 | var len = obj.length; 1566 | this.assert( 1567 | len < n 1568 | , 'expected #{this} to have a length below #{exp} but got #{act}' 1569 | , 'expected #{this} to not have a length below #{exp}' 1570 | , n 1571 | , len 1572 | ); 1573 | } else { 1574 | this.assert( 1575 | obj < n 1576 | , 'expected #{this} to be below ' + n 1577 | , 'expected #{this} to be at least ' + n 1578 | ); 1579 | } 1580 | } 1581 | 1582 | Assertion.addMethod('below', assertBelow); 1583 | Assertion.addMethod('lt', assertBelow); 1584 | Assertion.addMethod('lessThan', assertBelow); 1585 | 1586 | /** 1587 | * ### .most(value) 1588 | * 1589 | * Asserts that the target is less than or equal to `value`. 1590 | * 1591 | * expect(5).to.be.at.most(5); 1592 | * 1593 | * Can also be used in conjunction with `length` to 1594 | * assert a maximum length. The benefit being a 1595 | * more informative error message than if the length 1596 | * was supplied directly. 1597 | * 1598 | * expect('foo').to.have.length.of.at.most(4); 1599 | * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); 1600 | * 1601 | * @name most 1602 | * @alias lte 1603 | * @param {Number} value 1604 | * @param {String} message _optional_ 1605 | * @api public 1606 | */ 1607 | 1608 | function assertMost (n, msg) { 1609 | if (msg) flag(this, 'message', msg); 1610 | var obj = flag(this, 'object'); 1611 | if (flag(this, 'doLength')) { 1612 | new Assertion(obj, msg).to.have.property('length'); 1613 | var len = obj.length; 1614 | this.assert( 1615 | len <= n 1616 | , 'expected #{this} to have a length at most #{exp} but got #{act}' 1617 | , 'expected #{this} to have a length above #{exp}' 1618 | , n 1619 | , len 1620 | ); 1621 | } else { 1622 | this.assert( 1623 | obj <= n 1624 | , 'expected #{this} to be at most ' + n 1625 | , 'expected #{this} to be above ' + n 1626 | ); 1627 | } 1628 | } 1629 | 1630 | Assertion.addMethod('most', assertMost); 1631 | Assertion.addMethod('lte', assertMost); 1632 | 1633 | /** 1634 | * ### .within(start, finish) 1635 | * 1636 | * Asserts that the target is within a range. 1637 | * 1638 | * expect(7).to.be.within(5,10); 1639 | * 1640 | * Can also be used in conjunction with `length` to 1641 | * assert a length range. The benefit being a 1642 | * more informative error message than if the length 1643 | * was supplied directly. 1644 | * 1645 | * expect('foo').to.have.length.within(2,4); 1646 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1647 | * 1648 | * @name within 1649 | * @param {Number} start lowerbound inclusive 1650 | * @param {Number} finish upperbound inclusive 1651 | * @param {String} message _optional_ 1652 | * @api public 1653 | */ 1654 | 1655 | Assertion.addMethod('within', function (start, finish, msg) { 1656 | if (msg) flag(this, 'message', msg); 1657 | var obj = flag(this, 'object') 1658 | , range = start + '..' + finish; 1659 | if (flag(this, 'doLength')) { 1660 | new Assertion(obj, msg).to.have.property('length'); 1661 | var len = obj.length; 1662 | this.assert( 1663 | len >= start && len <= finish 1664 | , 'expected #{this} to have a length within ' + range 1665 | , 'expected #{this} to not have a length within ' + range 1666 | ); 1667 | } else { 1668 | this.assert( 1669 | obj >= start && obj <= finish 1670 | , 'expected #{this} to be within ' + range 1671 | , 'expected #{this} to not be within ' + range 1672 | ); 1673 | } 1674 | }); 1675 | 1676 | /** 1677 | * ### .instanceof(constructor) 1678 | * 1679 | * Asserts that the target is an instance of `constructor`. 1680 | * 1681 | * var Tea = function (name) { this.name = name; } 1682 | * , Chai = new Tea('chai'); 1683 | * 1684 | * expect(Chai).to.be.an.instanceof(Tea); 1685 | * expect([ 1, 2, 3 ]).to.be.instanceof(Array); 1686 | * 1687 | * @name instanceof 1688 | * @param {Constructor} constructor 1689 | * @param {String} message _optional_ 1690 | * @alias instanceOf 1691 | * @api public 1692 | */ 1693 | 1694 | function assertInstanceOf (constructor, msg) { 1695 | if (msg) flag(this, 'message', msg); 1696 | var name = _.getName(constructor); 1697 | this.assert( 1698 | flag(this, 'object') instanceof constructor 1699 | , 'expected #{this} to be an instance of ' + name 1700 | , 'expected #{this} to not be an instance of ' + name 1701 | ); 1702 | }; 1703 | 1704 | Assertion.addMethod('instanceof', assertInstanceOf); 1705 | Assertion.addMethod('instanceOf', assertInstanceOf); 1706 | 1707 | /** 1708 | * ### .property(name, [value]) 1709 | * 1710 | * Asserts that the target has a property `name`, optionally asserting that 1711 | * the value of that property is strictly equal to `value`. 1712 | * If the `deep` flag is set, you can use dot- and bracket-notation for deep 1713 | * references into objects and arrays. 1714 | * 1715 | * // simple referencing 1716 | * var obj = { foo: 'bar' }; 1717 | * expect(obj).to.have.property('foo'); 1718 | * expect(obj).to.have.property('foo', 'bar'); 1719 | * 1720 | * // deep referencing 1721 | * var deepObj = { 1722 | * green: { tea: 'matcha' } 1723 | * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] 1724 | * }; 1725 | 1726 | * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); 1727 | * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); 1728 | * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); 1729 | * 1730 | * You can also use an array as the starting point of a `deep.property` 1731 | * assertion, or traverse nested arrays. 1732 | * 1733 | * var arr = [ 1734 | * [ 'chai', 'matcha', 'konacha' ] 1735 | * , [ { tea: 'chai' } 1736 | * , { tea: 'matcha' } 1737 | * , { tea: 'konacha' } ] 1738 | * ]; 1739 | * 1740 | * expect(arr).to.have.deep.property('[0][1]', 'matcha'); 1741 | * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); 1742 | * 1743 | * Furthermore, `property` changes the subject of the assertion 1744 | * to be the value of that property from the original object. This 1745 | * permits for further chainable assertions on that property. 1746 | * 1747 | * expect(obj).to.have.property('foo') 1748 | * .that.is.a('string'); 1749 | * expect(deepObj).to.have.property('green') 1750 | * .that.is.an('object') 1751 | * .that.deep.equals({ tea: 'matcha' }); 1752 | * expect(deepObj).to.have.property('teas') 1753 | * .that.is.an('array') 1754 | * .with.deep.property('[2]') 1755 | * .that.deep.equals({ tea: 'konacha' }); 1756 | * 1757 | * @name property 1758 | * @alias deep.property 1759 | * @param {String} name 1760 | * @param {Mixed} value (optional) 1761 | * @param {String} message _optional_ 1762 | * @returns value of property for chaining 1763 | * @api public 1764 | */ 1765 | 1766 | Assertion.addMethod('property', function (name, val, msg) { 1767 | if (msg) flag(this, 'message', msg); 1768 | 1769 | var descriptor = flag(this, 'deep') ? 'deep property ' : 'property ' 1770 | , negate = flag(this, 'negate') 1771 | , obj = flag(this, 'object') 1772 | , value = flag(this, 'deep') 1773 | ? _.getPathValue(name, obj) 1774 | : obj[name]; 1775 | 1776 | if (negate && undefined !== val) { 1777 | if (undefined === value) { 1778 | msg = (msg != null) ? msg + ': ' : ''; 1779 | throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); 1780 | } 1781 | } else { 1782 | this.assert( 1783 | undefined !== value 1784 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) 1785 | , 'expected #{this} to not have ' + descriptor + _.inspect(name)); 1786 | } 1787 | 1788 | if (undefined !== val) { 1789 | this.assert( 1790 | val === value 1791 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' 1792 | , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' 1793 | , val 1794 | , value 1795 | ); 1796 | } 1797 | 1798 | flag(this, 'object', value); 1799 | }); 1800 | 1801 | 1802 | /** 1803 | * ### .ownProperty(name) 1804 | * 1805 | * Asserts that the target has an own property `name`. 1806 | * 1807 | * expect('test').to.have.ownProperty('length'); 1808 | * 1809 | * @name ownProperty 1810 | * @alias haveOwnProperty 1811 | * @param {String} name 1812 | * @param {String} message _optional_ 1813 | * @api public 1814 | */ 1815 | 1816 | function assertOwnProperty (name, msg) { 1817 | if (msg) flag(this, 'message', msg); 1818 | var obj = flag(this, 'object'); 1819 | this.assert( 1820 | obj.hasOwnProperty(name) 1821 | , 'expected #{this} to have own property ' + _.inspect(name) 1822 | , 'expected #{this} to not have own property ' + _.inspect(name) 1823 | ); 1824 | } 1825 | 1826 | Assertion.addMethod('ownProperty', assertOwnProperty); 1827 | Assertion.addMethod('haveOwnProperty', assertOwnProperty); 1828 | 1829 | /** 1830 | * ### .length(value) 1831 | * 1832 | * Asserts that the target's `length` property has 1833 | * the expected value. 1834 | * 1835 | * expect([ 1, 2, 3]).to.have.length(3); 1836 | * expect('foobar').to.have.length(6); 1837 | * 1838 | * Can also be used as a chain precursor to a value 1839 | * comparison for the length property. 1840 | * 1841 | * expect('foo').to.have.length.above(2); 1842 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 1843 | * expect('foo').to.have.length.below(4); 1844 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 1845 | * expect('foo').to.have.length.within(2,4); 1846 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1847 | * 1848 | * @name length 1849 | * @alias lengthOf 1850 | * @param {Number} length 1851 | * @param {String} message _optional_ 1852 | * @api public 1853 | */ 1854 | 1855 | function assertLengthChain () { 1856 | flag(this, 'doLength', true); 1857 | } 1858 | 1859 | function assertLength (n, msg) { 1860 | if (msg) flag(this, 'message', msg); 1861 | var obj = flag(this, 'object'); 1862 | new Assertion(obj, msg).to.have.property('length'); 1863 | var len = obj.length; 1864 | 1865 | this.assert( 1866 | len == n 1867 | , 'expected #{this} to have a length of #{exp} but got #{act}' 1868 | , 'expected #{this} to not have a length of #{act}' 1869 | , n 1870 | , len 1871 | ); 1872 | } 1873 | 1874 | Assertion.addChainableMethod('length', assertLength, assertLengthChain); 1875 | Assertion.addMethod('lengthOf', assertLength); 1876 | 1877 | /** 1878 | * ### .match(regexp) 1879 | * 1880 | * Asserts that the target matches a regular expression. 1881 | * 1882 | * expect('foobar').to.match(/^foo/); 1883 | * 1884 | * @name match 1885 | * @param {RegExp} RegularExpression 1886 | * @param {String} message _optional_ 1887 | * @api public 1888 | */ 1889 | 1890 | Assertion.addMethod('match', function (re, msg) { 1891 | if (msg) flag(this, 'message', msg); 1892 | var obj = flag(this, 'object'); 1893 | this.assert( 1894 | re.exec(obj) 1895 | , 'expected #{this} to match ' + re 1896 | , 'expected #{this} not to match ' + re 1897 | ); 1898 | }); 1899 | 1900 | /** 1901 | * ### .string(string) 1902 | * 1903 | * Asserts that the string target contains another string. 1904 | * 1905 | * expect('foobar').to.have.string('bar'); 1906 | * 1907 | * @name string 1908 | * @param {String} string 1909 | * @param {String} message _optional_ 1910 | * @api public 1911 | */ 1912 | 1913 | Assertion.addMethod('string', function (str, msg) { 1914 | if (msg) flag(this, 'message', msg); 1915 | var obj = flag(this, 'object'); 1916 | new Assertion(obj, msg).is.a('string'); 1917 | 1918 | this.assert( 1919 | ~obj.indexOf(str) 1920 | , 'expected #{this} to contain ' + _.inspect(str) 1921 | , 'expected #{this} to not contain ' + _.inspect(str) 1922 | ); 1923 | }); 1924 | 1925 | 1926 | /** 1927 | * ### .keys(key1, [key2], [...]) 1928 | * 1929 | * Asserts that the target has exactly the given keys, or 1930 | * asserts the inclusion of some keys when using the 1931 | * `include` or `contain` modifiers. 1932 | * 1933 | * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']); 1934 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar'); 1935 | * 1936 | * @name keys 1937 | * @alias key 1938 | * @param {String...|Array} keys 1939 | * @api public 1940 | */ 1941 | 1942 | function assertKeys (keys) { 1943 | var obj = flag(this, 'object') 1944 | , str 1945 | , ok = true; 1946 | 1947 | keys = keys instanceof Array 1948 | ? keys 1949 | : Array.prototype.slice.call(arguments); 1950 | 1951 | if (!keys.length) throw new Error('keys required'); 1952 | 1953 | var actual = Object.keys(obj) 1954 | , expected = keys 1955 | , len = keys.length; 1956 | 1957 | // Inclusion 1958 | ok = keys.every(function(key){ 1959 | return ~actual.indexOf(key); 1960 | }); 1961 | 1962 | // Strict 1963 | if (!flag(this, 'negate') && !flag(this, 'contains')) { 1964 | ok = ok && keys.length == actual.length; 1965 | } 1966 | 1967 | // Key string 1968 | if (len > 1) { 1969 | keys = keys.map(function(key){ 1970 | return _.inspect(key); 1971 | }); 1972 | var last = keys.pop(); 1973 | str = keys.join(', ') + ', and ' + last; 1974 | } else { 1975 | str = _.inspect(keys[0]); 1976 | } 1977 | 1978 | // Form 1979 | str = (len > 1 ? 'keys ' : 'key ') + str; 1980 | 1981 | // Have / include 1982 | str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; 1983 | 1984 | // Assertion 1985 | this.assert( 1986 | ok 1987 | , 'expected #{this} to ' + str 1988 | , 'expected #{this} to not ' + str 1989 | , expected.sort() 1990 | , actual.sort() 1991 | , true 1992 | ); 1993 | } 1994 | 1995 | Assertion.addMethod('keys', assertKeys); 1996 | Assertion.addMethod('key', assertKeys); 1997 | 1998 | /** 1999 | * ### .throw(constructor) 2000 | * 2001 | * Asserts that the function target will throw a specific error, or specific type of error 2002 | * (as determined using `instanceof`), optionally with a RegExp or string inclusion test 2003 | * for the error's message. 2004 | * 2005 | * var err = new ReferenceError('This is a bad function.'); 2006 | * var fn = function () { throw err; } 2007 | * expect(fn).to.throw(ReferenceError); 2008 | * expect(fn).to.throw(Error); 2009 | * expect(fn).to.throw(/bad function/); 2010 | * expect(fn).to.not.throw('good function'); 2011 | * expect(fn).to.throw(ReferenceError, /bad function/); 2012 | * expect(fn).to.throw(err); 2013 | * expect(fn).to.not.throw(new RangeError('Out of range.')); 2014 | * 2015 | * Please note that when a throw expectation is negated, it will check each 2016 | * parameter independently, starting with error constructor type. The appropriate way 2017 | * to check for the existence of a type of error but for a message that does not match 2018 | * is to use `and`. 2019 | * 2020 | * expect(fn).to.throw(ReferenceError) 2021 | * .and.not.throw(/good function/); 2022 | * 2023 | * @name throw 2024 | * @alias throws 2025 | * @alias Throw 2026 | * @param {ErrorConstructor} constructor 2027 | * @param {String|RegExp} expected error message 2028 | * @param {String} message _optional_ 2029 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 2030 | * @returns error for chaining (null if no error) 2031 | * @api public 2032 | */ 2033 | 2034 | function assertThrows (constructor, errMsg, msg) { 2035 | if (msg) flag(this, 'message', msg); 2036 | var obj = flag(this, 'object'); 2037 | new Assertion(obj, msg).is.a('function'); 2038 | 2039 | var thrown = false 2040 | , desiredError = null 2041 | , name = null 2042 | , thrownError = null; 2043 | 2044 | if (arguments.length === 0) { 2045 | errMsg = null; 2046 | constructor = null; 2047 | } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { 2048 | errMsg = constructor; 2049 | constructor = null; 2050 | } else if (constructor && constructor instanceof Error) { 2051 | desiredError = constructor; 2052 | constructor = null; 2053 | errMsg = null; 2054 | } else if (typeof constructor === 'function') { 2055 | name = constructor.prototype.name || constructor.name; 2056 | if (name === 'Error' && constructor !== Error) { 2057 | name = (new constructor()).name; 2058 | } 2059 | } else { 2060 | constructor = null; 2061 | } 2062 | 2063 | try { 2064 | obj(); 2065 | } catch (err) { 2066 | // first, check desired error 2067 | if (desiredError) { 2068 | this.assert( 2069 | err === desiredError 2070 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 2071 | , 'expected #{this} to not throw #{exp}' 2072 | , (desiredError instanceof Error ? desiredError.toString() : desiredError) 2073 | , (err instanceof Error ? err.toString() : err) 2074 | ); 2075 | 2076 | flag(this, 'object', err); 2077 | return this; 2078 | } 2079 | 2080 | // next, check constructor 2081 | if (constructor) { 2082 | this.assert( 2083 | err instanceof constructor 2084 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 2085 | , 'expected #{this} to not throw #{exp} but #{act} was thrown' 2086 | , name 2087 | , (err instanceof Error ? err.toString() : err) 2088 | ); 2089 | 2090 | if (!errMsg) { 2091 | flag(this, 'object', err); 2092 | return this; 2093 | } 2094 | } 2095 | 2096 | // next, check message 2097 | var message = 'object' === _.type(err) && "message" in err 2098 | ? err.message 2099 | : '' + err; 2100 | 2101 | if ((message != null) && errMsg && errMsg instanceof RegExp) { 2102 | this.assert( 2103 | errMsg.exec(message) 2104 | , 'expected #{this} to throw error matching #{exp} but got #{act}' 2105 | , 'expected #{this} to throw error not matching #{exp}' 2106 | , errMsg 2107 | , message 2108 | ); 2109 | 2110 | flag(this, 'object', err); 2111 | return this; 2112 | } else if ((message != null) && errMsg && 'string' === typeof errMsg) { 2113 | this.assert( 2114 | ~message.indexOf(errMsg) 2115 | , 'expected #{this} to throw error including #{exp} but got #{act}' 2116 | , 'expected #{this} to throw error not including #{act}' 2117 | , errMsg 2118 | , message 2119 | ); 2120 | 2121 | flag(this, 'object', err); 2122 | return this; 2123 | } else { 2124 | thrown = true; 2125 | thrownError = err; 2126 | } 2127 | } 2128 | 2129 | var actuallyGot = '' 2130 | , expectedThrown = name !== null 2131 | ? name 2132 | : desiredError 2133 | ? '#{exp}' //_.inspect(desiredError) 2134 | : 'an error'; 2135 | 2136 | if (thrown) { 2137 | actuallyGot = ' but #{act} was thrown' 2138 | } 2139 | 2140 | this.assert( 2141 | thrown === true 2142 | , 'expected #{this} to throw ' + expectedThrown + actuallyGot 2143 | , 'expected #{this} to not throw ' + expectedThrown + actuallyGot 2144 | , (desiredError instanceof Error ? desiredError.toString() : desiredError) 2145 | , (thrownError instanceof Error ? thrownError.toString() : thrownError) 2146 | ); 2147 | 2148 | flag(this, 'object', thrownError); 2149 | }; 2150 | 2151 | Assertion.addMethod('throw', assertThrows); 2152 | Assertion.addMethod('throws', assertThrows); 2153 | Assertion.addMethod('Throw', assertThrows); 2154 | 2155 | /** 2156 | * ### .respondTo(method) 2157 | * 2158 | * Asserts that the object or class target will respond to a method. 2159 | * 2160 | * Klass.prototype.bar = function(){}; 2161 | * expect(Klass).to.respondTo('bar'); 2162 | * expect(obj).to.respondTo('bar'); 2163 | * 2164 | * To check if a constructor will respond to a static function, 2165 | * set the `itself` flag. 2166 | * 2167 | * Klass.baz = function(){}; 2168 | * expect(Klass).itself.to.respondTo('baz'); 2169 | * 2170 | * @name respondTo 2171 | * @param {String} method 2172 | * @param {String} message _optional_ 2173 | * @api public 2174 | */ 2175 | 2176 | Assertion.addMethod('respondTo', function (method, msg) { 2177 | if (msg) flag(this, 'message', msg); 2178 | var obj = flag(this, 'object') 2179 | , itself = flag(this, 'itself') 2180 | , context = ('function' === _.type(obj) && !itself) 2181 | ? obj.prototype[method] 2182 | : obj[method]; 2183 | 2184 | this.assert( 2185 | 'function' === typeof context 2186 | , 'expected #{this} to respond to ' + _.inspect(method) 2187 | , 'expected #{this} to not respond to ' + _.inspect(method) 2188 | ); 2189 | }); 2190 | 2191 | /** 2192 | * ### .itself 2193 | * 2194 | * Sets the `itself` flag, later used by the `respondTo` assertion. 2195 | * 2196 | * function Foo() {} 2197 | * Foo.bar = function() {} 2198 | * Foo.prototype.baz = function() {} 2199 | * 2200 | * expect(Foo).itself.to.respondTo('bar'); 2201 | * expect(Foo).itself.not.to.respondTo('baz'); 2202 | * 2203 | * @name itself 2204 | * @api public 2205 | */ 2206 | 2207 | Assertion.addProperty('itself', function () { 2208 | flag(this, 'itself', true); 2209 | }); 2210 | 2211 | /** 2212 | * ### .satisfy(method) 2213 | * 2214 | * Asserts that the target passes a given truth test. 2215 | * 2216 | * expect(1).to.satisfy(function(num) { return num > 0; }); 2217 | * 2218 | * @name satisfy 2219 | * @param {Function} matcher 2220 | * @param {String} message _optional_ 2221 | * @api public 2222 | */ 2223 | 2224 | Assertion.addMethod('satisfy', function (matcher, msg) { 2225 | if (msg) flag(this, 'message', msg); 2226 | var obj = flag(this, 'object'); 2227 | var result = matcher(obj); 2228 | this.assert( 2229 | result 2230 | , 'expected #{this} to satisfy ' + _.objDisplay(matcher) 2231 | , 'expected #{this} to not satisfy' + _.objDisplay(matcher) 2232 | , this.negate ? false : true 2233 | , result 2234 | ); 2235 | }); 2236 | 2237 | /** 2238 | * ### .closeTo(expected, delta) 2239 | * 2240 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 2241 | * 2242 | * expect(1.5).to.be.closeTo(1, 0.5); 2243 | * 2244 | * @name closeTo 2245 | * @param {Number} expected 2246 | * @param {Number} delta 2247 | * @param {String} message _optional_ 2248 | * @api public 2249 | */ 2250 | 2251 | Assertion.addMethod('closeTo', function (expected, delta, msg) { 2252 | if (msg) flag(this, 'message', msg); 2253 | var obj = flag(this, 'object'); 2254 | 2255 | new Assertion(obj, msg).is.a('number'); 2256 | if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { 2257 | throw new Error('the arguments to closeTo must be numbers'); 2258 | } 2259 | 2260 | this.assert( 2261 | Math.abs(obj - expected) <= delta 2262 | , 'expected #{this} to be close to ' + expected + ' +/- ' + delta 2263 | , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta 2264 | ); 2265 | }); 2266 | 2267 | function isSubsetOf(subset, superset, cmp) { 2268 | return subset.every(function(elem) { 2269 | if (!cmp) return superset.indexOf(elem) !== -1; 2270 | 2271 | return superset.some(function(elem2) { 2272 | return cmp(elem, elem2); 2273 | }); 2274 | }) 2275 | } 2276 | 2277 | /** 2278 | * ### .members(set) 2279 | * 2280 | * Asserts that the target is a superset of `set`, 2281 | * or that the target and `set` have the same strictly-equal (===) members. 2282 | * Alternately, if the `deep` flag is set, set members are compared for deep 2283 | * equality. 2284 | * 2285 | * expect([1, 2, 3]).to.include.members([3, 2]); 2286 | * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); 2287 | * 2288 | * expect([4, 2]).to.have.members([2, 4]); 2289 | * expect([5, 2]).to.not.have.members([5, 2, 1]); 2290 | * 2291 | * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); 2292 | * 2293 | * @name members 2294 | * @param {Array} set 2295 | * @param {String} message _optional_ 2296 | * @api public 2297 | */ 2298 | 2299 | Assertion.addMethod('members', function (subset, msg) { 2300 | if (msg) flag(this, 'message', msg); 2301 | var obj = flag(this, 'object'); 2302 | 2303 | new Assertion(obj).to.be.an('array'); 2304 | new Assertion(subset).to.be.an('array'); 2305 | 2306 | var cmp = flag(this, 'deep') ? _.eql : undefined; 2307 | 2308 | if (flag(this, 'contains')) { 2309 | return this.assert( 2310 | isSubsetOf(subset, obj, cmp) 2311 | , 'expected #{this} to be a superset of #{act}' 2312 | , 'expected #{this} to not be a superset of #{act}' 2313 | , obj 2314 | , subset 2315 | ); 2316 | } 2317 | 2318 | this.assert( 2319 | isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) 2320 | , 'expected #{this} to have the same members as #{act}' 2321 | , 'expected #{this} to not have the same members as #{act}' 2322 | , obj 2323 | , subset 2324 | ); 2325 | }); 2326 | }; 2327 | 2328 | }); 2329 | require.register("chai/lib/chai/interface/assert.js", function(exports, require, module){ 2330 | /*! 2331 | * chai 2332 | * Copyright(c) 2011-2014 Jake Luer 2333 | * MIT Licensed 2334 | */ 2335 | 2336 | 2337 | module.exports = function (chai, util) { 2338 | 2339 | /*! 2340 | * Chai dependencies. 2341 | */ 2342 | 2343 | var Assertion = chai.Assertion 2344 | , flag = util.flag; 2345 | 2346 | /*! 2347 | * Module export. 2348 | */ 2349 | 2350 | /** 2351 | * ### assert(expression, message) 2352 | * 2353 | * Write your own test expressions. 2354 | * 2355 | * assert('foo' !== 'bar', 'foo is not bar'); 2356 | * assert(Array.isArray([]), 'empty arrays are arrays'); 2357 | * 2358 | * @param {Mixed} expression to test for truthiness 2359 | * @param {String} message to display on error 2360 | * @name assert 2361 | * @api public 2362 | */ 2363 | 2364 | var assert = chai.assert = function (express, errmsg) { 2365 | var test = new Assertion(null, null, chai.assert); 2366 | test.assert( 2367 | express 2368 | , errmsg 2369 | , '[ negation message unavailable ]' 2370 | ); 2371 | }; 2372 | 2373 | /** 2374 | * ### .fail(actual, expected, [message], [operator]) 2375 | * 2376 | * Throw a failure. Node.js `assert` module-compatible. 2377 | * 2378 | * @name fail 2379 | * @param {Mixed} actual 2380 | * @param {Mixed} expected 2381 | * @param {String} message 2382 | * @param {String} operator 2383 | * @api public 2384 | */ 2385 | 2386 | assert.fail = function (actual, expected, message, operator) { 2387 | message = message || 'assert.fail()'; 2388 | throw new chai.AssertionError(message, { 2389 | actual: actual 2390 | , expected: expected 2391 | , operator: operator 2392 | }, assert.fail); 2393 | }; 2394 | 2395 | /** 2396 | * ### .ok(object, [message]) 2397 | * 2398 | * Asserts that `object` is truthy. 2399 | * 2400 | * assert.ok('everything', 'everything is ok'); 2401 | * assert.ok(false, 'this will fail'); 2402 | * 2403 | * @name ok 2404 | * @param {Mixed} object to test 2405 | * @param {String} message 2406 | * @api public 2407 | */ 2408 | 2409 | assert.ok = function (val, msg) { 2410 | new Assertion(val, msg).is.ok; 2411 | }; 2412 | 2413 | /** 2414 | * ### .notOk(object, [message]) 2415 | * 2416 | * Asserts that `object` is falsy. 2417 | * 2418 | * assert.notOk('everything', 'this will fail'); 2419 | * assert.notOk(false, 'this will pass'); 2420 | * 2421 | * @name notOk 2422 | * @param {Mixed} object to test 2423 | * @param {String} message 2424 | * @api public 2425 | */ 2426 | 2427 | assert.notOk = function (val, msg) { 2428 | new Assertion(val, msg).is.not.ok; 2429 | }; 2430 | 2431 | /** 2432 | * ### .equal(actual, expected, [message]) 2433 | * 2434 | * Asserts non-strict equality (`==`) of `actual` and `expected`. 2435 | * 2436 | * assert.equal(3, '3', '== coerces values to strings'); 2437 | * 2438 | * @name equal 2439 | * @param {Mixed} actual 2440 | * @param {Mixed} expected 2441 | * @param {String} message 2442 | * @api public 2443 | */ 2444 | 2445 | assert.equal = function (act, exp, msg) { 2446 | var test = new Assertion(act, msg, assert.equal); 2447 | 2448 | test.assert( 2449 | exp == flag(test, 'object') 2450 | , 'expected #{this} to equal #{exp}' 2451 | , 'expected #{this} to not equal #{act}' 2452 | , exp 2453 | , act 2454 | ); 2455 | }; 2456 | 2457 | /** 2458 | * ### .notEqual(actual, expected, [message]) 2459 | * 2460 | * Asserts non-strict inequality (`!=`) of `actual` and `expected`. 2461 | * 2462 | * assert.notEqual(3, 4, 'these numbers are not equal'); 2463 | * 2464 | * @name notEqual 2465 | * @param {Mixed} actual 2466 | * @param {Mixed} expected 2467 | * @param {String} message 2468 | * @api public 2469 | */ 2470 | 2471 | assert.notEqual = function (act, exp, msg) { 2472 | var test = new Assertion(act, msg, assert.notEqual); 2473 | 2474 | test.assert( 2475 | exp != flag(test, 'object') 2476 | , 'expected #{this} to not equal #{exp}' 2477 | , 'expected #{this} to equal #{act}' 2478 | , exp 2479 | , act 2480 | ); 2481 | }; 2482 | 2483 | /** 2484 | * ### .strictEqual(actual, expected, [message]) 2485 | * 2486 | * Asserts strict equality (`===`) of `actual` and `expected`. 2487 | * 2488 | * assert.strictEqual(true, true, 'these booleans are strictly equal'); 2489 | * 2490 | * @name strictEqual 2491 | * @param {Mixed} actual 2492 | * @param {Mixed} expected 2493 | * @param {String} message 2494 | * @api public 2495 | */ 2496 | 2497 | assert.strictEqual = function (act, exp, msg) { 2498 | new Assertion(act, msg).to.equal(exp); 2499 | }; 2500 | 2501 | /** 2502 | * ### .notStrictEqual(actual, expected, [message]) 2503 | * 2504 | * Asserts strict inequality (`!==`) of `actual` and `expected`. 2505 | * 2506 | * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); 2507 | * 2508 | * @name notStrictEqual 2509 | * @param {Mixed} actual 2510 | * @param {Mixed} expected 2511 | * @param {String} message 2512 | * @api public 2513 | */ 2514 | 2515 | assert.notStrictEqual = function (act, exp, msg) { 2516 | new Assertion(act, msg).to.not.equal(exp); 2517 | }; 2518 | 2519 | /** 2520 | * ### .deepEqual(actual, expected, [message]) 2521 | * 2522 | * Asserts that `actual` is deeply equal to `expected`. 2523 | * 2524 | * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); 2525 | * 2526 | * @name deepEqual 2527 | * @param {Mixed} actual 2528 | * @param {Mixed} expected 2529 | * @param {String} message 2530 | * @api public 2531 | */ 2532 | 2533 | assert.deepEqual = function (act, exp, msg) { 2534 | new Assertion(act, msg).to.eql(exp); 2535 | }; 2536 | 2537 | /** 2538 | * ### .notDeepEqual(actual, expected, [message]) 2539 | * 2540 | * Assert that `actual` is not deeply equal to `expected`. 2541 | * 2542 | * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); 2543 | * 2544 | * @name notDeepEqual 2545 | * @param {Mixed} actual 2546 | * @param {Mixed} expected 2547 | * @param {String} message 2548 | * @api public 2549 | */ 2550 | 2551 | assert.notDeepEqual = function (act, exp, msg) { 2552 | new Assertion(act, msg).to.not.eql(exp); 2553 | }; 2554 | 2555 | /** 2556 | * ### .isTrue(value, [message]) 2557 | * 2558 | * Asserts that `value` is true. 2559 | * 2560 | * var teaServed = true; 2561 | * assert.isTrue(teaServed, 'the tea has been served'); 2562 | * 2563 | * @name isTrue 2564 | * @param {Mixed} value 2565 | * @param {String} message 2566 | * @api public 2567 | */ 2568 | 2569 | assert.isTrue = function (val, msg) { 2570 | new Assertion(val, msg).is['true']; 2571 | }; 2572 | 2573 | /** 2574 | * ### .isFalse(value, [message]) 2575 | * 2576 | * Asserts that `value` is false. 2577 | * 2578 | * var teaServed = false; 2579 | * assert.isFalse(teaServed, 'no tea yet? hmm...'); 2580 | * 2581 | * @name isFalse 2582 | * @param {Mixed} value 2583 | * @param {String} message 2584 | * @api public 2585 | */ 2586 | 2587 | assert.isFalse = function (val, msg) { 2588 | new Assertion(val, msg).is['false']; 2589 | }; 2590 | 2591 | /** 2592 | * ### .isNull(value, [message]) 2593 | * 2594 | * Asserts that `value` is null. 2595 | * 2596 | * assert.isNull(err, 'there was no error'); 2597 | * 2598 | * @name isNull 2599 | * @param {Mixed} value 2600 | * @param {String} message 2601 | * @api public 2602 | */ 2603 | 2604 | assert.isNull = function (val, msg) { 2605 | new Assertion(val, msg).to.equal(null); 2606 | }; 2607 | 2608 | /** 2609 | * ### .isNotNull(value, [message]) 2610 | * 2611 | * Asserts that `value` is not null. 2612 | * 2613 | * var tea = 'tasty chai'; 2614 | * assert.isNotNull(tea, 'great, time for tea!'); 2615 | * 2616 | * @name isNotNull 2617 | * @param {Mixed} value 2618 | * @param {String} message 2619 | * @api public 2620 | */ 2621 | 2622 | assert.isNotNull = function (val, msg) { 2623 | new Assertion(val, msg).to.not.equal(null); 2624 | }; 2625 | 2626 | /** 2627 | * ### .isUndefined(value, [message]) 2628 | * 2629 | * Asserts that `value` is `undefined`. 2630 | * 2631 | * var tea; 2632 | * assert.isUndefined(tea, 'no tea defined'); 2633 | * 2634 | * @name isUndefined 2635 | * @param {Mixed} value 2636 | * @param {String} message 2637 | * @api public 2638 | */ 2639 | 2640 | assert.isUndefined = function (val, msg) { 2641 | new Assertion(val, msg).to.equal(undefined); 2642 | }; 2643 | 2644 | /** 2645 | * ### .isDefined(value, [message]) 2646 | * 2647 | * Asserts that `value` is not `undefined`. 2648 | * 2649 | * var tea = 'cup of chai'; 2650 | * assert.isDefined(tea, 'tea has been defined'); 2651 | * 2652 | * @name isDefined 2653 | * @param {Mixed} value 2654 | * @param {String} message 2655 | * @api public 2656 | */ 2657 | 2658 | assert.isDefined = function (val, msg) { 2659 | new Assertion(val, msg).to.not.equal(undefined); 2660 | }; 2661 | 2662 | /** 2663 | * ### .isFunction(value, [message]) 2664 | * 2665 | * Asserts that `value` is a function. 2666 | * 2667 | * function serveTea() { return 'cup of tea'; }; 2668 | * assert.isFunction(serveTea, 'great, we can have tea now'); 2669 | * 2670 | * @name isFunction 2671 | * @param {Mixed} value 2672 | * @param {String} message 2673 | * @api public 2674 | */ 2675 | 2676 | assert.isFunction = function (val, msg) { 2677 | new Assertion(val, msg).to.be.a('function'); 2678 | }; 2679 | 2680 | /** 2681 | * ### .isNotFunction(value, [message]) 2682 | * 2683 | * Asserts that `value` is _not_ a function. 2684 | * 2685 | * var serveTea = [ 'heat', 'pour', 'sip' ]; 2686 | * assert.isNotFunction(serveTea, 'great, we have listed the steps'); 2687 | * 2688 | * @name isNotFunction 2689 | * @param {Mixed} value 2690 | * @param {String} message 2691 | * @api public 2692 | */ 2693 | 2694 | assert.isNotFunction = function (val, msg) { 2695 | new Assertion(val, msg).to.not.be.a('function'); 2696 | }; 2697 | 2698 | /** 2699 | * ### .isObject(value, [message]) 2700 | * 2701 | * Asserts that `value` is an object (as revealed by 2702 | * `Object.prototype.toString`). 2703 | * 2704 | * var selection = { name: 'Chai', serve: 'with spices' }; 2705 | * assert.isObject(selection, 'tea selection is an object'); 2706 | * 2707 | * @name isObject 2708 | * @param {Mixed} value 2709 | * @param {String} message 2710 | * @api public 2711 | */ 2712 | 2713 | assert.isObject = function (val, msg) { 2714 | new Assertion(val, msg).to.be.a('object'); 2715 | }; 2716 | 2717 | /** 2718 | * ### .isNotObject(value, [message]) 2719 | * 2720 | * Asserts that `value` is _not_ an object. 2721 | * 2722 | * var selection = 'chai' 2723 | * assert.isNotObject(selection, 'tea selection is not an object'); 2724 | * assert.isNotObject(null, 'null is not an object'); 2725 | * 2726 | * @name isNotObject 2727 | * @param {Mixed} value 2728 | * @param {String} message 2729 | * @api public 2730 | */ 2731 | 2732 | assert.isNotObject = function (val, msg) { 2733 | new Assertion(val, msg).to.not.be.a('object'); 2734 | }; 2735 | 2736 | /** 2737 | * ### .isArray(value, [message]) 2738 | * 2739 | * Asserts that `value` is an array. 2740 | * 2741 | * var menu = [ 'green', 'chai', 'oolong' ]; 2742 | * assert.isArray(menu, 'what kind of tea do we want?'); 2743 | * 2744 | * @name isArray 2745 | * @param {Mixed} value 2746 | * @param {String} message 2747 | * @api public 2748 | */ 2749 | 2750 | assert.isArray = function (val, msg) { 2751 | new Assertion(val, msg).to.be.an('array'); 2752 | }; 2753 | 2754 | /** 2755 | * ### .isNotArray(value, [message]) 2756 | * 2757 | * Asserts that `value` is _not_ an array. 2758 | * 2759 | * var menu = 'green|chai|oolong'; 2760 | * assert.isNotArray(menu, 'what kind of tea do we want?'); 2761 | * 2762 | * @name isNotArray 2763 | * @param {Mixed} value 2764 | * @param {String} message 2765 | * @api public 2766 | */ 2767 | 2768 | assert.isNotArray = function (val, msg) { 2769 | new Assertion(val, msg).to.not.be.an('array'); 2770 | }; 2771 | 2772 | /** 2773 | * ### .isString(value, [message]) 2774 | * 2775 | * Asserts that `value` is a string. 2776 | * 2777 | * var teaOrder = 'chai'; 2778 | * assert.isString(teaOrder, 'order placed'); 2779 | * 2780 | * @name isString 2781 | * @param {Mixed} value 2782 | * @param {String} message 2783 | * @api public 2784 | */ 2785 | 2786 | assert.isString = function (val, msg) { 2787 | new Assertion(val, msg).to.be.a('string'); 2788 | }; 2789 | 2790 | /** 2791 | * ### .isNotString(value, [message]) 2792 | * 2793 | * Asserts that `value` is _not_ a string. 2794 | * 2795 | * var teaOrder = 4; 2796 | * assert.isNotString(teaOrder, 'order placed'); 2797 | * 2798 | * @name isNotString 2799 | * @param {Mixed} value 2800 | * @param {String} message 2801 | * @api public 2802 | */ 2803 | 2804 | assert.isNotString = function (val, msg) { 2805 | new Assertion(val, msg).to.not.be.a('string'); 2806 | }; 2807 | 2808 | /** 2809 | * ### .isNumber(value, [message]) 2810 | * 2811 | * Asserts that `value` is a number. 2812 | * 2813 | * var cups = 2; 2814 | * assert.isNumber(cups, 'how many cups'); 2815 | * 2816 | * @name isNumber 2817 | * @param {Number} value 2818 | * @param {String} message 2819 | * @api public 2820 | */ 2821 | 2822 | assert.isNumber = function (val, msg) { 2823 | new Assertion(val, msg).to.be.a('number'); 2824 | }; 2825 | 2826 | /** 2827 | * ### .isNotNumber(value, [message]) 2828 | * 2829 | * Asserts that `value` is _not_ a number. 2830 | * 2831 | * var cups = '2 cups please'; 2832 | * assert.isNotNumber(cups, 'how many cups'); 2833 | * 2834 | * @name isNotNumber 2835 | * @param {Mixed} value 2836 | * @param {String} message 2837 | * @api public 2838 | */ 2839 | 2840 | assert.isNotNumber = function (val, msg) { 2841 | new Assertion(val, msg).to.not.be.a('number'); 2842 | }; 2843 | 2844 | /** 2845 | * ### .isBoolean(value, [message]) 2846 | * 2847 | * Asserts that `value` is a boolean. 2848 | * 2849 | * var teaReady = true 2850 | * , teaServed = false; 2851 | * 2852 | * assert.isBoolean(teaReady, 'is the tea ready'); 2853 | * assert.isBoolean(teaServed, 'has tea been served'); 2854 | * 2855 | * @name isBoolean 2856 | * @param {Mixed} value 2857 | * @param {String} message 2858 | * @api public 2859 | */ 2860 | 2861 | assert.isBoolean = function (val, msg) { 2862 | new Assertion(val, msg).to.be.a('boolean'); 2863 | }; 2864 | 2865 | /** 2866 | * ### .isNotBoolean(value, [message]) 2867 | * 2868 | * Asserts that `value` is _not_ a boolean. 2869 | * 2870 | * var teaReady = 'yep' 2871 | * , teaServed = 'nope'; 2872 | * 2873 | * assert.isNotBoolean(teaReady, 'is the tea ready'); 2874 | * assert.isNotBoolean(teaServed, 'has tea been served'); 2875 | * 2876 | * @name isNotBoolean 2877 | * @param {Mixed} value 2878 | * @param {String} message 2879 | * @api public 2880 | */ 2881 | 2882 | assert.isNotBoolean = function (val, msg) { 2883 | new Assertion(val, msg).to.not.be.a('boolean'); 2884 | }; 2885 | 2886 | /** 2887 | * ### .typeOf(value, name, [message]) 2888 | * 2889 | * Asserts that `value`'s type is `name`, as determined by 2890 | * `Object.prototype.toString`. 2891 | * 2892 | * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); 2893 | * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); 2894 | * assert.typeOf('tea', 'string', 'we have a string'); 2895 | * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); 2896 | * assert.typeOf(null, 'null', 'we have a null'); 2897 | * assert.typeOf(undefined, 'undefined', 'we have an undefined'); 2898 | * 2899 | * @name typeOf 2900 | * @param {Mixed} value 2901 | * @param {String} name 2902 | * @param {String} message 2903 | * @api public 2904 | */ 2905 | 2906 | assert.typeOf = function (val, type, msg) { 2907 | new Assertion(val, msg).to.be.a(type); 2908 | }; 2909 | 2910 | /** 2911 | * ### .notTypeOf(value, name, [message]) 2912 | * 2913 | * Asserts that `value`'s type is _not_ `name`, as determined by 2914 | * `Object.prototype.toString`. 2915 | * 2916 | * assert.notTypeOf('tea', 'number', 'strings are not numbers'); 2917 | * 2918 | * @name notTypeOf 2919 | * @param {Mixed} value 2920 | * @param {String} typeof name 2921 | * @param {String} message 2922 | * @api public 2923 | */ 2924 | 2925 | assert.notTypeOf = function (val, type, msg) { 2926 | new Assertion(val, msg).to.not.be.a(type); 2927 | }; 2928 | 2929 | /** 2930 | * ### .instanceOf(object, constructor, [message]) 2931 | * 2932 | * Asserts that `value` is an instance of `constructor`. 2933 | * 2934 | * var Tea = function (name) { this.name = name; } 2935 | * , chai = new Tea('chai'); 2936 | * 2937 | * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); 2938 | * 2939 | * @name instanceOf 2940 | * @param {Object} object 2941 | * @param {Constructor} constructor 2942 | * @param {String} message 2943 | * @api public 2944 | */ 2945 | 2946 | assert.instanceOf = function (val, type, msg) { 2947 | new Assertion(val, msg).to.be.instanceOf(type); 2948 | }; 2949 | 2950 | /** 2951 | * ### .notInstanceOf(object, constructor, [message]) 2952 | * 2953 | * Asserts `value` is not an instance of `constructor`. 2954 | * 2955 | * var Tea = function (name) { this.name = name; } 2956 | * , chai = new String('chai'); 2957 | * 2958 | * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); 2959 | * 2960 | * @name notInstanceOf 2961 | * @param {Object} object 2962 | * @param {Constructor} constructor 2963 | * @param {String} message 2964 | * @api public 2965 | */ 2966 | 2967 | assert.notInstanceOf = function (val, type, msg) { 2968 | new Assertion(val, msg).to.not.be.instanceOf(type); 2969 | }; 2970 | 2971 | /** 2972 | * ### .include(haystack, needle, [message]) 2973 | * 2974 | * Asserts that `haystack` includes `needle`. Works 2975 | * for strings and arrays. 2976 | * 2977 | * assert.include('foobar', 'bar', 'foobar contains string "bar"'); 2978 | * assert.include([ 1, 2, 3 ], 3, 'array contains value'); 2979 | * 2980 | * @name include 2981 | * @param {Array|String} haystack 2982 | * @param {Mixed} needle 2983 | * @param {String} message 2984 | * @api public 2985 | */ 2986 | 2987 | assert.include = function (exp, inc, msg) { 2988 | new Assertion(exp, msg, assert.include).include(inc); 2989 | }; 2990 | 2991 | /** 2992 | * ### .notInclude(haystack, needle, [message]) 2993 | * 2994 | * Asserts that `haystack` does not include `needle`. Works 2995 | * for strings and arrays. 2996 | *i 2997 | * assert.notInclude('foobar', 'baz', 'string not include substring'); 2998 | * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); 2999 | * 3000 | * @name notInclude 3001 | * @param {Array|String} haystack 3002 | * @param {Mixed} needle 3003 | * @param {String} message 3004 | * @api public 3005 | */ 3006 | 3007 | assert.notInclude = function (exp, inc, msg) { 3008 | new Assertion(exp, msg, assert.notInclude).not.include(inc); 3009 | }; 3010 | 3011 | /** 3012 | * ### .match(value, regexp, [message]) 3013 | * 3014 | * Asserts that `value` matches the regular expression `regexp`. 3015 | * 3016 | * assert.match('foobar', /^foo/, 'regexp matches'); 3017 | * 3018 | * @name match 3019 | * @param {Mixed} value 3020 | * @param {RegExp} regexp 3021 | * @param {String} message 3022 | * @api public 3023 | */ 3024 | 3025 | assert.match = function (exp, re, msg) { 3026 | new Assertion(exp, msg).to.match(re); 3027 | }; 3028 | 3029 | /** 3030 | * ### .notMatch(value, regexp, [message]) 3031 | * 3032 | * Asserts that `value` does not match the regular expression `regexp`. 3033 | * 3034 | * assert.notMatch('foobar', /^foo/, 'regexp does not match'); 3035 | * 3036 | * @name notMatch 3037 | * @param {Mixed} value 3038 | * @param {RegExp} regexp 3039 | * @param {String} message 3040 | * @api public 3041 | */ 3042 | 3043 | assert.notMatch = function (exp, re, msg) { 3044 | new Assertion(exp, msg).to.not.match(re); 3045 | }; 3046 | 3047 | /** 3048 | * ### .property(object, property, [message]) 3049 | * 3050 | * Asserts that `object` has a property named by `property`. 3051 | * 3052 | * assert.property({ tea: { green: 'matcha' }}, 'tea'); 3053 | * 3054 | * @name property 3055 | * @param {Object} object 3056 | * @param {String} property 3057 | * @param {String} message 3058 | * @api public 3059 | */ 3060 | 3061 | assert.property = function (obj, prop, msg) { 3062 | new Assertion(obj, msg).to.have.property(prop); 3063 | }; 3064 | 3065 | /** 3066 | * ### .notProperty(object, property, [message]) 3067 | * 3068 | * Asserts that `object` does _not_ have a property named by `property`. 3069 | * 3070 | * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); 3071 | * 3072 | * @name notProperty 3073 | * @param {Object} object 3074 | * @param {String} property 3075 | * @param {String} message 3076 | * @api public 3077 | */ 3078 | 3079 | assert.notProperty = function (obj, prop, msg) { 3080 | new Assertion(obj, msg).to.not.have.property(prop); 3081 | }; 3082 | 3083 | /** 3084 | * ### .deepProperty(object, property, [message]) 3085 | * 3086 | * Asserts that `object` has a property named by `property`, which can be a 3087 | * string using dot- and bracket-notation for deep reference. 3088 | * 3089 | * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); 3090 | * 3091 | * @name deepProperty 3092 | * @param {Object} object 3093 | * @param {String} property 3094 | * @param {String} message 3095 | * @api public 3096 | */ 3097 | 3098 | assert.deepProperty = function (obj, prop, msg) { 3099 | new Assertion(obj, msg).to.have.deep.property(prop); 3100 | }; 3101 | 3102 | /** 3103 | * ### .notDeepProperty(object, property, [message]) 3104 | * 3105 | * Asserts that `object` does _not_ have a property named by `property`, which 3106 | * can be a string using dot- and bracket-notation for deep reference. 3107 | * 3108 | * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); 3109 | * 3110 | * @name notDeepProperty 3111 | * @param {Object} object 3112 | * @param {String} property 3113 | * @param {String} message 3114 | * @api public 3115 | */ 3116 | 3117 | assert.notDeepProperty = function (obj, prop, msg) { 3118 | new Assertion(obj, msg).to.not.have.deep.property(prop); 3119 | }; 3120 | 3121 | /** 3122 | * ### .propertyVal(object, property, value, [message]) 3123 | * 3124 | * Asserts that `object` has a property named by `property` with value given 3125 | * by `value`. 3126 | * 3127 | * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); 3128 | * 3129 | * @name propertyVal 3130 | * @param {Object} object 3131 | * @param {String} property 3132 | * @param {Mixed} value 3133 | * @param {String} message 3134 | * @api public 3135 | */ 3136 | 3137 | assert.propertyVal = function (obj, prop, val, msg) { 3138 | new Assertion(obj, msg).to.have.property(prop, val); 3139 | }; 3140 | 3141 | /** 3142 | * ### .propertyNotVal(object, property, value, [message]) 3143 | * 3144 | * Asserts that `object` has a property named by `property`, but with a value 3145 | * different from that given by `value`. 3146 | * 3147 | * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); 3148 | * 3149 | * @name propertyNotVal 3150 | * @param {Object} object 3151 | * @param {String} property 3152 | * @param {Mixed} value 3153 | * @param {String} message 3154 | * @api public 3155 | */ 3156 | 3157 | assert.propertyNotVal = function (obj, prop, val, msg) { 3158 | new Assertion(obj, msg).to.not.have.property(prop, val); 3159 | }; 3160 | 3161 | /** 3162 | * ### .deepPropertyVal(object, property, value, [message]) 3163 | * 3164 | * Asserts that `object` has a property named by `property` with value given 3165 | * by `value`. `property` can use dot- and bracket-notation for deep 3166 | * reference. 3167 | * 3168 | * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); 3169 | * 3170 | * @name deepPropertyVal 3171 | * @param {Object} object 3172 | * @param {String} property 3173 | * @param {Mixed} value 3174 | * @param {String} message 3175 | * @api public 3176 | */ 3177 | 3178 | assert.deepPropertyVal = function (obj, prop, val, msg) { 3179 | new Assertion(obj, msg).to.have.deep.property(prop, val); 3180 | }; 3181 | 3182 | /** 3183 | * ### .deepPropertyNotVal(object, property, value, [message]) 3184 | * 3185 | * Asserts that `object` has a property named by `property`, but with a value 3186 | * different from that given by `value`. `property` can use dot- and 3187 | * bracket-notation for deep reference. 3188 | * 3189 | * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); 3190 | * 3191 | * @name deepPropertyNotVal 3192 | * @param {Object} object 3193 | * @param {String} property 3194 | * @param {Mixed} value 3195 | * @param {String} message 3196 | * @api public 3197 | */ 3198 | 3199 | assert.deepPropertyNotVal = function (obj, prop, val, msg) { 3200 | new Assertion(obj, msg).to.not.have.deep.property(prop, val); 3201 | }; 3202 | 3203 | /** 3204 | * ### .lengthOf(object, length, [message]) 3205 | * 3206 | * Asserts that `object` has a `length` property with the expected value. 3207 | * 3208 | * assert.lengthOf([1,2,3], 3, 'array has length of 3'); 3209 | * assert.lengthOf('foobar', 5, 'string has length of 6'); 3210 | * 3211 | * @name lengthOf 3212 | * @param {Mixed} object 3213 | * @param {Number} length 3214 | * @param {String} message 3215 | * @api public 3216 | */ 3217 | 3218 | assert.lengthOf = function (exp, len, msg) { 3219 | new Assertion(exp, msg).to.have.length(len); 3220 | }; 3221 | 3222 | /** 3223 | * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) 3224 | * 3225 | * Asserts that `function` will throw an error that is an instance of 3226 | * `constructor`, or alternately that it will throw an error with message 3227 | * matching `regexp`. 3228 | * 3229 | * assert.throw(fn, 'function throws a reference error'); 3230 | * assert.throw(fn, /function throws a reference error/); 3231 | * assert.throw(fn, ReferenceError); 3232 | * assert.throw(fn, ReferenceError, 'function throws a reference error'); 3233 | * assert.throw(fn, ReferenceError, /function throws a reference error/); 3234 | * 3235 | * @name throws 3236 | * @alias throw 3237 | * @alias Throw 3238 | * @param {Function} function 3239 | * @param {ErrorConstructor} constructor 3240 | * @param {RegExp} regexp 3241 | * @param {String} message 3242 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3243 | * @api public 3244 | */ 3245 | 3246 | assert.Throw = function (fn, errt, errs, msg) { 3247 | if ('string' === typeof errt || errt instanceof RegExp) { 3248 | errs = errt; 3249 | errt = null; 3250 | } 3251 | 3252 | var assertErr = new Assertion(fn, msg).to.Throw(errt, errs); 3253 | return flag(assertErr, 'object'); 3254 | }; 3255 | 3256 | /** 3257 | * ### .doesNotThrow(function, [constructor/regexp], [message]) 3258 | * 3259 | * Asserts that `function` will _not_ throw an error that is an instance of 3260 | * `constructor`, or alternately that it will not throw an error with message 3261 | * matching `regexp`. 3262 | * 3263 | * assert.doesNotThrow(fn, Error, 'function does not throw'); 3264 | * 3265 | * @name doesNotThrow 3266 | * @param {Function} function 3267 | * @param {ErrorConstructor} constructor 3268 | * @param {RegExp} regexp 3269 | * @param {String} message 3270 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3271 | * @api public 3272 | */ 3273 | 3274 | assert.doesNotThrow = function (fn, type, msg) { 3275 | if ('string' === typeof type) { 3276 | msg = type; 3277 | type = null; 3278 | } 3279 | 3280 | new Assertion(fn, msg).to.not.Throw(type); 3281 | }; 3282 | 3283 | /** 3284 | * ### .operator(val1, operator, val2, [message]) 3285 | * 3286 | * Compares two values using `operator`. 3287 | * 3288 | * assert.operator(1, '<', 2, 'everything is ok'); 3289 | * assert.operator(1, '>', 2, 'this will fail'); 3290 | * 3291 | * @name operator 3292 | * @param {Mixed} val1 3293 | * @param {String} operator 3294 | * @param {Mixed} val2 3295 | * @param {String} message 3296 | * @api public 3297 | */ 3298 | 3299 | assert.operator = function (val, operator, val2, msg) { 3300 | if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) { 3301 | throw new Error('Invalid operator "' + operator + '"'); 3302 | } 3303 | var test = new Assertion(eval(val + operator + val2), msg); 3304 | test.assert( 3305 | true === flag(test, 'object') 3306 | , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) 3307 | , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); 3308 | }; 3309 | 3310 | /** 3311 | * ### .closeTo(actual, expected, delta, [message]) 3312 | * 3313 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 3314 | * 3315 | * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); 3316 | * 3317 | * @name closeTo 3318 | * @param {Number} actual 3319 | * @param {Number} expected 3320 | * @param {Number} delta 3321 | * @param {String} message 3322 | * @api public 3323 | */ 3324 | 3325 | assert.closeTo = function (act, exp, delta, msg) { 3326 | new Assertion(act, msg).to.be.closeTo(exp, delta); 3327 | }; 3328 | 3329 | /** 3330 | * ### .sameMembers(set1, set2, [message]) 3331 | * 3332 | * Asserts that `set1` and `set2` have the same members. 3333 | * Order is not taken into account. 3334 | * 3335 | * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); 3336 | * 3337 | * @name sameMembers 3338 | * @param {Array} set1 3339 | * @param {Array} set2 3340 | * @param {String} message 3341 | * @api public 3342 | */ 3343 | 3344 | assert.sameMembers = function (set1, set2, msg) { 3345 | new Assertion(set1, msg).to.have.same.members(set2); 3346 | } 3347 | 3348 | /** 3349 | * ### .includeMembers(superset, subset, [message]) 3350 | * 3351 | * Asserts that `subset` is included in `superset`. 3352 | * Order is not taken into account. 3353 | * 3354 | * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); 3355 | * 3356 | * @name includeMembers 3357 | * @param {Array} superset 3358 | * @param {Array} subset 3359 | * @param {String} message 3360 | * @api public 3361 | */ 3362 | 3363 | assert.includeMembers = function (superset, subset, msg) { 3364 | new Assertion(superset, msg).to.include.members(subset); 3365 | } 3366 | 3367 | /*! 3368 | * Undocumented / untested 3369 | */ 3370 | 3371 | assert.ifError = function (val, msg) { 3372 | new Assertion(val, msg).to.not.be.ok; 3373 | }; 3374 | 3375 | /*! 3376 | * Aliases. 3377 | */ 3378 | 3379 | (function alias(name, as){ 3380 | assert[as] = assert[name]; 3381 | return alias; 3382 | }) 3383 | ('Throw', 'throw') 3384 | ('Throw', 'throws'); 3385 | }; 3386 | 3387 | }); 3388 | require.register("chai/lib/chai/interface/expect.js", function(exports, require, module){ 3389 | /*! 3390 | * chai 3391 | * Copyright(c) 2011-2014 Jake Luer 3392 | * MIT Licensed 3393 | */ 3394 | 3395 | module.exports = function (chai, util) { 3396 | chai.expect = function (val, message) { 3397 | return new chai.Assertion(val, message); 3398 | }; 3399 | }; 3400 | 3401 | 3402 | }); 3403 | require.register("chai/lib/chai/interface/should.js", function(exports, require, module){ 3404 | /*! 3405 | * chai 3406 | * Copyright(c) 2011-2014 Jake Luer 3407 | * MIT Licensed 3408 | */ 3409 | 3410 | module.exports = function (chai, util) { 3411 | var Assertion = chai.Assertion; 3412 | 3413 | function loadShould () { 3414 | // explicitly define this method as function as to have it's name to include as `ssfi` 3415 | function shouldGetter() { 3416 | if (this instanceof String || this instanceof Number) { 3417 | return new Assertion(this.constructor(this), null, shouldGetter); 3418 | } else if (this instanceof Boolean) { 3419 | return new Assertion(this == true, null, shouldGetter); 3420 | } 3421 | return new Assertion(this, null, shouldGetter); 3422 | } 3423 | function shouldSetter(value) { 3424 | // See https://github.com/chaijs/chai/issues/86: this makes 3425 | // `whatever.should = someValue` actually set `someValue`, which is 3426 | // especially useful for `global.should = require('chai').should()`. 3427 | // 3428 | // Note that we have to use [[DefineProperty]] instead of [[Put]] 3429 | // since otherwise we would trigger this very setter! 3430 | Object.defineProperty(this, 'should', { 3431 | value: value, 3432 | enumerable: true, 3433 | configurable: true, 3434 | writable: true 3435 | }); 3436 | } 3437 | // modify Object.prototype to have `should` 3438 | Object.defineProperty(Object.prototype, 'should', { 3439 | set: shouldSetter 3440 | , get: shouldGetter 3441 | , configurable: true 3442 | }); 3443 | 3444 | var should = {}; 3445 | 3446 | should.equal = function (val1, val2, msg) { 3447 | new Assertion(val1, msg).to.equal(val2); 3448 | }; 3449 | 3450 | should.Throw = function (fn, errt, errs, msg) { 3451 | new Assertion(fn, msg).to.Throw(errt, errs); 3452 | }; 3453 | 3454 | should.exist = function (val, msg) { 3455 | new Assertion(val, msg).to.exist; 3456 | } 3457 | 3458 | // negation 3459 | should.not = {} 3460 | 3461 | should.not.equal = function (val1, val2, msg) { 3462 | new Assertion(val1, msg).to.not.equal(val2); 3463 | }; 3464 | 3465 | should.not.Throw = function (fn, errt, errs, msg) { 3466 | new Assertion(fn, msg).to.not.Throw(errt, errs); 3467 | }; 3468 | 3469 | should.not.exist = function (val, msg) { 3470 | new Assertion(val, msg).to.not.exist; 3471 | } 3472 | 3473 | should['throw'] = should['Throw']; 3474 | should.not['throw'] = should.not['Throw']; 3475 | 3476 | return should; 3477 | }; 3478 | 3479 | chai.should = loadShould; 3480 | chai.Should = loadShould; 3481 | }; 3482 | 3483 | }); 3484 | require.register("chai/lib/chai/utils/addChainableMethod.js", function(exports, require, module){ 3485 | /*! 3486 | * Chai - addChainingMethod utility 3487 | * Copyright(c) 2012-2014 Jake Luer 3488 | * MIT Licensed 3489 | */ 3490 | 3491 | /*! 3492 | * Module dependencies 3493 | */ 3494 | 3495 | var transferFlags = require('./transferFlags'); 3496 | var flag = require('./flag'); 3497 | var config = require('../config'); 3498 | 3499 | /*! 3500 | * Module variables 3501 | */ 3502 | 3503 | // Check whether `__proto__` is supported 3504 | var hasProtoSupport = '__proto__' in Object; 3505 | 3506 | // Without `__proto__` support, this module will need to add properties to a function. 3507 | // However, some Function.prototype methods cannot be overwritten, 3508 | // and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). 3509 | var excludeNames = /^(?:length|name|arguments|caller)$/; 3510 | 3511 | // Cache `Function` properties 3512 | var call = Function.prototype.call, 3513 | apply = Function.prototype.apply; 3514 | 3515 | /** 3516 | * ### addChainableMethod (ctx, name, method, chainingBehavior) 3517 | * 3518 | * Adds a method to an object, such that the method can also be chained. 3519 | * 3520 | * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { 3521 | * var obj = utils.flag(this, 'object'); 3522 | * new chai.Assertion(obj).to.be.equal(str); 3523 | * }); 3524 | * 3525 | * Can also be accessed directly from `chai.Assertion`. 3526 | * 3527 | * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); 3528 | * 3529 | * The result can then be used as both a method assertion, executing both `method` and 3530 | * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. 3531 | * 3532 | * expect(fooStr).to.be.foo('bar'); 3533 | * expect(fooStr).to.be.foo.equal('foo'); 3534 | * 3535 | * @param {Object} ctx object to which the method is added 3536 | * @param {String} name of method to add 3537 | * @param {Function} method function to be used for `name`, when called 3538 | * @param {Function} chainingBehavior function to be called every time the property is accessed 3539 | * @name addChainableMethod 3540 | * @api public 3541 | */ 3542 | 3543 | module.exports = function (ctx, name, method, chainingBehavior) { 3544 | if (typeof chainingBehavior !== 'function') { 3545 | chainingBehavior = function () { }; 3546 | } 3547 | 3548 | var chainableBehavior = { 3549 | method: method 3550 | , chainingBehavior: chainingBehavior 3551 | }; 3552 | 3553 | // save the methods so we can overwrite them later, if we need to. 3554 | if (!ctx.__methods) { 3555 | ctx.__methods = {}; 3556 | } 3557 | ctx.__methods[name] = chainableBehavior; 3558 | 3559 | Object.defineProperty(ctx, name, 3560 | { get: function () { 3561 | chainableBehavior.chainingBehavior.call(this); 3562 | 3563 | var assert = function assert() { 3564 | var old_ssfi = flag(this, 'ssfi'); 3565 | if (old_ssfi && config.includeStack === false) 3566 | flag(this, 'ssfi', assert); 3567 | var result = chainableBehavior.method.apply(this, arguments); 3568 | return result === undefined ? this : result; 3569 | }; 3570 | 3571 | // Use `__proto__` if available 3572 | if (hasProtoSupport) { 3573 | // Inherit all properties from the object by replacing the `Function` prototype 3574 | var prototype = assert.__proto__ = Object.create(this); 3575 | // Restore the `call` and `apply` methods from `Function` 3576 | prototype.call = call; 3577 | prototype.apply = apply; 3578 | } 3579 | // Otherwise, redefine all properties (slow!) 3580 | else { 3581 | var asserterNames = Object.getOwnPropertyNames(ctx); 3582 | asserterNames.forEach(function (asserterName) { 3583 | if (!excludeNames.test(asserterName)) { 3584 | var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); 3585 | Object.defineProperty(assert, asserterName, pd); 3586 | } 3587 | }); 3588 | } 3589 | 3590 | transferFlags(this, assert); 3591 | return assert; 3592 | } 3593 | , configurable: true 3594 | }); 3595 | }; 3596 | 3597 | }); 3598 | require.register("chai/lib/chai/utils/addMethod.js", function(exports, require, module){ 3599 | /*! 3600 | * Chai - addMethod utility 3601 | * Copyright(c) 2012-2014 Jake Luer 3602 | * MIT Licensed 3603 | */ 3604 | 3605 | var config = require('../config'); 3606 | 3607 | /** 3608 | * ### .addMethod (ctx, name, method) 3609 | * 3610 | * Adds a method to the prototype of an object. 3611 | * 3612 | * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { 3613 | * var obj = utils.flag(this, 'object'); 3614 | * new chai.Assertion(obj).to.be.equal(str); 3615 | * }); 3616 | * 3617 | * Can also be accessed directly from `chai.Assertion`. 3618 | * 3619 | * chai.Assertion.addMethod('foo', fn); 3620 | * 3621 | * Then can be used as any other assertion. 3622 | * 3623 | * expect(fooStr).to.be.foo('bar'); 3624 | * 3625 | * @param {Object} ctx object to which the method is added 3626 | * @param {String} name of method to add 3627 | * @param {Function} method function to be used for name 3628 | * @name addMethod 3629 | * @api public 3630 | */ 3631 | var flag = require('./flag'); 3632 | 3633 | module.exports = function (ctx, name, method) { 3634 | ctx[name] = function () { 3635 | var old_ssfi = flag(this, 'ssfi'); 3636 | if (old_ssfi && config.includeStack === false) 3637 | flag(this, 'ssfi', ctx[name]); 3638 | var result = method.apply(this, arguments); 3639 | return result === undefined ? this : result; 3640 | }; 3641 | }; 3642 | 3643 | }); 3644 | require.register("chai/lib/chai/utils/addProperty.js", function(exports, require, module){ 3645 | /*! 3646 | * Chai - addProperty utility 3647 | * Copyright(c) 2012-2014 Jake Luer 3648 | * MIT Licensed 3649 | */ 3650 | 3651 | /** 3652 | * ### addProperty (ctx, name, getter) 3653 | * 3654 | * Adds a property to the prototype of an object. 3655 | * 3656 | * utils.addProperty(chai.Assertion.prototype, 'foo', function () { 3657 | * var obj = utils.flag(this, 'object'); 3658 | * new chai.Assertion(obj).to.be.instanceof(Foo); 3659 | * }); 3660 | * 3661 | * Can also be accessed directly from `chai.Assertion`. 3662 | * 3663 | * chai.Assertion.addProperty('foo', fn); 3664 | * 3665 | * Then can be used as any other assertion. 3666 | * 3667 | * expect(myFoo).to.be.foo; 3668 | * 3669 | * @param {Object} ctx object to which the property is added 3670 | * @param {String} name of property to add 3671 | * @param {Function} getter function to be used for name 3672 | * @name addProperty 3673 | * @api public 3674 | */ 3675 | 3676 | module.exports = function (ctx, name, getter) { 3677 | Object.defineProperty(ctx, name, 3678 | { get: function () { 3679 | var result = getter.call(this); 3680 | return result === undefined ? this : result; 3681 | } 3682 | , configurable: true 3683 | }); 3684 | }; 3685 | 3686 | }); 3687 | require.register("chai/lib/chai/utils/flag.js", function(exports, require, module){ 3688 | /*! 3689 | * Chai - flag utility 3690 | * Copyright(c) 2012-2014 Jake Luer 3691 | * MIT Licensed 3692 | */ 3693 | 3694 | /** 3695 | * ### flag(object ,key, [value]) 3696 | * 3697 | * Get or set a flag value on an object. If a 3698 | * value is provided it will be set, else it will 3699 | * return the currently set value or `undefined` if 3700 | * the value is not set. 3701 | * 3702 | * utils.flag(this, 'foo', 'bar'); // setter 3703 | * utils.flag(this, 'foo'); // getter, returns `bar` 3704 | * 3705 | * @param {Object} object (constructed Assertion 3706 | * @param {String} key 3707 | * @param {Mixed} value (optional) 3708 | * @name flag 3709 | * @api private 3710 | */ 3711 | 3712 | module.exports = function (obj, key, value) { 3713 | var flags = obj.__flags || (obj.__flags = Object.create(null)); 3714 | if (arguments.length === 3) { 3715 | flags[key] = value; 3716 | } else { 3717 | return flags[key]; 3718 | } 3719 | }; 3720 | 3721 | }); 3722 | require.register("chai/lib/chai/utils/getActual.js", function(exports, require, module){ 3723 | /*! 3724 | * Chai - getActual utility 3725 | * Copyright(c) 2012-2014 Jake Luer 3726 | * MIT Licensed 3727 | */ 3728 | 3729 | /** 3730 | * # getActual(object, [actual]) 3731 | * 3732 | * Returns the `actual` value for an Assertion 3733 | * 3734 | * @param {Object} object (constructed Assertion) 3735 | * @param {Arguments} chai.Assertion.prototype.assert arguments 3736 | */ 3737 | 3738 | module.exports = function (obj, args) { 3739 | return args.length > 4 ? args[4] : obj._obj; 3740 | }; 3741 | 3742 | }); 3743 | require.register("chai/lib/chai/utils/getEnumerableProperties.js", function(exports, require, module){ 3744 | /*! 3745 | * Chai - getEnumerableProperties utility 3746 | * Copyright(c) 2012-2014 Jake Luer 3747 | * MIT Licensed 3748 | */ 3749 | 3750 | /** 3751 | * ### .getEnumerableProperties(object) 3752 | * 3753 | * This allows the retrieval of enumerable property names of an object, 3754 | * inherited or not. 3755 | * 3756 | * @param {Object} object 3757 | * @returns {Array} 3758 | * @name getEnumerableProperties 3759 | * @api public 3760 | */ 3761 | 3762 | module.exports = function getEnumerableProperties(object) { 3763 | var result = []; 3764 | for (var name in object) { 3765 | result.push(name); 3766 | } 3767 | return result; 3768 | }; 3769 | 3770 | }); 3771 | require.register("chai/lib/chai/utils/getMessage.js", function(exports, require, module){ 3772 | /*! 3773 | * Chai - message composition utility 3774 | * Copyright(c) 2012-2014 Jake Luer 3775 | * MIT Licensed 3776 | */ 3777 | 3778 | /*! 3779 | * Module dependancies 3780 | */ 3781 | 3782 | var flag = require('./flag') 3783 | , getActual = require('./getActual') 3784 | , inspect = require('./inspect') 3785 | , objDisplay = require('./objDisplay'); 3786 | 3787 | /** 3788 | * ### .getMessage(object, message, negateMessage) 3789 | * 3790 | * Construct the error message based on flags 3791 | * and template tags. Template tags will return 3792 | * a stringified inspection of the object referenced. 3793 | * 3794 | * Message template tags: 3795 | * - `#{this}` current asserted object 3796 | * - `#{act}` actual value 3797 | * - `#{exp}` expected value 3798 | * 3799 | * @param {Object} object (constructed Assertion) 3800 | * @param {Arguments} chai.Assertion.prototype.assert arguments 3801 | * @name getMessage 3802 | * @api public 3803 | */ 3804 | 3805 | module.exports = function (obj, args) { 3806 | var negate = flag(obj, 'negate') 3807 | , val = flag(obj, 'object') 3808 | , expected = args[3] 3809 | , actual = getActual(obj, args) 3810 | , msg = negate ? args[2] : args[1] 3811 | , flagMsg = flag(obj, 'message'); 3812 | 3813 | if(typeof msg === "function") msg = msg(); 3814 | msg = msg || ''; 3815 | msg = msg 3816 | .replace(/#{this}/g, objDisplay(val)) 3817 | .replace(/#{act}/g, objDisplay(actual)) 3818 | .replace(/#{exp}/g, objDisplay(expected)); 3819 | 3820 | return flagMsg ? flagMsg + ': ' + msg : msg; 3821 | }; 3822 | 3823 | }); 3824 | require.register("chai/lib/chai/utils/getName.js", function(exports, require, module){ 3825 | /*! 3826 | * Chai - getName utility 3827 | * Copyright(c) 2012-2014 Jake Luer 3828 | * MIT Licensed 3829 | */ 3830 | 3831 | /** 3832 | * # getName(func) 3833 | * 3834 | * Gets the name of a function, in a cross-browser way. 3835 | * 3836 | * @param {Function} a function (usually a constructor) 3837 | */ 3838 | 3839 | module.exports = function (func) { 3840 | if (func.name) return func.name; 3841 | 3842 | var match = /^\s?function ([^(]*)\(/.exec(func); 3843 | return match && match[1] ? match[1] : ""; 3844 | }; 3845 | 3846 | }); 3847 | require.register("chai/lib/chai/utils/getPathValue.js", function(exports, require, module){ 3848 | /*! 3849 | * Chai - getPathValue utility 3850 | * Copyright(c) 2012-2014 Jake Luer 3851 | * @see https://github.com/logicalparadox/filtr 3852 | * MIT Licensed 3853 | */ 3854 | 3855 | /** 3856 | * ### .getPathValue(path, object) 3857 | * 3858 | * This allows the retrieval of values in an 3859 | * object given a string path. 3860 | * 3861 | * var obj = { 3862 | * prop1: { 3863 | * arr: ['a', 'b', 'c'] 3864 | * , str: 'Hello' 3865 | * } 3866 | * , prop2: { 3867 | * arr: [ { nested: 'Universe' } ] 3868 | * , str: 'Hello again!' 3869 | * } 3870 | * } 3871 | * 3872 | * The following would be the results. 3873 | * 3874 | * getPathValue('prop1.str', obj); // Hello 3875 | * getPathValue('prop1.att[2]', obj); // b 3876 | * getPathValue('prop2.arr[0].nested', obj); // Universe 3877 | * 3878 | * @param {String} path 3879 | * @param {Object} object 3880 | * @returns {Object} value or `undefined` 3881 | * @name getPathValue 3882 | * @api public 3883 | */ 3884 | 3885 | var getPathValue = module.exports = function (path, obj) { 3886 | var parsed = parsePath(path); 3887 | return _getPathValue(parsed, obj); 3888 | }; 3889 | 3890 | /*! 3891 | * ## parsePath(path) 3892 | * 3893 | * Helper function used to parse string object 3894 | * paths. Use in conjunction with `_getPathValue`. 3895 | * 3896 | * var parsed = parsePath('myobject.property.subprop'); 3897 | * 3898 | * ### Paths: 3899 | * 3900 | * * Can be as near infinitely deep and nested 3901 | * * Arrays are also valid using the formal `myobject.document[3].property`. 3902 | * 3903 | * @param {String} path 3904 | * @returns {Object} parsed 3905 | * @api private 3906 | */ 3907 | 3908 | function parsePath (path) { 3909 | var str = path.replace(/\[/g, '.[') 3910 | , parts = str.match(/(\\\.|[^.]+?)+/g); 3911 | return parts.map(function (value) { 3912 | var re = /\[(\d+)\]$/ 3913 | , mArr = re.exec(value) 3914 | if (mArr) return { i: parseFloat(mArr[1]) }; 3915 | else return { p: value }; 3916 | }); 3917 | }; 3918 | 3919 | /*! 3920 | * ## _getPathValue(parsed, obj) 3921 | * 3922 | * Helper companion function for `.parsePath` that returns 3923 | * the value located at the parsed address. 3924 | * 3925 | * var value = getPathValue(parsed, obj); 3926 | * 3927 | * @param {Object} parsed definition from `parsePath`. 3928 | * @param {Object} object to search against 3929 | * @returns {Object|Undefined} value 3930 | * @api private 3931 | */ 3932 | 3933 | function _getPathValue (parsed, obj) { 3934 | var tmp = obj 3935 | , res; 3936 | for (var i = 0, l = parsed.length; i < l; i++) { 3937 | var part = parsed[i]; 3938 | if (tmp) { 3939 | if ('undefined' !== typeof part.p) 3940 | tmp = tmp[part.p]; 3941 | else if ('undefined' !== typeof part.i) 3942 | tmp = tmp[part.i]; 3943 | if (i == (l - 1)) res = tmp; 3944 | } else { 3945 | res = undefined; 3946 | } 3947 | } 3948 | return res; 3949 | }; 3950 | 3951 | }); 3952 | require.register("chai/lib/chai/utils/getProperties.js", function(exports, require, module){ 3953 | /*! 3954 | * Chai - getProperties utility 3955 | * Copyright(c) 2012-2014 Jake Luer 3956 | * MIT Licensed 3957 | */ 3958 | 3959 | /** 3960 | * ### .getProperties(object) 3961 | * 3962 | * This allows the retrieval of property names of an object, enumerable or not, 3963 | * inherited or not. 3964 | * 3965 | * @param {Object} object 3966 | * @returns {Array} 3967 | * @name getProperties 3968 | * @api public 3969 | */ 3970 | 3971 | module.exports = function getProperties(object) { 3972 | var result = Object.getOwnPropertyNames(subject); 3973 | 3974 | function addProperty(property) { 3975 | if (result.indexOf(property) === -1) { 3976 | result.push(property); 3977 | } 3978 | } 3979 | 3980 | var proto = Object.getPrototypeOf(subject); 3981 | while (proto !== null) { 3982 | Object.getOwnPropertyNames(proto).forEach(addProperty); 3983 | proto = Object.getPrototypeOf(proto); 3984 | } 3985 | 3986 | return result; 3987 | }; 3988 | 3989 | }); 3990 | require.register("chai/lib/chai/utils/index.js", function(exports, require, module){ 3991 | /*! 3992 | * chai 3993 | * Copyright(c) 2011 Jake Luer 3994 | * MIT Licensed 3995 | */ 3996 | 3997 | /*! 3998 | * Main exports 3999 | */ 4000 | 4001 | var exports = module.exports = {}; 4002 | 4003 | /*! 4004 | * test utility 4005 | */ 4006 | 4007 | exports.test = require('./test'); 4008 | 4009 | /*! 4010 | * type utility 4011 | */ 4012 | 4013 | exports.type = require('./type'); 4014 | 4015 | /*! 4016 | * message utility 4017 | */ 4018 | 4019 | exports.getMessage = require('./getMessage'); 4020 | 4021 | /*! 4022 | * actual utility 4023 | */ 4024 | 4025 | exports.getActual = require('./getActual'); 4026 | 4027 | /*! 4028 | * Inspect util 4029 | */ 4030 | 4031 | exports.inspect = require('./inspect'); 4032 | 4033 | /*! 4034 | * Object Display util 4035 | */ 4036 | 4037 | exports.objDisplay = require('./objDisplay'); 4038 | 4039 | /*! 4040 | * Flag utility 4041 | */ 4042 | 4043 | exports.flag = require('./flag'); 4044 | 4045 | /*! 4046 | * Flag transferring utility 4047 | */ 4048 | 4049 | exports.transferFlags = require('./transferFlags'); 4050 | 4051 | /*! 4052 | * Deep equal utility 4053 | */ 4054 | 4055 | exports.eql = require('deep-eql'); 4056 | 4057 | /*! 4058 | * Deep path value 4059 | */ 4060 | 4061 | exports.getPathValue = require('./getPathValue'); 4062 | 4063 | /*! 4064 | * Function name 4065 | */ 4066 | 4067 | exports.getName = require('./getName'); 4068 | 4069 | /*! 4070 | * add Property 4071 | */ 4072 | 4073 | exports.addProperty = require('./addProperty'); 4074 | 4075 | /*! 4076 | * add Method 4077 | */ 4078 | 4079 | exports.addMethod = require('./addMethod'); 4080 | 4081 | /*! 4082 | * overwrite Property 4083 | */ 4084 | 4085 | exports.overwriteProperty = require('./overwriteProperty'); 4086 | 4087 | /*! 4088 | * overwrite Method 4089 | */ 4090 | 4091 | exports.overwriteMethod = require('./overwriteMethod'); 4092 | 4093 | /*! 4094 | * Add a chainable method 4095 | */ 4096 | 4097 | exports.addChainableMethod = require('./addChainableMethod'); 4098 | 4099 | /*! 4100 | * Overwrite chainable method 4101 | */ 4102 | 4103 | exports.overwriteChainableMethod = require('./overwriteChainableMethod'); 4104 | 4105 | 4106 | }); 4107 | require.register("chai/lib/chai/utils/inspect.js", function(exports, require, module){ 4108 | // This is (almost) directly from Node.js utils 4109 | // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js 4110 | 4111 | var getName = require('./getName'); 4112 | var getProperties = require('./getProperties'); 4113 | var getEnumerableProperties = require('./getEnumerableProperties'); 4114 | 4115 | module.exports = inspect; 4116 | 4117 | /** 4118 | * Echos the value of a value. Trys to print the value out 4119 | * in the best way possible given the different types. 4120 | * 4121 | * @param {Object} obj The object to print out. 4122 | * @param {Boolean} showHidden Flag that shows hidden (not enumerable) 4123 | * properties of objects. 4124 | * @param {Number} depth Depth in which to descend in object. Default is 2. 4125 | * @param {Boolean} colors Flag to turn on ANSI escape codes to color the 4126 | * output. Default is false (no coloring). 4127 | */ 4128 | function inspect(obj, showHidden, depth, colors) { 4129 | var ctx = { 4130 | showHidden: showHidden, 4131 | seen: [], 4132 | stylize: function (str) { return str; } 4133 | }; 4134 | return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); 4135 | } 4136 | 4137 | // Returns true if object is a DOM element. 4138 | var isDOMElement = function (object) { 4139 | if (typeof HTMLElement === 'object') { 4140 | return object instanceof HTMLElement; 4141 | } else { 4142 | return object && 4143 | typeof object === 'object' && 4144 | object.nodeType === 1 && 4145 | typeof object.nodeName === 'string'; 4146 | } 4147 | }; 4148 | 4149 | function formatValue(ctx, value, recurseTimes) { 4150 | // Provide a hook for user-specified inspect functions. 4151 | // Check that value is an object with an inspect function on it 4152 | if (value && typeof value.inspect === 'function' && 4153 | // Filter out the util module, it's inspect function is special 4154 | value.inspect !== exports.inspect && 4155 | // Also filter out any prototype objects using the circular check. 4156 | !(value.constructor && value.constructor.prototype === value)) { 4157 | var ret = value.inspect(recurseTimes); 4158 | if (typeof ret !== 'string') { 4159 | ret = formatValue(ctx, ret, recurseTimes); 4160 | } 4161 | return ret; 4162 | } 4163 | 4164 | // Primitive types cannot have properties 4165 | var primitive = formatPrimitive(ctx, value); 4166 | if (primitive) { 4167 | return primitive; 4168 | } 4169 | 4170 | // If this is a DOM element, try to get the outer HTML. 4171 | if (isDOMElement(value)) { 4172 | if ('outerHTML' in value) { 4173 | return value.outerHTML; 4174 | // This value does not have an outerHTML attribute, 4175 | // it could still be an XML element 4176 | } else { 4177 | // Attempt to serialize it 4178 | try { 4179 | if (document.xmlVersion) { 4180 | var xmlSerializer = new XMLSerializer(); 4181 | return xmlSerializer.serializeToString(value); 4182 | } else { 4183 | // Firefox 11- do not support outerHTML 4184 | // It does, however, support innerHTML 4185 | // Use the following to render the element 4186 | var ns = "http://www.w3.org/1999/xhtml"; 4187 | var container = document.createElementNS(ns, '_'); 4188 | 4189 | container.appendChild(value.cloneNode(false)); 4190 | html = container.innerHTML 4191 | .replace('><', '>' + value.innerHTML + '<'); 4192 | container.innerHTML = ''; 4193 | return html; 4194 | } 4195 | } catch (err) { 4196 | // This could be a non-native DOM implementation, 4197 | // continue with the normal flow: 4198 | // printing the element as if it is an object. 4199 | } 4200 | } 4201 | } 4202 | 4203 | // Look up the keys of the object. 4204 | var visibleKeys = getEnumerableProperties(value); 4205 | var keys = ctx.showHidden ? getProperties(value) : visibleKeys; 4206 | 4207 | // Some type of object without properties can be shortcutted. 4208 | // In IE, errors have a single `stack` property, or if they are vanilla `Error`, 4209 | // a `stack` plus `description` property; ignore those for consistency. 4210 | if (keys.length === 0 || (isError(value) && ( 4211 | (keys.length === 1 && keys[0] === 'stack') || 4212 | (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') 4213 | ))) { 4214 | if (typeof value === 'function') { 4215 | var name = getName(value); 4216 | var nameSuffix = name ? ': ' + name : ''; 4217 | return ctx.stylize('[Function' + nameSuffix + ']', 'special'); 4218 | } 4219 | if (isRegExp(value)) { 4220 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 4221 | } 4222 | if (isDate(value)) { 4223 | return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); 4224 | } 4225 | if (isError(value)) { 4226 | return formatError(value); 4227 | } 4228 | } 4229 | 4230 | var base = '', array = false, braces = ['{', '}']; 4231 | 4232 | // Make Array say that they are Array 4233 | if (isArray(value)) { 4234 | array = true; 4235 | braces = ['[', ']']; 4236 | } 4237 | 4238 | // Make functions say that they are functions 4239 | if (typeof value === 'function') { 4240 | var name = getName(value); 4241 | var nameSuffix = name ? ': ' + name : ''; 4242 | base = ' [Function' + nameSuffix + ']'; 4243 | } 4244 | 4245 | // Make RegExps say that they are RegExps 4246 | if (isRegExp(value)) { 4247 | base = ' ' + RegExp.prototype.toString.call(value); 4248 | } 4249 | 4250 | // Make dates with properties first say the date 4251 | if (isDate(value)) { 4252 | base = ' ' + Date.prototype.toUTCString.call(value); 4253 | } 4254 | 4255 | // Make error with message first say the error 4256 | if (isError(value)) { 4257 | return formatError(value); 4258 | } 4259 | 4260 | if (keys.length === 0 && (!array || value.length == 0)) { 4261 | return braces[0] + base + braces[1]; 4262 | } 4263 | 4264 | if (recurseTimes < 0) { 4265 | if (isRegExp(value)) { 4266 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 4267 | } else { 4268 | return ctx.stylize('[Object]', 'special'); 4269 | } 4270 | } 4271 | 4272 | ctx.seen.push(value); 4273 | 4274 | var output; 4275 | if (array) { 4276 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 4277 | } else { 4278 | output = keys.map(function(key) { 4279 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 4280 | }); 4281 | } 4282 | 4283 | ctx.seen.pop(); 4284 | 4285 | return reduceToSingleString(output, base, braces); 4286 | } 4287 | 4288 | 4289 | function formatPrimitive(ctx, value) { 4290 | switch (typeof value) { 4291 | case 'undefined': 4292 | return ctx.stylize('undefined', 'undefined'); 4293 | 4294 | case 'string': 4295 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 4296 | .replace(/'/g, "\\'") 4297 | .replace(/\\"/g, '"') + '\''; 4298 | return ctx.stylize(simple, 'string'); 4299 | 4300 | case 'number': 4301 | return ctx.stylize('' + value, 'number'); 4302 | 4303 | case 'boolean': 4304 | return ctx.stylize('' + value, 'boolean'); 4305 | } 4306 | // For some reason typeof null is "object", so special case here. 4307 | if (value === null) { 4308 | return ctx.stylize('null', 'null'); 4309 | } 4310 | } 4311 | 4312 | 4313 | function formatError(value) { 4314 | return '[' + Error.prototype.toString.call(value) + ']'; 4315 | } 4316 | 4317 | 4318 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 4319 | var output = []; 4320 | for (var i = 0, l = value.length; i < l; ++i) { 4321 | if (Object.prototype.hasOwnProperty.call(value, String(i))) { 4322 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 4323 | String(i), true)); 4324 | } else { 4325 | output.push(''); 4326 | } 4327 | } 4328 | keys.forEach(function(key) { 4329 | if (!key.match(/^\d+$/)) { 4330 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 4331 | key, true)); 4332 | } 4333 | }); 4334 | return output; 4335 | } 4336 | 4337 | 4338 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 4339 | var name, str; 4340 | if (value.__lookupGetter__) { 4341 | if (value.__lookupGetter__(key)) { 4342 | if (value.__lookupSetter__(key)) { 4343 | str = ctx.stylize('[Getter/Setter]', 'special'); 4344 | } else { 4345 | str = ctx.stylize('[Getter]', 'special'); 4346 | } 4347 | } else { 4348 | if (value.__lookupSetter__(key)) { 4349 | str = ctx.stylize('[Setter]', 'special'); 4350 | } 4351 | } 4352 | } 4353 | if (visibleKeys.indexOf(key) < 0) { 4354 | name = '[' + key + ']'; 4355 | } 4356 | if (!str) { 4357 | if (ctx.seen.indexOf(value[key]) < 0) { 4358 | if (recurseTimes === null) { 4359 | str = formatValue(ctx, value[key], null); 4360 | } else { 4361 | str = formatValue(ctx, value[key], recurseTimes - 1); 4362 | } 4363 | if (str.indexOf('\n') > -1) { 4364 | if (array) { 4365 | str = str.split('\n').map(function(line) { 4366 | return ' ' + line; 4367 | }).join('\n').substr(2); 4368 | } else { 4369 | str = '\n' + str.split('\n').map(function(line) { 4370 | return ' ' + line; 4371 | }).join('\n'); 4372 | } 4373 | } 4374 | } else { 4375 | str = ctx.stylize('[Circular]', 'special'); 4376 | } 4377 | } 4378 | if (typeof name === 'undefined') { 4379 | if (array && key.match(/^\d+$/)) { 4380 | return str; 4381 | } 4382 | name = JSON.stringify('' + key); 4383 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 4384 | name = name.substr(1, name.length - 2); 4385 | name = ctx.stylize(name, 'name'); 4386 | } else { 4387 | name = name.replace(/'/g, "\\'") 4388 | .replace(/\\"/g, '"') 4389 | .replace(/(^"|"$)/g, "'"); 4390 | name = ctx.stylize(name, 'string'); 4391 | } 4392 | } 4393 | 4394 | return name + ': ' + str; 4395 | } 4396 | 4397 | 4398 | function reduceToSingleString(output, base, braces) { 4399 | var numLinesEst = 0; 4400 | var length = output.reduce(function(prev, cur) { 4401 | numLinesEst++; 4402 | if (cur.indexOf('\n') >= 0) numLinesEst++; 4403 | return prev + cur.length + 1; 4404 | }, 0); 4405 | 4406 | if (length > 60) { 4407 | return braces[0] + 4408 | (base === '' ? '' : base + '\n ') + 4409 | ' ' + 4410 | output.join(',\n ') + 4411 | ' ' + 4412 | braces[1]; 4413 | } 4414 | 4415 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 4416 | } 4417 | 4418 | function isArray(ar) { 4419 | return Array.isArray(ar) || 4420 | (typeof ar === 'object' && objectToString(ar) === '[object Array]'); 4421 | } 4422 | 4423 | function isRegExp(re) { 4424 | return typeof re === 'object' && objectToString(re) === '[object RegExp]'; 4425 | } 4426 | 4427 | function isDate(d) { 4428 | return typeof d === 'object' && objectToString(d) === '[object Date]'; 4429 | } 4430 | 4431 | function isError(e) { 4432 | return typeof e === 'object' && objectToString(e) === '[object Error]'; 4433 | } 4434 | 4435 | function objectToString(o) { 4436 | return Object.prototype.toString.call(o); 4437 | } 4438 | 4439 | }); 4440 | require.register("chai/lib/chai/utils/objDisplay.js", function(exports, require, module){ 4441 | /*! 4442 | * Chai - flag utility 4443 | * Copyright(c) 2012-2014 Jake Luer 4444 | * MIT Licensed 4445 | */ 4446 | 4447 | /*! 4448 | * Module dependancies 4449 | */ 4450 | 4451 | var inspect = require('./inspect'); 4452 | var config = require('../config'); 4453 | 4454 | /** 4455 | * ### .objDisplay (object) 4456 | * 4457 | * Determines if an object or an array matches 4458 | * criteria to be inspected in-line for error 4459 | * messages or should be truncated. 4460 | * 4461 | * @param {Mixed} javascript object to inspect 4462 | * @name objDisplay 4463 | * @api public 4464 | */ 4465 | 4466 | module.exports = function (obj) { 4467 | var str = inspect(obj) 4468 | , type = Object.prototype.toString.call(obj); 4469 | 4470 | if (config.truncateThreshold && str.length >= config.truncateThreshold) { 4471 | if (type === '[object Function]') { 4472 | return !obj.name || obj.name === '' 4473 | ? '[Function]' 4474 | : '[Function: ' + obj.name + ']'; 4475 | } else if (type === '[object Array]') { 4476 | return '[ Array(' + obj.length + ') ]'; 4477 | } else if (type === '[object Object]') { 4478 | var keys = Object.keys(obj) 4479 | , kstr = keys.length > 2 4480 | ? keys.splice(0, 2).join(', ') + ', ...' 4481 | : keys.join(', '); 4482 | return '{ Object (' + kstr + ') }'; 4483 | } else { 4484 | return str; 4485 | } 4486 | } else { 4487 | return str; 4488 | } 4489 | }; 4490 | 4491 | }); 4492 | require.register("chai/lib/chai/utils/overwriteMethod.js", function(exports, require, module){ 4493 | /*! 4494 | * Chai - overwriteMethod utility 4495 | * Copyright(c) 2012-2014 Jake Luer 4496 | * MIT Licensed 4497 | */ 4498 | 4499 | /** 4500 | * ### overwriteMethod (ctx, name, fn) 4501 | * 4502 | * Overwites an already existing method and provides 4503 | * access to previous function. Must return function 4504 | * to be used for name. 4505 | * 4506 | * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { 4507 | * return function (str) { 4508 | * var obj = utils.flag(this, 'object'); 4509 | * if (obj instanceof Foo) { 4510 | * new chai.Assertion(obj.value).to.equal(str); 4511 | * } else { 4512 | * _super.apply(this, arguments); 4513 | * } 4514 | * } 4515 | * }); 4516 | * 4517 | * Can also be accessed directly from `chai.Assertion`. 4518 | * 4519 | * chai.Assertion.overwriteMethod('foo', fn); 4520 | * 4521 | * Then can be used as any other assertion. 4522 | * 4523 | * expect(myFoo).to.equal('bar'); 4524 | * 4525 | * @param {Object} ctx object whose method is to be overwritten 4526 | * @param {String} name of method to overwrite 4527 | * @param {Function} method function that returns a function to be used for name 4528 | * @name overwriteMethod 4529 | * @api public 4530 | */ 4531 | 4532 | module.exports = function (ctx, name, method) { 4533 | var _method = ctx[name] 4534 | , _super = function () { return this; }; 4535 | 4536 | if (_method && 'function' === typeof _method) 4537 | _super = _method; 4538 | 4539 | ctx[name] = function () { 4540 | var result = method(_super).apply(this, arguments); 4541 | return result === undefined ? this : result; 4542 | } 4543 | }; 4544 | 4545 | }); 4546 | require.register("chai/lib/chai/utils/overwriteProperty.js", function(exports, require, module){ 4547 | /*! 4548 | * Chai - overwriteProperty utility 4549 | * Copyright(c) 2012-2014 Jake Luer 4550 | * MIT Licensed 4551 | */ 4552 | 4553 | /** 4554 | * ### overwriteProperty (ctx, name, fn) 4555 | * 4556 | * Overwites an already existing property getter and provides 4557 | * access to previous value. Must return function to use as getter. 4558 | * 4559 | * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { 4560 | * return function () { 4561 | * var obj = utils.flag(this, 'object'); 4562 | * if (obj instanceof Foo) { 4563 | * new chai.Assertion(obj.name).to.equal('bar'); 4564 | * } else { 4565 | * _super.call(this); 4566 | * } 4567 | * } 4568 | * }); 4569 | * 4570 | * 4571 | * Can also be accessed directly from `chai.Assertion`. 4572 | * 4573 | * chai.Assertion.overwriteProperty('foo', fn); 4574 | * 4575 | * Then can be used as any other assertion. 4576 | * 4577 | * expect(myFoo).to.be.ok; 4578 | * 4579 | * @param {Object} ctx object whose property is to be overwritten 4580 | * @param {String} name of property to overwrite 4581 | * @param {Function} getter function that returns a getter function to be used for name 4582 | * @name overwriteProperty 4583 | * @api public 4584 | */ 4585 | 4586 | module.exports = function (ctx, name, getter) { 4587 | var _get = Object.getOwnPropertyDescriptor(ctx, name) 4588 | , _super = function () {}; 4589 | 4590 | if (_get && 'function' === typeof _get.get) 4591 | _super = _get.get 4592 | 4593 | Object.defineProperty(ctx, name, 4594 | { get: function () { 4595 | var result = getter(_super).call(this); 4596 | return result === undefined ? this : result; 4597 | } 4598 | , configurable: true 4599 | }); 4600 | }; 4601 | 4602 | }); 4603 | require.register("chai/lib/chai/utils/overwriteChainableMethod.js", function(exports, require, module){ 4604 | /*! 4605 | * Chai - overwriteChainableMethod utility 4606 | * Copyright(c) 2012-2014 Jake Luer 4607 | * MIT Licensed 4608 | */ 4609 | 4610 | /** 4611 | * ### overwriteChainableMethod (ctx, name, fn) 4612 | * 4613 | * Overwites an already existing chainable method 4614 | * and provides access to the previous function or 4615 | * property. Must return functions to be used for 4616 | * name. 4617 | * 4618 | * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', 4619 | * function (_super) { 4620 | * } 4621 | * , function (_super) { 4622 | * } 4623 | * ); 4624 | * 4625 | * Can also be accessed directly from `chai.Assertion`. 4626 | * 4627 | * chai.Assertion.overwriteChainableMethod('foo', fn, fn); 4628 | * 4629 | * Then can be used as any other assertion. 4630 | * 4631 | * expect(myFoo).to.have.length(3); 4632 | * expect(myFoo).to.have.length.above(3); 4633 | * 4634 | * @param {Object} ctx object whose method / property is to be overwritten 4635 | * @param {String} name of method / property to overwrite 4636 | * @param {Function} method function that returns a function to be used for name 4637 | * @param {Function} chainingBehavior function that returns a function to be used for property 4638 | * @name overwriteChainableMethod 4639 | * @api public 4640 | */ 4641 | 4642 | module.exports = function (ctx, name, method, chainingBehavior) { 4643 | var chainableBehavior = ctx.__methods[name]; 4644 | 4645 | var _chainingBehavior = chainableBehavior.chainingBehavior; 4646 | chainableBehavior.chainingBehavior = function () { 4647 | var result = chainingBehavior(_chainingBehavior).call(this); 4648 | return result === undefined ? this : result; 4649 | }; 4650 | 4651 | var _method = chainableBehavior.method; 4652 | chainableBehavior.method = function () { 4653 | var result = method(_method).apply(this, arguments); 4654 | return result === undefined ? this : result; 4655 | }; 4656 | }; 4657 | 4658 | }); 4659 | require.register("chai/lib/chai/utils/test.js", function(exports, require, module){ 4660 | /*! 4661 | * Chai - test utility 4662 | * Copyright(c) 2012-2014 Jake Luer 4663 | * MIT Licensed 4664 | */ 4665 | 4666 | /*! 4667 | * Module dependancies 4668 | */ 4669 | 4670 | var flag = require('./flag'); 4671 | 4672 | /** 4673 | * # test(object, expression) 4674 | * 4675 | * Test and object for expression. 4676 | * 4677 | * @param {Object} object (constructed Assertion) 4678 | * @param {Arguments} chai.Assertion.prototype.assert arguments 4679 | */ 4680 | 4681 | module.exports = function (obj, args) { 4682 | var negate = flag(obj, 'negate') 4683 | , expr = args[0]; 4684 | return negate ? !expr : expr; 4685 | }; 4686 | 4687 | }); 4688 | require.register("chai/lib/chai/utils/transferFlags.js", function(exports, require, module){ 4689 | /*! 4690 | * Chai - transferFlags utility 4691 | * Copyright(c) 2012-2014 Jake Luer 4692 | * MIT Licensed 4693 | */ 4694 | 4695 | /** 4696 | * ### transferFlags(assertion, object, includeAll = true) 4697 | * 4698 | * Transfer all the flags for `assertion` to `object`. If 4699 | * `includeAll` is set to `false`, then the base Chai 4700 | * assertion flags (namely `object`, `ssfi`, and `message`) 4701 | * will not be transferred. 4702 | * 4703 | * 4704 | * var newAssertion = new Assertion(); 4705 | * utils.transferFlags(assertion, newAssertion); 4706 | * 4707 | * var anotherAsseriton = new Assertion(myObj); 4708 | * utils.transferFlags(assertion, anotherAssertion, false); 4709 | * 4710 | * @param {Assertion} assertion the assertion to transfer the flags from 4711 | * @param {Object} object the object to transfer the flags too; usually a new assertion 4712 | * @param {Boolean} includeAll 4713 | * @name getAllFlags 4714 | * @api private 4715 | */ 4716 | 4717 | module.exports = function (assertion, object, includeAll) { 4718 | var flags = assertion.__flags || (assertion.__flags = Object.create(null)); 4719 | 4720 | if (!object.__flags) { 4721 | object.__flags = Object.create(null); 4722 | } 4723 | 4724 | includeAll = arguments.length === 3 ? includeAll : true; 4725 | 4726 | for (var flag in flags) { 4727 | if (includeAll || 4728 | (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { 4729 | object.__flags[flag] = flags[flag]; 4730 | } 4731 | } 4732 | }; 4733 | 4734 | }); 4735 | require.register("chai/lib/chai/utils/type.js", function(exports, require, module){ 4736 | /*! 4737 | * Chai - type utility 4738 | * Copyright(c) 2012-2014 Jake Luer 4739 | * MIT Licensed 4740 | */ 4741 | 4742 | /*! 4743 | * Detectable javascript natives 4744 | */ 4745 | 4746 | var natives = { 4747 | '[object Arguments]': 'arguments' 4748 | , '[object Array]': 'array' 4749 | , '[object Date]': 'date' 4750 | , '[object Function]': 'function' 4751 | , '[object Number]': 'number' 4752 | , '[object RegExp]': 'regexp' 4753 | , '[object String]': 'string' 4754 | }; 4755 | 4756 | /** 4757 | * ### type(object) 4758 | * 4759 | * Better implementation of `typeof` detection that can 4760 | * be used cross-browser. Handles the inconsistencies of 4761 | * Array, `null`, and `undefined` detection. 4762 | * 4763 | * utils.type({}) // 'object' 4764 | * utils.type(null) // `null' 4765 | * utils.type(undefined) // `undefined` 4766 | * utils.type([]) // `array` 4767 | * 4768 | * @param {Mixed} object to detect type of 4769 | * @name type 4770 | * @api private 4771 | */ 4772 | 4773 | module.exports = function (obj) { 4774 | var str = Object.prototype.toString.call(obj); 4775 | if (natives[str]) return natives[str]; 4776 | if (obj === null) return 'null'; 4777 | if (obj === undefined) return 'undefined'; 4778 | if (obj === Object(obj)) return 'object'; 4779 | return typeof obj; 4780 | }; 4781 | 4782 | }); 4783 | 4784 | 4785 | 4786 | 4787 | require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js"); 4788 | require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js"); 4789 | require.alias("chaijs-assertion-error/index.js", "assertion-error/index.js"); 4790 | require.alias("chaijs-assertion-error/index.js", "chaijs-assertion-error/index.js"); 4791 | require.alias("chaijs-deep-eql/lib/eql.js", "chai/deps/deep-eql/lib/eql.js"); 4792 | require.alias("chaijs-deep-eql/lib/eql.js", "chai/deps/deep-eql/index.js"); 4793 | require.alias("chaijs-deep-eql/lib/eql.js", "deep-eql/index.js"); 4794 | require.alias("chaijs-type-detect/lib/type.js", "chaijs-deep-eql/deps/type-detect/lib/type.js"); 4795 | require.alias("chaijs-type-detect/lib/type.js", "chaijs-deep-eql/deps/type-detect/index.js"); 4796 | require.alias("chaijs-type-detect/lib/type.js", "chaijs-type-detect/index.js"); 4797 | require.alias("chaijs-deep-eql/lib/eql.js", "chaijs-deep-eql/index.js"); 4798 | require.alias("chai/index.js", "chai/index.js");if (typeof exports == "object") { 4799 | module.exports = require("chai"); 4800 | } else if (typeof define == "function" && define.amd) { 4801 | define([], function(){ return require("chai"); }); 4802 | } else { 4803 | this["chai"] = require("chai"); 4804 | }})(); -------------------------------------------------------------------------------- /test/mocha/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, 13 | #mocha li { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | #mocha ul { 19 | list-style: none; 20 | } 21 | 22 | #mocha h1, 23 | #mocha h2 { 24 | margin: 0; 25 | } 26 | 27 | #mocha h1 { 28 | margin-top: 15px; 29 | font-size: 1em; 30 | font-weight: 200; 31 | } 32 | 33 | #mocha h1 a { 34 | text-decoration: none; 35 | color: inherit; 36 | } 37 | 38 | #mocha h1 a:hover { 39 | text-decoration: underline; 40 | } 41 | 42 | #mocha .suite .suite h1 { 43 | margin-top: 0; 44 | font-size: .8em; 45 | } 46 | 47 | #mocha .hidden { 48 | display: none; 49 | } 50 | 51 | #mocha h2 { 52 | font-size: 12px; 53 | font-weight: normal; 54 | cursor: pointer; 55 | } 56 | 57 | #mocha .suite { 58 | margin-left: 15px; 59 | } 60 | 61 | #mocha .test { 62 | margin-left: 15px; 63 | overflow: hidden; 64 | } 65 | 66 | #mocha .test.pending:hover h2::after { 67 | content: '(pending)'; 68 | font-family: arial, sans-serif; 69 | } 70 | 71 | #mocha .test.pass.medium .duration { 72 | background: #c09853; 73 | } 74 | 75 | #mocha .test.pass.slow .duration { 76 | background: #b94a48; 77 | } 78 | 79 | #mocha .test.pass::before { 80 | content: '✓'; 81 | font-size: 12px; 82 | display: block; 83 | float: left; 84 | margin-right: 5px; 85 | color: #00d6b2; 86 | } 87 | 88 | #mocha .test.pass .duration { 89 | font-size: 9px; 90 | margin-left: 5px; 91 | padding: 2px 5px; 92 | color: #fff; 93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 96 | -webkit-border-radius: 5px; 97 | -moz-border-radius: 5px; 98 | -ms-border-radius: 5px; 99 | -o-border-radius: 5px; 100 | border-radius: 5px; 101 | } 102 | 103 | #mocha .test.pass.fast .duration { 104 | display: none; 105 | } 106 | 107 | #mocha .test.pending { 108 | color: #0b97c4; 109 | } 110 | 111 | #mocha .test.pending::before { 112 | content: '◦'; 113 | color: #0b97c4; 114 | } 115 | 116 | #mocha .test.fail { 117 | color: #c00; 118 | } 119 | 120 | #mocha .test.fail pre { 121 | color: black; 122 | } 123 | 124 | #mocha .test.fail::before { 125 | content: '✖'; 126 | font-size: 12px; 127 | display: block; 128 | float: left; 129 | margin-right: 5px; 130 | color: #c00; 131 | } 132 | 133 | #mocha .test pre.error { 134 | color: #c00; 135 | max-height: 300px; 136 | overflow: auto; 137 | } 138 | 139 | /** 140 | * (1): approximate for browsers not supporting calc 141 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) 142 | * ^^ seriously 143 | */ 144 | #mocha .test pre { 145 | display: block; 146 | float: left; 147 | clear: left; 148 | font: 12px/1.5 monaco, monospace; 149 | margin: 5px; 150 | padding: 15px; 151 | border: 1px solid #eee; 152 | max-width: 85%; /*(1)*/ 153 | max-width: calc(100% - 42px); /*(2)*/ 154 | word-wrap: break-word; 155 | border-bottom-color: #ddd; 156 | -webkit-border-radius: 3px; 157 | -webkit-box-shadow: 0 1px 3px #eee; 158 | -moz-border-radius: 3px; 159 | -moz-box-shadow: 0 1px 3px #eee; 160 | border-radius: 3px; 161 | } 162 | 163 | #mocha .test h2 { 164 | position: relative; 165 | } 166 | 167 | #mocha .test a.replay { 168 | position: absolute; 169 | top: 3px; 170 | right: 0; 171 | text-decoration: none; 172 | vertical-align: middle; 173 | display: block; 174 | width: 15px; 175 | height: 15px; 176 | line-height: 15px; 177 | text-align: center; 178 | background: #eee; 179 | font-size: 15px; 180 | -moz-border-radius: 15px; 181 | border-radius: 15px; 182 | -webkit-transition: opacity 200ms; 183 | -moz-transition: opacity 200ms; 184 | transition: opacity 200ms; 185 | opacity: 0.3; 186 | color: #888; 187 | } 188 | 189 | #mocha .test:hover a.replay { 190 | opacity: 1; 191 | } 192 | 193 | #mocha-report.pass .test.fail { 194 | display: none; 195 | } 196 | 197 | #mocha-report.fail .test.pass { 198 | display: none; 199 | } 200 | 201 | #mocha-report.pending .test.pass, 202 | #mocha-report.pending .test.fail { 203 | display: none; 204 | } 205 | #mocha-report.pending .test.pass.pending { 206 | display: block; 207 | } 208 | 209 | #mocha-error { 210 | color: #c00; 211 | font-size: 1.5em; 212 | font-weight: 100; 213 | letter-spacing: 1px; 214 | } 215 | 216 | #mocha-stats { 217 | position: fixed; 218 | top: 15px; 219 | right: 10px; 220 | font-size: 12px; 221 | margin: 0; 222 | color: #888; 223 | z-index: 1; 224 | } 225 | 226 | #mocha-stats .progress { 227 | float: right; 228 | padding-top: 0; 229 | } 230 | 231 | #mocha-stats em { 232 | color: black; 233 | } 234 | 235 | #mocha-stats a { 236 | text-decoration: none; 237 | color: inherit; 238 | } 239 | 240 | #mocha-stats a:hover { 241 | border-bottom: 1px solid #eee; 242 | } 243 | 244 | #mocha-stats li { 245 | display: inline-block; 246 | margin: 0 5px; 247 | list-style: none; 248 | padding-top: 11px; 249 | } 250 | 251 | #mocha-stats canvas { 252 | width: 40px; 253 | height: 40px; 254 | } 255 | 256 | #mocha code .comment { color: #ddd; } 257 | #mocha code .init { color: #2f6fad; } 258 | #mocha code .string { color: #5890ad; } 259 | #mocha code .keyword { color: #8a6343; } 260 | #mocha code .number { color: #2f6fad; } 261 | 262 | @media screen and (max-device-width: 480px) { 263 | #mocha { 264 | margin: 60px 0px; 265 | } 266 | 267 | #mocha #stats { 268 | position: absolute; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /test/test-runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | var expect = chai.expect; 2 | 3 | describe('Render-slicer', function() { 4 | 5 | function range(n){ 6 | return Array.apply(null, Array(n)).map(function(d, i){ return i; }); 7 | } 8 | 9 | var data; 10 | 11 | before(function() { 12 | data = range(40); 13 | }); 14 | 15 | after(function() { 16 | data = null; 17 | }); 18 | 19 | it('properly wraps a function', function() { 20 | var queuedFunc = renderSlicer(function(){ }); 21 | queuedFunc(data); 22 | }); 23 | 24 | it('calls the function for every data point', function(done) { 25 | var count = 0; 26 | var queuedFunc = renderSlicer(function(){ 27 | count++; 28 | if(count === data.length){ 29 | expect(count).to.equal(40); 30 | done(); 31 | } 32 | }); 33 | queuedFunc(data); 34 | }); 35 | 36 | it('passes the data point to the wrapped function', function(done) { 37 | var count = 0; 38 | var queuedFunc = renderSlicer(function(d){ 39 | expect(d).to.equal(count); 40 | count++; 41 | if(count === data.length) done(); 42 | }); 43 | queuedFunc(data); 44 | }); 45 | 46 | it('can pass an array of objects as data point', function(done) { 47 | var dataObject = [{key: 'a', value: 0}, {key: 'b', value: 1}] 48 | var count = 0; 49 | var queuedFunc = renderSlicer(function(d){ 50 | expect(d.value).to.equal(count); 51 | count++; 52 | if(count === dataObject.length) done(); 53 | }); 54 | queuedFunc(dataObject); 55 | }); 56 | 57 | it('calls onDone() when finished', function(done) { 58 | var queuedFunc = renderSlicer(function(){ }) 59 | .onDone(function(){ 60 | expect(queuedFunc.remaining()).to.equal(0); 61 | done(); 62 | }); 63 | queuedFunc(data); 64 | }); 65 | 66 | it('calls onChunkDone() when a chunk is finished', function(done) { 67 | var queuedFunc = renderSlicer(function(){ }) 68 | .onChunkDone(function(d){ 69 | expect(queuedFunc.remaining()).to.equal(0); 70 | done(); 71 | }); 72 | queuedFunc(data); 73 | }); 74 | 75 | it('uses a default chunk size of 1000', function(done) { 76 | var data = range(1000); 77 | var count = 0; 78 | var queuedFunc = renderSlicer(function(){ }) 79 | .onChunkDone(function(d){ 80 | count++; 81 | expect(count).to.equal(1); 82 | }); 83 | queuedFunc(data); 84 | 85 | queuedFunc = renderSlicer(function(){ }) 86 | .onChunkDone(function(d){ 87 | count++; 88 | if(count === 2) done(); 89 | }); 90 | data = range(1001); 91 | queuedFunc(data); 92 | }); 93 | 94 | it('sets the chunk size, number of data entries to be rendered each frame', function(done) { 95 | var count = 0; 96 | var queuedFunc = renderSlicer(function(){ }) 97 | .rate(2) 98 | .onChunkDone(function(d){ 99 | count++; 100 | if(count === data.length / 2) done(); 101 | }); 102 | queuedFunc(data); 103 | }); 104 | 105 | it('gets the chunk size', function() { 106 | var queuedFunc = renderSlicer(function(){ }) 107 | .rate(2); 108 | expect(queuedFunc.rate()).to.equal(2); 109 | }); 110 | 111 | it('can use remaining() to calculate progress percentage', function(done) { 112 | var count = 0; 113 | var expectedProgress = [25, 50, 75, 100]; 114 | var queuedFunc = renderSlicer(function(){ }) 115 | .rate(10) 116 | .onChunkDone(function(d){ 117 | var percentageRemaining = 100 - (queuedFunc.remaining() / data.length) * 100; 118 | expect(percentageRemaining).to.equal(expectedProgress[count]); 119 | count++; 120 | if(percentageRemaining === 100) done(); 121 | }); 122 | queuedFunc(data); 123 | }); 124 | 125 | it('can use count() to calculate progress percentage', function(done) { 126 | var queuedFunc = renderSlicer(function(){ }) 127 | .rate(10) 128 | .onFrameDone(function(){ 129 | console.log(queuedFunc.count(), queuedFunc.remaining()); 130 | var progress = queuedFunc.count() / data.length * 100; 131 | if(progress === 100){ 132 | done(); 133 | } 134 | }); 135 | queuedFunc(data); 136 | }); 137 | 138 | it('stops and replaces the current queue when called with new data', function(done) { 139 | var count = 0; 140 | var queuedFunc = renderSlicer(function(){ }) 141 | .rate(10) 142 | .onChunkDone(function(){ 143 | count++; 144 | if(queuedFunc.remaining() === 0){ 145 | expect(count).to.equal(2); 146 | done() 147 | } 148 | }); 149 | queuedFunc(data); 150 | queuedFunc(range(5)) 151 | }); 152 | 153 | it('stops the current queue using invalidate()', function(done) { 154 | var count = 0; 155 | var queuedFunc = renderSlicer(function(){ }) 156 | .rate(10) 157 | .onChunkDone(function(){ 158 | count++; 159 | if(queuedFunc.remaining() === 30){ 160 | expect(count).to.equal(1); 161 | done() 162 | } 163 | }); 164 | queuedFunc(data); 165 | queuedFunc.invalidate(); 166 | }); 167 | 168 | it('calls onStart() before the first render', function(done) { 169 | var isStarted = false; 170 | var queuedFunc = renderSlicer(function(){ }) 171 | .onStart(function(){ 172 | isStarted = true; 173 | }) 174 | .onFrameDone(function(){ 175 | expect(isStarted).to.be.true; 176 | done() 177 | }); 178 | queuedFunc(data); 179 | }); 180 | 181 | it('adds new data and continue rendering', function(done) { 182 | var count = 0; 183 | var queuedFunc = renderSlicer(function(){ }) 184 | .onFrameDone(function(){ 185 | count++; 186 | if(count > 40) done(); 187 | }); 188 | queuedFunc(data); 189 | queuedFunc.add([40, 41]); 190 | }); 191 | 192 | }); --------------------------------------------------------------------------------