├── README.md ├── callbacks └── callbackExercises.md ├── closures └── closureExercises.md ├── scope ├── SpecRunner.html ├── functions.js ├── lib │ ├── chai │ │ └── chai.js │ └── mocha │ │ ├── mocha.css │ │ └── mocha.js └── scopeExercises.md ├── underscore-extra-credit └── underscoreExercises.md └── underscore-loops └── callbackExercises.md /README.md: -------------------------------------------------------------------------------- 1 | # JSFundamentals Course Description 2 | 3 | Come here to solidify your understanding of functions and get started with functional programming in JavaScript. This is a highly interactive course that uses exercises and projects to drive home these JS Fundamentals. You will finish this course with deep knowledge on one of the most important aspects of the language: functions. 4 | 5 | 6 | ## Goals of this course 7 | 8 | The goal of the JavaScript Fundamentals part 1 and 2 is to give technical foundation and support for those who have been learning JavaScript for a couple of months, so that they will have reached a level required for the Hack Reactor admission's interviews. 9 | 10 | *IMPORTANT*: completion of the HRJR courses is no guarantee of admission, nor has any influence in the admissions process. 11 | 12 | It is our goal, however, that students who successfully complete the HRJR series will have covered all JavaScript topics necessary for the interview. 13 | 14 | If Hack Reactor takes people from 60 to 120 in web development, then Hack Reactor Junior takes people from 10 to 60 ('coz we don't teach variables and the like). 15 | 16 | ## Prerequisites 17 | 18 | It is recommended that students take JS Fundamentals: Objects, Arrays and Functions prior to this course; however it is not required. Students should have 3-5 months experience with JavaScript and programming. Students should understand and be familiar with variables, if/else statements, loops, objects, arrays and the most basic of JavaScript syntax. 19 | 20 | ## Textbook 21 | 22 | No textbook is required for this course. All materials are included in this github repo. 23 | 24 | ## Technical requirements 25 | 26 | Laptop, Chrome browser and a text editor. We recommend Sublime Text 3 for this course because it's fast, lightweight and you can run your JavaScript files in its console with Node. 27 | 28 | 29 | 30 | ## Resources 31 | 32 | **Scope and Closure:** http://speakingjs.com/es5/ch16.html 33 | -------------------------------------------------------------------------------- /callbacks/callbackExercises.md: -------------------------------------------------------------------------------- 1 | # Callback Exercises 2 | 3 | 1. Write a function, `funcCaller`, that takes a `func` (a function) and an `arg` (any data type). The function returns the `func` called with `arg`(as an argument). 4 | 5 | 1. Write a function, `firstVal`, that takes an array, `arr`, and a function, `func`, and calls `func` with the first index of the `arr`, the index # and the whole array. 6 | 7 | 1. Change `firstVal` to work not only with arrays but also objects. Since objects are not ordered, you can use any key-value pair on the object. 8 | 9 | 1. [Extra Credit] Write a function, `once`, (see: http://underscorejs.org/#once) that takes a function and returns a version of that function which can only be called once. [Hint: you need a closure] 10 | You probably don't want to be able to double charge someone's credit card. Here is an example of how to use it: 11 | ```javascript 12 | var chargeCreditCard = function(num, price){ 13 | //charges credit card for a certain price 14 | }; 15 | var processPaymentOnce = once(chargeCreditCard); 16 | processPaymentOnce(123456789012, 200); 17 | ``` 18 | -------------------------------------------------------------------------------- /closures/closureExercises.md: -------------------------------------------------------------------------------- 1 | ## Closure exercises 2 | 3 | 1. Write a function, `nonsense` that takes an input `string`. This function contains another function, `blab` which alerts `string` and is immediately called inside the function `nonsense`. `blab` should look like this inside of the `nonsense` function: 4 | 5 | ```javascript 6 | var blab = function(){ 7 | alert(string); 8 | }; 9 | ``` 10 | 11 | 1. In your function, `nonsense`, change the immediate call to a setTimeout so that the call to `blab` comes after 2 seconds. The `blab` function itself should stay the same as before. 12 | 13 | 1. Now, instead of calling `blab` inside of `nonsense`, return `blab` (without invoking it). Call `nonsense` with some string and store the returned value (the `blab` function) in a variable called `blabLater`. Call `nonsense` again with a different string and store the returned value in a variable called `blabAgainLater`. 14 | 15 | 1. Inspect `blabLater` and `blabAgainLater` in your console. Call them (they are functions!) and see what happens! 16 | 17 | 18 | 1. Write a function with a closure. The first function should only take one argument, someone's first name, and the inner function should take one more argument, someone's last name. The inner function should console.log both the first name and the last name. 19 | ```javascript 20 | var lastNameTrier = function(firstName){ 21 | //does stuff 22 | 23 | var innerFunction = function() { 24 | //does stuff 25 | }; 26 | //maybe returns something here 27 | }; 28 | var firstNameFarmer = lastNameTrier('Farmer'); //logs nothing 29 | firstNameFarmer('Brown'); //logs 'Farmer Brown' 30 | ``` 31 | This function is useful in case you want to try on different last names. For example, I could use firstName again with another last name: 32 | 33 | ```javascript 34 | firstNameFarmer('Jane'); //logs 'Farmer Jane' 35 | firstNameFarmer('Lynne'); //logs 'Farmer Lynne' 36 | ``` 37 | 38 | 39 | 1. Create a `storyWriter` function that returns an object with two methods. One method, `addWords` adds a word to your story and returns the story while the other one, `erase`, resets the story back to an empty string. Here is an implementation: 40 | ```javascript 41 | var farmLoveStory = storyWriter(); 42 | farmLoveStory.addWords('There was once a lonely cow.'); // 'There was once a lonely cow.' 43 | farmLoveStory.addWords('It saw a friendly face.'); //'There was once a lonely cow. It saw a friendly face.' 44 | 45 | var storyOfMyLife = storyWriter(); 46 | storyOfMyLife.addWords('My code broke.'); // 'My code broke.' 47 | storyOfMyLife.addWords('I ate some ice cream.'); //'My code broke. I ate some ice cream.' 48 | storyOfMyLife.erase(); // '' 49 | 50 | ``` 51 | 52 | 1. Using the module pattern, design a toaster. Use your creativity here and think about what you want your users to be able to access on the outside of your toaster vs what you don't want them to be able to touch. 53 | 54 | ```javascript 55 | var Toaster = function(){ 56 | //some private methods and properties 57 | 58 | return { 59 | //some public methods and properties, etc 60 | }; 61 | }; 62 | ``` 63 | 64 | 65 | 1. [EXTRA CREDIT] Use the module pattern to design a character in a Super Mario game. Think about what actions you can control in the game and other aspects you can't control directly (example: you can only affect your health indirectly by eating a mushroom). If you are not familiar with Super Mario, choose another simple game for this example. 66 | 67 | 1. [EXTRA CREDIT] Why doesn't the code below work? This is a function that should return an array of functions that console.log() each person's name as a string when invoked. Fiddle with this function and inspect how it works, then try to fix it using a closure. Be prepared to explain to a partner how it worked before, and how it works now with a closure. 68 | 69 | ```javascript 70 | var checkAttendanceFunc = function(nameArr){ 71 | var resultArr = []; 72 | for(var i = 0; i < nameArr.length; i++){ 73 | resultArr.push(function(){ console.log('Is', nameArr[i], 'present?', i)}) 74 | }; 75 | return resultArr; 76 | }; 77 | ``` 78 | Here is a hint: http://jsfiddle.net/PuEy6/ 79 | 80 | 1. [EXTRA CREDIT] Write a function that takes another function\* as an argument and creates a version of the function that can only be called one time. Repeated calls to the modified function will have no effect, returning the value from the original call. How could you do this without using a closure? Is it even possible? How could you do this with a closure? \*Note: This original input function should *not* have any parameters. 81 | -------------------------------------------------------------------------------- /scope/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Functions 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /scope/functions.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | 4 | describe('Function Exercises', function () { 5 | 6 | var ACTUAL; 7 | 8 | // This resets the value of ACTUAL (to null) before each test is run 9 | beforeEach(function () { 10 | ACTUAL = null; 11 | }); 12 | 13 | it('a function has access to its own local scope variables', function () { 14 | var fn = function () { 15 | var name = 'inner'; 16 | ACTUAL = name; 17 | }; 18 | fn(); 19 | expect(ACTUAL === 'inner').to.be.true; 20 | }); 21 | 22 | it('inputs to a function are treated as local scope variables', function () { 23 | var fn = function (name) { 24 | ACTUAL = name; 25 | }; 26 | fn('inner'); 27 | expect(ACTUAL === '???').to.be.true; 28 | }); 29 | 30 | it('a function has access to the variables contained within the same scope that function was created in', function () { 31 | var name = 'outer'; 32 | var fn = function () { 33 | ACTUAL = name; 34 | }; 35 | fn(); 36 | expect(ACTUAL === '???').to.be.true; 37 | }); 38 | 39 | it('a function\'s local scope variables are not available anywhere outside that function', function () { 40 | var firstFn = function () { 41 | var localToFirstFn = 'inner'; 42 | }; 43 | firstFn(); 44 | expect(function () { 45 | ACTUAL = localToFirstFn; 46 | }).to.throw(); 47 | expect(ACTUAL === '???').to.be.true; 48 | }); 49 | 50 | it('a function\'s local scope variables are not available anywhere outside that function, regardless of the context it\'s called in', function () { 51 | var firstFn = function () { 52 | var localToFirstFn = 'first'; 53 | // Although false, it might seem reasonable to think that the secondFn (which mentions the localToFirstFn variable), should have access to the localToFirstFn variable, since it's being called here from within the scope where that variable is declared. 54 | secondFn(); 55 | }; 56 | var secondFn = function () { 57 | ACTUAL = localToFirstFn; 58 | }; 59 | expect(function () { 60 | // of course, calling the secondFn should throw an error in this case, since secondFn does not have access to the localToFirstFn variable 61 | secondFn(); 62 | }).to.throw(); 63 | expect(function () { 64 | // in addition, calling the firstFn (which in turn calls the secondFn) should also throw, since it the calling context of secondFn has no influence over its scope access rules 65 | firstFn(); 66 | }).to.throw(); 67 | expect(ACTUAL === '???').to.be.true; 68 | }); 69 | 70 | it('if an inner and an outer variable share the same name, and the name is referenced in the inner scope, the inner scope variable masks the variable from the outer scope with the same name. This renders the outer scope variables inaccassible from anywhere within the inner function block', function () { 71 | var sameName = 'outer'; 72 | var fn = function () { 73 | var sameName = 'inner'; 74 | ACTUAL = sameName; 75 | }; 76 | fn(); 77 | expect(ACTUAL === '???').to.be.true; 78 | }); 79 | 80 | it('if an inner and an outer variable share the same name, and the name is referenced in the outer scope, the outer value binding will be used', function () { 81 | var sameName = 'outer'; 82 | var fn = function () { 83 | var sameName = 'inner'; 84 | }; 85 | fn(); 86 | ACTUAL = sameName; 87 | expect(ACTUAL === '???').to.be.true; 88 | }); 89 | 90 | it('a new variable scope is created for every call to a function, as exemplified with a counter', function () { 91 | var fn = function () { 92 | // the `||` symbol here is being used to set a default value for innerCounter. If innerCounter already contains a truthy value, then the value in that variable will be unchanged. If it is falsey however (such as if it were completely uninitialized), then this line will set it to the default value of 10. 93 | var innerCounter = innerCounter || 10; 94 | innerCounter = innerCounter + 1; 95 | ACTUAL = innerCounter; 96 | }; 97 | 98 | fn(); 99 | expect(ACTUAL === '???').to.be.true; 100 | fn(); 101 | expect(ACTUAL === '???').to.be.true; 102 | }); 103 | 104 | it('a new variable scope is created for each call to a function, as exemplified with uninitialized string variables', function () { 105 | // this is a longer form of the same observation as above, using strings instead of numbers. 106 | var fn = function () { 107 | var localVariable; 108 | if (localVariable === undefined) { 109 | // the variable will be initialized for the first time during this call to fn 110 | ACTUAL = 'alpha'; 111 | } else if (localVariable === 'initialized') { 112 | // the variable has already been initialized by a previous call to fn 113 | ACTUAL = 'omega'; 114 | } 115 | // now that actual has been set, we will initialize localVariable to refer to a string 116 | localVariable = 'initialized'; 117 | }; 118 | 119 | fn(); 120 | expect(ACTUAL === '???').to.be.true; 121 | fn(); 122 | expect(ACTUAL === '???').to.be.true; 123 | }); 124 | 125 | it('an inner function can access both its local scope variables and variables in its containing scope, provided the variables have different names', function () { 126 | var outerName = 'outer'; 127 | var fn = function () { 128 | var innerName = 'inner'; 129 | ACTUAL = innerName + outerName; 130 | }; 131 | fn(); 132 | expect(ACTUAL === '???').to.be.true; 133 | }); 134 | 135 | it('between calls to an inner function, that inner function retains access to a variable in an outer scope. Modifying those variables has a lasting effect between calls to the inner function.', function () { 136 | var outerCounter = 10; 137 | 138 | var fn = function () { 139 | outerCounter = outerCounter + 1; 140 | ACTUAL = outerCounter; 141 | }; 142 | 143 | fn(); 144 | expect(ACTUAL === '???').to.be.true; 145 | fn(); 146 | expect(ACTUAL === '???').to.be.true; 147 | }); 148 | 149 | it('the rule about retaining access to variables from an outer scope still applies, even after the outer function call (that created the outer scope) has returned', function () { 150 | var outerFn = function () { 151 | // NOTE: the contents of this function is the same as the entire body of the previous test 152 | var counterInOuterScope = 10; 153 | 154 | var innerIncrementingFn = function () { 155 | counterInOuterScope = counterInOuterScope + 1; 156 | ACTUAL = counterInOuterScope; 157 | }; 158 | 159 | innerIncrementingFn(); 160 | expect(ACTUAL === '???').to.be.true; 161 | innerIncrementingFn(); 162 | expect(ACTUAL === '???').to.be.true; 163 | // Here, we retain a reference to the newly created inner function for later, by assigning it to the global scope (window) 164 | window.retainedInnerFn = innerIncrementingFn; 165 | 166 | }; 167 | 168 | // before we run outerFn, there will be no innerFn exported to the global scope 169 | expect(window.retainedInnerFn).to.equal.undefined; 170 | // running this outer function should have the same effect as running the whole previous test, with the addition of placing the innerFn somewhere that we can reach it after outerFn has returned 171 | outerFn(); 172 | expect(window.retainedInnerFn).to.be.a('function'); 173 | // even though the outerFn has returned once the only call to it was completed a couple of lines above, the inner function remains available in the global scope, and still has access to the variables of that containing scope where it was first created. 174 | window.retainedInnerFn(); 175 | expect(ACTUAL === '???').to.be.true; 176 | }); 177 | 178 | }); 179 | 180 | })(); 181 | -------------------------------------------------------------------------------- /scope/lib/chai/chai.js: -------------------------------------------------------------------------------- 1 | !function (name, context, definition) { 2 | if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { 3 | module.exports = definition(); 4 | } else if (typeof define === 'function' && typeof define.amd === 'object') { 5 | define(function () { 6 | return definition(); 7 | }); 8 | } else { 9 | context[name] = definition(); 10 | } 11 | }('chai', this, function () { 12 | 13 | function require(p) { 14 | var path = require.resolve(p) 15 | , mod = require.modules[path]; 16 | if (!mod) throw new Error('failed to require "' + p + '"'); 17 | if (!mod.exports) { 18 | mod.exports = {}; 19 | mod.call(mod.exports, mod, mod.exports, require.relative(path)); 20 | } 21 | return mod.exports; 22 | } 23 | 24 | require.modules = {}; 25 | 26 | require.resolve = function (path) { 27 | var orig = path 28 | , reg = path + '.js' 29 | , index = path + '/index.js'; 30 | return require.modules[reg] && reg 31 | || require.modules[index] && index 32 | || orig; 33 | }; 34 | 35 | require.register = function (path, fn) { 36 | require.modules[path] = fn; 37 | }; 38 | 39 | require.relative = function (parent) { 40 | return function(p){ 41 | if ('.' != p.charAt(0)) return require(p); 42 | 43 | var path = parent.split('/') 44 | , segs = p.split('/'); 45 | path.pop(); 46 | 47 | for (var i = 0; i < segs.length; i++) { 48 | var seg = segs[i]; 49 | if ('..' == seg) path.pop(); 50 | else if ('.' != seg) path.push(seg); 51 | } 52 | 53 | return require(path.join('/')); 54 | }; 55 | }; 56 | 57 | require.alias = function (from, to) { 58 | var fn = require.modules[from]; 59 | require.modules[to] = fn; 60 | }; 61 | 62 | 63 | require.register("chai.js", function(module, exports, require){ 64 | /*! 65 | * chai 66 | * Copyright(c) 2011-2013 Jake Luer 67 | * MIT Licensed 68 | */ 69 | 70 | var used = [] 71 | , exports = module.exports = {}; 72 | 73 | /*! 74 | * Chai version 75 | */ 76 | 77 | exports.version = '1.5.0'; 78 | 79 | /*! 80 | * Primary `Assertion` prototype 81 | */ 82 | 83 | exports.Assertion = require('./chai/assertion'); 84 | 85 | /*! 86 | * Assertion Error 87 | */ 88 | 89 | exports.AssertionError = require('./chai/error'); 90 | 91 | /*! 92 | * Utils for plugins (not exported) 93 | */ 94 | 95 | var util = require('./chai/utils'); 96 | 97 | /** 98 | * # .use(function) 99 | * 100 | * Provides a way to extend the internals of Chai 101 | * 102 | * @param {Function} 103 | * @returns {this} for chaining 104 | * @api public 105 | */ 106 | 107 | exports.use = function (fn) { 108 | if (!~used.indexOf(fn)) { 109 | fn(this, util); 110 | used.push(fn); 111 | } 112 | 113 | return this; 114 | }; 115 | 116 | /*! 117 | * Core Assertions 118 | */ 119 | 120 | var core = require('./chai/core/assertions'); 121 | exports.use(core); 122 | 123 | /*! 124 | * Expect interface 125 | */ 126 | 127 | var expect = require('./chai/interface/expect'); 128 | exports.use(expect); 129 | 130 | /*! 131 | * Should interface 132 | */ 133 | 134 | var should = require('./chai/interface/should'); 135 | exports.use(should); 136 | 137 | /*! 138 | * Assert interface 139 | */ 140 | 141 | var assert = require('./chai/interface/assert'); 142 | exports.use(assert); 143 | 144 | }); // module: chai.js 145 | 146 | require.register("chai/assertion.js", function(module, exports, require){ 147 | /*! 148 | * chai 149 | * http://chaijs.com 150 | * Copyright(c) 2011-2013 Jake Luer 151 | * MIT Licensed 152 | */ 153 | 154 | /*! 155 | * Module dependencies. 156 | */ 157 | 158 | var AssertionError = require('./error') 159 | , util = require('./utils') 160 | , flag = util.flag; 161 | 162 | /*! 163 | * Module export. 164 | */ 165 | 166 | module.exports = Assertion; 167 | 168 | 169 | /*! 170 | * Assertion Constructor 171 | * 172 | * Creates object for chaining. 173 | * 174 | * @api private 175 | */ 176 | 177 | function Assertion (obj, msg, stack) { 178 | flag(this, 'ssfi', stack || arguments.callee); 179 | flag(this, 'object', obj); 180 | flag(this, 'message', msg); 181 | } 182 | 183 | /*! 184 | * ### Assertion.includeStack 185 | * 186 | * User configurable property, influences whether stack trace 187 | * is included in Assertion error message. Default of false 188 | * suppresses stack trace in the error message 189 | * 190 | * Assertion.includeStack = true; // enable stack on error 191 | * 192 | * @api public 193 | */ 194 | 195 | Assertion.includeStack = false; 196 | 197 | /*! 198 | * ### Assertion.showDiff 199 | * 200 | * User configurable property, influences whether or not 201 | * the `showDiff` flag should be included in the thrown 202 | * AssertionErrors. `false` will always be `false`; `true` 203 | * will be true when the assertion has requested a diff 204 | * be shown. 205 | * 206 | * @api public 207 | */ 208 | 209 | Assertion.showDiff = true; 210 | 211 | Assertion.addProperty = function (name, fn) { 212 | util.addProperty(this.prototype, name, fn); 213 | }; 214 | 215 | Assertion.addMethod = function (name, fn) { 216 | util.addMethod(this.prototype, name, fn); 217 | }; 218 | 219 | Assertion.addChainableMethod = function (name, fn, chainingBehavior) { 220 | util.addChainableMethod(this.prototype, name, fn, chainingBehavior); 221 | }; 222 | 223 | Assertion.overwriteProperty = function (name, fn) { 224 | util.overwriteProperty(this.prototype, name, fn); 225 | }; 226 | 227 | Assertion.overwriteMethod = function (name, fn) { 228 | util.overwriteMethod(this.prototype, name, fn); 229 | }; 230 | 231 | /*! 232 | * ### .assert(expression, message, negateMessage, expected, actual) 233 | * 234 | * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. 235 | * 236 | * @name assert 237 | * @param {Philosophical} expression to be tested 238 | * @param {String} message to display if fails 239 | * @param {String} negatedMessage to display if negated expression fails 240 | * @param {Mixed} expected value (remember to check for negation) 241 | * @param {Mixed} actual (optional) will default to `this.obj` 242 | * @api private 243 | */ 244 | 245 | Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { 246 | var ok = util.test(this, arguments); 247 | if (true !== showDiff) showDiff = false; 248 | if (true !== Assertion.showDiff) showDiff = false; 249 | 250 | if (!ok) { 251 | var msg = util.getMessage(this, arguments) 252 | , actual = util.getActual(this, arguments); 253 | throw new AssertionError({ 254 | message: msg 255 | , actual: actual 256 | , expected: expected 257 | , stackStartFunction: (Assertion.includeStack) ? this.assert : flag(this, 'ssfi') 258 | , showDiff: showDiff 259 | }); 260 | } 261 | }; 262 | 263 | /*! 264 | * ### ._obj 265 | * 266 | * Quick reference to stored `actual` value for plugin developers. 267 | * 268 | * @api private 269 | */ 270 | 271 | Object.defineProperty(Assertion.prototype, '_obj', 272 | { get: function () { 273 | return flag(this, 'object'); 274 | } 275 | , set: function (val) { 276 | flag(this, 'object', val); 277 | } 278 | }); 279 | 280 | }); // module: chai/assertion.js 281 | 282 | require.register("chai/core/assertions.js", function(module, exports, require){ 283 | /*! 284 | * chai 285 | * http://chaijs.com 286 | * Copyright(c) 2011-2013 Jake Luer 287 | * MIT Licensed 288 | */ 289 | 290 | module.exports = function (chai, _) { 291 | var Assertion = chai.Assertion 292 | , toString = Object.prototype.toString 293 | , flag = _.flag; 294 | 295 | /** 296 | * ### Language Chains 297 | * 298 | * The following are provide as chainable getters to 299 | * improve the readability of your assertions. They 300 | * do not provide an testing capability unless they 301 | * have been overwritten by a plugin. 302 | * 303 | * **Chains** 304 | * 305 | * - to 306 | * - be 307 | * - been 308 | * - is 309 | * - that 310 | * - and 311 | * - have 312 | * - with 313 | * - at 314 | * - of 315 | * 316 | * @name language chains 317 | * @api public 318 | */ 319 | 320 | [ 'to', 'be', 'been' 321 | , 'is', 'and', 'have' 322 | , 'with', 'that', 'at' 323 | , 'of' ].forEach(function (chain) { 324 | Assertion.addProperty(chain, function () { 325 | return this; 326 | }); 327 | }); 328 | 329 | /** 330 | * ### .not 331 | * 332 | * Negates any of assertions following in the chain. 333 | * 334 | * expect(foo).to.not.equal('bar'); 335 | * expect(goodFn).to.not.throw(Error); 336 | * expect({ foo: 'baz' }).to.have.property('foo') 337 | * .and.not.equal('bar'); 338 | * 339 | * @name not 340 | * @api public 341 | */ 342 | 343 | Assertion.addProperty('not', function () { 344 | flag(this, 'negate', true); 345 | }); 346 | 347 | /** 348 | * ### .deep 349 | * 350 | * Sets the `deep` flag, later used by the `equal` and 351 | * `property` assertions. 352 | * 353 | * expect(foo).to.deep.equal({ bar: 'baz' }); 354 | * expect({ foo: { bar: { baz: 'quux' } } }) 355 | * .to.have.deep.property('foo.bar.baz', 'quux'); 356 | * 357 | * @name deep 358 | * @api public 359 | */ 360 | 361 | Assertion.addProperty('deep', function () { 362 | flag(this, 'deep', true); 363 | }); 364 | 365 | /** 366 | * ### .a(type) 367 | * 368 | * The `a` and `an` assertions are aliases that can be 369 | * used either as language chains or to assert a value's 370 | * type. 371 | * 372 | * // typeof 373 | * expect('test').to.be.a('string'); 374 | * expect({ foo: 'bar' }).to.be.an('object'); 375 | * expect(null).to.be.a('null'); 376 | * expect(undefined).to.be.an('undefined'); 377 | * 378 | * // language chain 379 | * expect(foo).to.be.an.instanceof(Foo); 380 | * 381 | * @name a 382 | * @alias an 383 | * @param {String} type 384 | * @param {String} message _optional_ 385 | * @api public 386 | */ 387 | 388 | function an (type, msg) { 389 | if (msg) flag(this, 'message', msg); 390 | type = type.toLowerCase(); 391 | var obj = flag(this, 'object') 392 | , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; 393 | 394 | this.assert( 395 | type === _.type(obj) 396 | , 'expected #{this} to be ' + article + type 397 | , 'expected #{this} not to be ' + article + type 398 | ); 399 | } 400 | 401 | Assertion.addChainableMethod('an', an); 402 | Assertion.addChainableMethod('a', an); 403 | 404 | /** 405 | * ### .include(value) 406 | * 407 | * The `include` and `contain` assertions can be used as either property 408 | * based language chains or as methods to assert the inclusion of an object 409 | * in an array or a substring in a string. When used as language chains, 410 | * they toggle the `contain` flag for the `keys` assertion. 411 | * 412 | * expect([1,2,3]).to.include(2); 413 | * expect('foobar').to.contain('foo'); 414 | * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); 415 | * 416 | * @name include 417 | * @alias contain 418 | * @param {Object|String|Number} obj 419 | * @param {String} message _optional_ 420 | * @api public 421 | */ 422 | 423 | function includeChainingBehavior () { 424 | flag(this, 'contains', true); 425 | } 426 | 427 | function include (val, msg) { 428 | if (msg) flag(this, 'message', msg); 429 | var obj = flag(this, 'object') 430 | this.assert( 431 | ~obj.indexOf(val) 432 | , 'expected #{this} to include ' + _.inspect(val) 433 | , 'expected #{this} to not include ' + _.inspect(val)); 434 | } 435 | 436 | Assertion.addChainableMethod('include', include, includeChainingBehavior); 437 | Assertion.addChainableMethod('contain', include, includeChainingBehavior); 438 | 439 | /** 440 | * ### .ok 441 | * 442 | * Asserts that the target is truthy. 443 | * 444 | * expect('everthing').to.be.ok; 445 | * expect(1).to.be.ok; 446 | * expect(false).to.not.be.ok; 447 | * expect(undefined).to.not.be.ok; 448 | * expect(null).to.not.be.ok; 449 | * 450 | * @name ok 451 | * @api public 452 | */ 453 | 454 | Assertion.addProperty('ok', function () { 455 | this.assert( 456 | flag(this, 'object') 457 | , 'expected #{this} to be truthy' 458 | , 'expected #{this} to be falsy'); 459 | }); 460 | 461 | /** 462 | * ### .true 463 | * 464 | * Asserts that the target is `true`. 465 | * 466 | * expect(true).to.be.true; 467 | * expect(1).to.not.be.true; 468 | * 469 | * @name true 470 | * @api public 471 | */ 472 | 473 | Assertion.addProperty('true', function () { 474 | this.assert( 475 | true === flag(this, 'object') 476 | , 'expected #{this} to be true' 477 | , 'expected #{this} to be false' 478 | , this.negate ? false : true 479 | ); 480 | }); 481 | 482 | /** 483 | * ### .false 484 | * 485 | * Asserts that the target is `false`. 486 | * 487 | * expect(false).to.be.false; 488 | * expect(0).to.not.be.false; 489 | * 490 | * @name false 491 | * @api public 492 | */ 493 | 494 | Assertion.addProperty('false', function () { 495 | this.assert( 496 | false === flag(this, 'object') 497 | , 'expected #{this} to be false' 498 | , 'expected #{this} to be true' 499 | , this.negate ? true : false 500 | ); 501 | }); 502 | 503 | /** 504 | * ### .null 505 | * 506 | * Asserts that the target is `null`. 507 | * 508 | * expect(null).to.be.null; 509 | * expect(undefined).not.to.be.null; 510 | * 511 | * @name null 512 | * @api public 513 | */ 514 | 515 | Assertion.addProperty('null', function () { 516 | this.assert( 517 | null === flag(this, 'object') 518 | , 'expected #{this} to be null' 519 | , 'expected #{this} not to be null' 520 | ); 521 | }); 522 | 523 | /** 524 | * ### .undefined 525 | * 526 | * Asserts that the target is `undefined`. 527 | * 528 | * expect(undefined).to.be.undefined; 529 | * expect(null).to.not.be.undefined; 530 | * 531 | * @name undefined 532 | * @api public 533 | */ 534 | 535 | Assertion.addProperty('undefined', function () { 536 | this.assert( 537 | undefined === flag(this, 'object') 538 | , 'expected #{this} to be undefined' 539 | , 'expected #{this} not to be undefined' 540 | ); 541 | }); 542 | 543 | /** 544 | * ### .exist 545 | * 546 | * Asserts that the target is neither `null` nor `undefined`. 547 | * 548 | * var foo = 'hi' 549 | * , bar = null 550 | * , baz; 551 | * 552 | * expect(foo).to.exist; 553 | * expect(bar).to.not.exist; 554 | * expect(baz).to.not.exist; 555 | * 556 | * @name exist 557 | * @api public 558 | */ 559 | 560 | Assertion.addProperty('exist', function () { 561 | this.assert( 562 | null != flag(this, 'object') 563 | , 'expected #{this} to exist' 564 | , 'expected #{this} to not exist' 565 | ); 566 | }); 567 | 568 | 569 | /** 570 | * ### .empty 571 | * 572 | * Asserts that the target's length is `0`. For arrays, it checks 573 | * the `length` property. For objects, it gets the count of 574 | * enumerable keys. 575 | * 576 | * expect([]).to.be.empty; 577 | * expect('').to.be.empty; 578 | * expect({}).to.be.empty; 579 | * 580 | * @name empty 581 | * @api public 582 | */ 583 | 584 | Assertion.addProperty('empty', function () { 585 | var obj = flag(this, 'object') 586 | , expected = obj; 587 | 588 | if (Array.isArray(obj) || 'string' === typeof object) { 589 | expected = obj.length; 590 | } else if (typeof obj === 'object') { 591 | expected = Object.keys(obj).length; 592 | } 593 | 594 | this.assert( 595 | !expected 596 | , 'expected #{this} to be empty' 597 | , 'expected #{this} not to be empty' 598 | ); 599 | }); 600 | 601 | /** 602 | * ### .arguments 603 | * 604 | * Asserts that the target is an arguments object. 605 | * 606 | * function test () { 607 | * expect(arguments).to.be.arguments; 608 | * } 609 | * 610 | * @name arguments 611 | * @alias Arguments 612 | * @api public 613 | */ 614 | 615 | function checkArguments () { 616 | var obj = flag(this, 'object') 617 | , type = Object.prototype.toString.call(obj); 618 | this.assert( 619 | '[object Arguments]' === type 620 | , 'expected #{this} to be arguments but got ' + type 621 | , 'expected #{this} to not be arguments' 622 | ); 623 | } 624 | 625 | Assertion.addProperty('arguments', checkArguments); 626 | Assertion.addProperty('Arguments', checkArguments); 627 | 628 | /** 629 | * ### .equal(value) 630 | * 631 | * Asserts that the target is strictly equal (`===`) to `value`. 632 | * Alternately, if the `deep` flag is set, asserts that 633 | * the target is deeply equal to `value`. 634 | * 635 | * expect('hello').to.equal('hello'); 636 | * expect(42).to.equal(42); 637 | * expect(1).to.not.equal(true); 638 | * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); 639 | * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); 640 | * 641 | * @name equal 642 | * @alias equals 643 | * @alias eq 644 | * @alias deep.equal 645 | * @param {Mixed} value 646 | * @param {String} message _optional_ 647 | * @api public 648 | */ 649 | 650 | function assertEqual (val, msg) { 651 | if (msg) flag(this, 'message', msg); 652 | var obj = flag(this, 'object'); 653 | if (flag(this, 'deep')) { 654 | return this.eql(val); 655 | } else { 656 | this.assert( 657 | val === obj 658 | , 'expected #{this} to equal #{exp}' 659 | , 'expected #{this} to not equal #{exp}' 660 | , val 661 | , this._obj 662 | , true 663 | ); 664 | } 665 | } 666 | 667 | Assertion.addMethod('equal', assertEqual); 668 | Assertion.addMethod('equals', assertEqual); 669 | Assertion.addMethod('eq', assertEqual); 670 | 671 | /** 672 | * ### .eql(value) 673 | * 674 | * Asserts that the target is deeply equal to `value`. 675 | * 676 | * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); 677 | * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); 678 | * 679 | * @name eql 680 | * @alias eqls 681 | * @param {Mixed} value 682 | * @param {String} message _optional_ 683 | * @api public 684 | */ 685 | 686 | function assertEql(obj, msg) { 687 | if (msg) flag(this, 'message', msg); 688 | this.assert( 689 | _.eql(obj, flag(this, 'object')) 690 | , 'expected #{this} to deeply equal #{exp}' 691 | , 'expected #{this} to not deeply equal #{exp}' 692 | , obj 693 | , this._obj 694 | , true 695 | ); 696 | } 697 | 698 | Assertion.addMethod('eql', assertEql); 699 | Assertion.addMethod('eqls', assertEql); 700 | 701 | /** 702 | * ### .above(value) 703 | * 704 | * Asserts that the target is greater than `value`. 705 | * 706 | * expect(10).to.be.above(5); 707 | * 708 | * Can also be used in conjunction with `length` to 709 | * assert a minimum length. The benefit being a 710 | * more informative error message than if the length 711 | * was supplied directly. 712 | * 713 | * expect('foo').to.have.length.above(2); 714 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 715 | * 716 | * @name above 717 | * @alias gt 718 | * @alias greaterThan 719 | * @param {Number} value 720 | * @param {String} message _optional_ 721 | * @api public 722 | */ 723 | 724 | function assertAbove (n, msg) { 725 | if (msg) flag(this, 'message', msg); 726 | var obj = flag(this, 'object'); 727 | if (flag(this, 'doLength')) { 728 | new Assertion(obj, msg).to.have.property('length'); 729 | var len = obj.length; 730 | this.assert( 731 | len > n 732 | , 'expected #{this} to have a length above #{exp} but got #{act}' 733 | , 'expected #{this} to not have a length above #{exp}' 734 | , n 735 | , len 736 | ); 737 | } else { 738 | this.assert( 739 | obj > n 740 | , 'expected #{this} to be above ' + n 741 | , 'expected #{this} to be at most ' + n 742 | ); 743 | } 744 | } 745 | 746 | Assertion.addMethod('above', assertAbove); 747 | Assertion.addMethod('gt', assertAbove); 748 | Assertion.addMethod('greaterThan', assertAbove); 749 | 750 | /** 751 | * ### .least(value) 752 | * 753 | * Asserts that the target is greater than or equal to `value`. 754 | * 755 | * expect(10).to.be.at.least(10); 756 | * 757 | * Can also be used in conjunction with `length` to 758 | * assert a minimum length. The benefit being a 759 | * more informative error message than if the length 760 | * was supplied directly. 761 | * 762 | * expect('foo').to.have.length.of.at.least(2); 763 | * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); 764 | * 765 | * @name least 766 | * @alias gte 767 | * @param {Number} value 768 | * @param {String} message _optional_ 769 | * @api public 770 | */ 771 | 772 | function assertLeast (n, msg) { 773 | if (msg) flag(this, 'message', msg); 774 | var obj = flag(this, 'object'); 775 | if (flag(this, 'doLength')) { 776 | new Assertion(obj, msg).to.have.property('length'); 777 | var len = obj.length; 778 | this.assert( 779 | len >= n 780 | , 'expected #{this} to have a length at least #{exp} but got #{act}' 781 | , 'expected #{this} to have a length below #{exp}' 782 | , n 783 | , len 784 | ); 785 | } else { 786 | this.assert( 787 | obj >= n 788 | , 'expected #{this} to be at least ' + n 789 | , 'expected #{this} to be below ' + n 790 | ); 791 | } 792 | } 793 | 794 | Assertion.addMethod('least', assertLeast); 795 | Assertion.addMethod('gte', assertLeast); 796 | 797 | /** 798 | * ### .below(value) 799 | * 800 | * Asserts that the target is less than `value`. 801 | * 802 | * expect(5).to.be.below(10); 803 | * 804 | * Can also be used in conjunction with `length` to 805 | * assert a maximum length. The benefit being a 806 | * more informative error message than if the length 807 | * was supplied directly. 808 | * 809 | * expect('foo').to.have.length.below(4); 810 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 811 | * 812 | * @name below 813 | * @alias lt 814 | * @alias lessThan 815 | * @param {Number} value 816 | * @param {String} message _optional_ 817 | * @api public 818 | */ 819 | 820 | function assertBelow (n, msg) { 821 | if (msg) flag(this, 'message', msg); 822 | var obj = flag(this, 'object'); 823 | if (flag(this, 'doLength')) { 824 | new Assertion(obj, msg).to.have.property('length'); 825 | var len = obj.length; 826 | this.assert( 827 | len < n 828 | , 'expected #{this} to have a length below #{exp} but got #{act}' 829 | , 'expected #{this} to not have a length below #{exp}' 830 | , n 831 | , len 832 | ); 833 | } else { 834 | this.assert( 835 | obj < n 836 | , 'expected #{this} to be below ' + n 837 | , 'expected #{this} to be at least ' + n 838 | ); 839 | } 840 | } 841 | 842 | Assertion.addMethod('below', assertBelow); 843 | Assertion.addMethod('lt', assertBelow); 844 | Assertion.addMethod('lessThan', assertBelow); 845 | 846 | /** 847 | * ### .most(value) 848 | * 849 | * Asserts that the target is less than or equal to `value`. 850 | * 851 | * expect(5).to.be.at.most(5); 852 | * 853 | * Can also be used in conjunction with `length` to 854 | * assert a maximum length. The benefit being a 855 | * more informative error message than if the length 856 | * was supplied directly. 857 | * 858 | * expect('foo').to.have.length.of.at.most(4); 859 | * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); 860 | * 861 | * @name most 862 | * @alias lte 863 | * @param {Number} value 864 | * @param {String} message _optional_ 865 | * @api public 866 | */ 867 | 868 | function assertMost (n, msg) { 869 | if (msg) flag(this, 'message', msg); 870 | var obj = flag(this, 'object'); 871 | if (flag(this, 'doLength')) { 872 | new Assertion(obj, msg).to.have.property('length'); 873 | var len = obj.length; 874 | this.assert( 875 | len <= n 876 | , 'expected #{this} to have a length at most #{exp} but got #{act}' 877 | , 'expected #{this} to have a length above #{exp}' 878 | , n 879 | , len 880 | ); 881 | } else { 882 | this.assert( 883 | obj <= n 884 | , 'expected #{this} to be at most ' + n 885 | , 'expected #{this} to be above ' + n 886 | ); 887 | } 888 | } 889 | 890 | Assertion.addMethod('most', assertMost); 891 | Assertion.addMethod('lte', assertMost); 892 | 893 | /** 894 | * ### .within(start, finish) 895 | * 896 | * Asserts that the target is within a range. 897 | * 898 | * expect(7).to.be.within(5,10); 899 | * 900 | * Can also be used in conjunction with `length` to 901 | * assert a length range. The benefit being a 902 | * more informative error message than if the length 903 | * was supplied directly. 904 | * 905 | * expect('foo').to.have.length.within(2,4); 906 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 907 | * 908 | * @name within 909 | * @param {Number} start lowerbound inclusive 910 | * @param {Number} finish upperbound inclusive 911 | * @param {String} message _optional_ 912 | * @api public 913 | */ 914 | 915 | Assertion.addMethod('within', function (start, finish, msg) { 916 | if (msg) flag(this, 'message', msg); 917 | var obj = flag(this, 'object') 918 | , range = start + '..' + finish; 919 | if (flag(this, 'doLength')) { 920 | new Assertion(obj, msg).to.have.property('length'); 921 | var len = obj.length; 922 | this.assert( 923 | len >= start && len <= finish 924 | , 'expected #{this} to have a length within ' + range 925 | , 'expected #{this} to not have a length within ' + range 926 | ); 927 | } else { 928 | this.assert( 929 | obj >= start && obj <= finish 930 | , 'expected #{this} to be within ' + range 931 | , 'expected #{this} to not be within ' + range 932 | ); 933 | } 934 | }); 935 | 936 | /** 937 | * ### .instanceof(constructor) 938 | * 939 | * Asserts that the target is an instance of `constructor`. 940 | * 941 | * var Tea = function (name) { this.name = name; } 942 | * , Chai = new Tea('chai'); 943 | * 944 | * expect(Chai).to.be.an.instanceof(Tea); 945 | * expect([ 1, 2, 3 ]).to.be.instanceof(Array); 946 | * 947 | * @name instanceof 948 | * @param {Constructor} constructor 949 | * @param {String} message _optional_ 950 | * @alias instanceOf 951 | * @api public 952 | */ 953 | 954 | function assertInstanceOf (constructor, msg) { 955 | if (msg) flag(this, 'message', msg); 956 | var name = _.getName(constructor); 957 | this.assert( 958 | flag(this, 'object') instanceof constructor 959 | , 'expected #{this} to be an instance of ' + name 960 | , 'expected #{this} to not be an instance of ' + name 961 | ); 962 | }; 963 | 964 | Assertion.addMethod('instanceof', assertInstanceOf); 965 | Assertion.addMethod('instanceOf', assertInstanceOf); 966 | 967 | /** 968 | * ### .property(name, [value]) 969 | * 970 | * Asserts that the target has a property `name`, optionally asserting that 971 | * the value of that property is strictly equal to `value`. 972 | * If the `deep` flag is set, you can use dot- and bracket-notation for deep 973 | * references into objects and arrays. 974 | * 975 | * // simple referencing 976 | * var obj = { foo: 'bar' }; 977 | * expect(obj).to.have.property('foo'); 978 | * expect(obj).to.have.property('foo', 'bar'); 979 | * 980 | * // deep referencing 981 | * var deepObj = { 982 | * green: { tea: 'matcha' } 983 | * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] 984 | * }; 985 | 986 | * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); 987 | * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); 988 | * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); 989 | * 990 | * You can also use an array as the starting point of a `deep.property` 991 | * assertion, or traverse nested arrays. 992 | * 993 | * var arr = [ 994 | * [ 'chai', 'matcha', 'konacha' ] 995 | * , [ { tea: 'chai' } 996 | * , { tea: 'matcha' } 997 | * , { tea: 'konacha' } ] 998 | * ]; 999 | * 1000 | * expect(arr).to.have.deep.property('[0][1]', 'matcha'); 1001 | * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); 1002 | * 1003 | * Furthermore, `property` changes the subject of the assertion 1004 | * to be the value of that property from the original object. This 1005 | * permits for further chainable assertions on that property. 1006 | * 1007 | * expect(obj).to.have.property('foo') 1008 | * .that.is.a('string'); 1009 | * expect(deepObj).to.have.property('green') 1010 | * .that.is.an('object') 1011 | * .that.deep.equals({ tea: 'matcha' }); 1012 | * expect(deepObj).to.have.property('teas') 1013 | * .that.is.an('array') 1014 | * .with.deep.property('[2]') 1015 | * .that.deep.equals({ tea: 'konacha' }); 1016 | * 1017 | * @name property 1018 | * @alias deep.property 1019 | * @param {String} name 1020 | * @param {Mixed} value (optional) 1021 | * @param {String} message _optional_ 1022 | * @returns value of property for chaining 1023 | * @api public 1024 | */ 1025 | 1026 | Assertion.addMethod('property', function (name, val, msg) { 1027 | if (msg) flag(this, 'message', msg); 1028 | 1029 | var descriptor = flag(this, 'deep') ? 'deep property ' : 'property ' 1030 | , negate = flag(this, 'negate') 1031 | , obj = flag(this, 'object') 1032 | , value = flag(this, 'deep') 1033 | ? _.getPathValue(name, obj) 1034 | : obj[name]; 1035 | 1036 | if (negate && undefined !== val) { 1037 | if (undefined === value) { 1038 | msg = (msg != null) ? msg + ': ' : ''; 1039 | throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); 1040 | } 1041 | } else { 1042 | this.assert( 1043 | undefined !== value 1044 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) 1045 | , 'expected #{this} to not have ' + descriptor + _.inspect(name)); 1046 | } 1047 | 1048 | if (undefined !== val) { 1049 | this.assert( 1050 | val === value 1051 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' 1052 | , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' 1053 | , val 1054 | , value 1055 | ); 1056 | } 1057 | 1058 | flag(this, 'object', value); 1059 | }); 1060 | 1061 | 1062 | /** 1063 | * ### .ownProperty(name) 1064 | * 1065 | * Asserts that the target has an own property `name`. 1066 | * 1067 | * expect('test').to.have.ownProperty('length'); 1068 | * 1069 | * @name ownProperty 1070 | * @alias haveOwnProperty 1071 | * @param {String} name 1072 | * @param {String} message _optional_ 1073 | * @api public 1074 | */ 1075 | 1076 | function assertOwnProperty (name, msg) { 1077 | if (msg) flag(this, 'message', msg); 1078 | var obj = flag(this, 'object'); 1079 | this.assert( 1080 | obj.hasOwnProperty(name) 1081 | , 'expected #{this} to have own property ' + _.inspect(name) 1082 | , 'expected #{this} to not have own property ' + _.inspect(name) 1083 | ); 1084 | } 1085 | 1086 | Assertion.addMethod('ownProperty', assertOwnProperty); 1087 | Assertion.addMethod('haveOwnProperty', assertOwnProperty); 1088 | 1089 | /** 1090 | * ### .length(value) 1091 | * 1092 | * Asserts that the target's `length` property has 1093 | * the expected value. 1094 | * 1095 | * expect([ 1, 2, 3]).to.have.length(3); 1096 | * expect('foobar').to.have.length(6); 1097 | * 1098 | * Can also be used as a chain precursor to a value 1099 | * comparison for the length property. 1100 | * 1101 | * expect('foo').to.have.length.above(2); 1102 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 1103 | * expect('foo').to.have.length.below(4); 1104 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 1105 | * expect('foo').to.have.length.within(2,4); 1106 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1107 | * 1108 | * @name length 1109 | * @alias lengthOf 1110 | * @param {Number} length 1111 | * @param {String} message _optional_ 1112 | * @api public 1113 | */ 1114 | 1115 | function assertLengthChain () { 1116 | flag(this, 'doLength', true); 1117 | } 1118 | 1119 | function assertLength (n, msg) { 1120 | if (msg) flag(this, 'message', msg); 1121 | var obj = flag(this, 'object'); 1122 | new Assertion(obj, msg).to.have.property('length'); 1123 | var len = obj.length; 1124 | 1125 | this.assert( 1126 | len == n 1127 | , 'expected #{this} to have a length of #{exp} but got #{act}' 1128 | , 'expected #{this} to not have a length of #{act}' 1129 | , n 1130 | , len 1131 | ); 1132 | } 1133 | 1134 | Assertion.addChainableMethod('length', assertLength, assertLengthChain); 1135 | Assertion.addMethod('lengthOf', assertLength, assertLengthChain); 1136 | 1137 | /** 1138 | * ### .match(regexp) 1139 | * 1140 | * Asserts that the target matches a regular expression. 1141 | * 1142 | * expect('foobar').to.match(/^foo/); 1143 | * 1144 | * @name match 1145 | * @param {RegExp} RegularExpression 1146 | * @param {String} message _optional_ 1147 | * @api public 1148 | */ 1149 | 1150 | Assertion.addMethod('match', function (re, msg) { 1151 | if (msg) flag(this, 'message', msg); 1152 | var obj = flag(this, 'object'); 1153 | this.assert( 1154 | re.exec(obj) 1155 | , 'expected #{this} to match ' + re 1156 | , 'expected #{this} not to match ' + re 1157 | ); 1158 | }); 1159 | 1160 | /** 1161 | * ### .string(string) 1162 | * 1163 | * Asserts that the string target contains another string. 1164 | * 1165 | * expect('foobar').to.have.string('bar'); 1166 | * 1167 | * @name string 1168 | * @param {String} string 1169 | * @param {String} message _optional_ 1170 | * @api public 1171 | */ 1172 | 1173 | Assertion.addMethod('string', function (str, msg) { 1174 | if (msg) flag(this, 'message', msg); 1175 | var obj = flag(this, 'object'); 1176 | new Assertion(obj, msg).is.a('string'); 1177 | 1178 | this.assert( 1179 | ~obj.indexOf(str) 1180 | , 'expected #{this} to contain ' + _.inspect(str) 1181 | , 'expected #{this} to not contain ' + _.inspect(str) 1182 | ); 1183 | }); 1184 | 1185 | 1186 | /** 1187 | * ### .keys(key1, [key2], [...]) 1188 | * 1189 | * Asserts that the target has exactly the given keys, or 1190 | * asserts the inclusion of some keys when using the 1191 | * `include` or `contain` modifiers. 1192 | * 1193 | * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']); 1194 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar'); 1195 | * 1196 | * @name keys 1197 | * @alias key 1198 | * @param {String...|Array} keys 1199 | * @api public 1200 | */ 1201 | 1202 | function assertKeys (keys) { 1203 | var obj = flag(this, 'object') 1204 | , str 1205 | , ok = true; 1206 | 1207 | keys = keys instanceof Array 1208 | ? keys 1209 | : Array.prototype.slice.call(arguments); 1210 | 1211 | if (!keys.length) throw new Error('keys required'); 1212 | 1213 | var actual = Object.keys(obj) 1214 | , len = keys.length; 1215 | 1216 | // Inclusion 1217 | ok = keys.every(function(key){ 1218 | return ~actual.indexOf(key); 1219 | }); 1220 | 1221 | // Strict 1222 | if (!flag(this, 'negate') && !flag(this, 'contains')) { 1223 | ok = ok && keys.length == actual.length; 1224 | } 1225 | 1226 | // Key string 1227 | if (len > 1) { 1228 | keys = keys.map(function(key){ 1229 | return _.inspect(key); 1230 | }); 1231 | var last = keys.pop(); 1232 | str = keys.join(', ') + ', and ' + last; 1233 | } else { 1234 | str = _.inspect(keys[0]); 1235 | } 1236 | 1237 | // Form 1238 | str = (len > 1 ? 'keys ' : 'key ') + str; 1239 | 1240 | // Have / include 1241 | str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; 1242 | 1243 | // Assertion 1244 | this.assert( 1245 | ok 1246 | , 'expected #{this} to ' + str 1247 | , 'expected #{this} to not ' + str 1248 | ); 1249 | } 1250 | 1251 | Assertion.addMethod('keys', assertKeys); 1252 | Assertion.addMethod('key', assertKeys); 1253 | 1254 | /** 1255 | * ### .throw(constructor) 1256 | * 1257 | * Asserts that the function target will throw a specific error, or specific type of error 1258 | * (as determined using `instanceof`), optionally with a RegExp or string inclusion test 1259 | * for the error's message. 1260 | * 1261 | * var err = new ReferenceError('This is a bad function.'); 1262 | * var fn = function () { throw err; } 1263 | * expect(fn).to.throw(ReferenceError); 1264 | * expect(fn).to.throw(Error); 1265 | * expect(fn).to.throw(/bad function/); 1266 | * expect(fn).to.not.throw('good function'); 1267 | * expect(fn).to.throw(ReferenceError, /bad function/); 1268 | * expect(fn).to.throw(err); 1269 | * expect(fn).to.not.throw(new RangeError('Out of range.')); 1270 | * 1271 | * Please note that when a throw expectation is negated, it will check each 1272 | * parameter independently, starting with error constructor type. The appropriate way 1273 | * to check for the existence of a type of error but for a message that does not match 1274 | * is to use `and`. 1275 | * 1276 | * expect(fn).to.throw(ReferenceError) 1277 | * .and.not.throw(/good function/); 1278 | * 1279 | * @name throw 1280 | * @alias throws 1281 | * @alias Throw 1282 | * @param {ErrorConstructor} constructor 1283 | * @param {String|RegExp} expected error message 1284 | * @param {String} message _optional_ 1285 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 1286 | * @api public 1287 | */ 1288 | 1289 | function assertThrows (constructor, errMsg, msg) { 1290 | if (msg) flag(this, 'message', msg); 1291 | var obj = flag(this, 'object'); 1292 | new Assertion(obj, msg).is.a('function'); 1293 | 1294 | var thrown = false 1295 | , desiredError = null 1296 | , name = null 1297 | , thrownError = null; 1298 | 1299 | if (arguments.length === 0) { 1300 | errMsg = null; 1301 | constructor = null; 1302 | } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { 1303 | errMsg = constructor; 1304 | constructor = null; 1305 | } else if (constructor && constructor instanceof Error) { 1306 | desiredError = constructor; 1307 | constructor = null; 1308 | errMsg = null; 1309 | } else if (typeof constructor === 'function') { 1310 | name = (new constructor()).name; 1311 | } else { 1312 | constructor = null; 1313 | } 1314 | 1315 | try { 1316 | obj(); 1317 | } catch (err) { 1318 | // first, check desired error 1319 | if (desiredError) { 1320 | this.assert( 1321 | err === desiredError 1322 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 1323 | , 'expected #{this} to not throw #{exp}' 1324 | , desiredError 1325 | , err 1326 | ); 1327 | 1328 | return this; 1329 | } 1330 | // next, check constructor 1331 | if (constructor) { 1332 | this.assert( 1333 | err instanceof constructor 1334 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 1335 | , 'expected #{this} to not throw #{exp} but #{act} was thrown' 1336 | , name 1337 | , err 1338 | ); 1339 | 1340 | if (!errMsg) return this; 1341 | } 1342 | // next, check message 1343 | var message = 'object' === _.type(err) && "message" in err 1344 | ? err.message 1345 | : '' + err; 1346 | 1347 | if ((message != null) && errMsg && errMsg instanceof RegExp) { 1348 | this.assert( 1349 | errMsg.exec(message) 1350 | , 'expected #{this} to throw error matching #{exp} but got #{act}' 1351 | , 'expected #{this} to throw error not matching #{exp}' 1352 | , errMsg 1353 | , message 1354 | ); 1355 | 1356 | return this; 1357 | } else if ((message != null) && errMsg && 'string' === typeof errMsg) { 1358 | this.assert( 1359 | ~message.indexOf(errMsg) 1360 | , 'expected #{this} to throw error including #{exp} but got #{act}' 1361 | , 'expected #{this} to throw error not including #{act}' 1362 | , errMsg 1363 | , message 1364 | ); 1365 | 1366 | return this; 1367 | } else { 1368 | thrown = true; 1369 | thrownError = err; 1370 | } 1371 | } 1372 | 1373 | var actuallyGot = '' 1374 | , expectedThrown = name !== null 1375 | ? name 1376 | : desiredError 1377 | ? '#{exp}' //_.inspect(desiredError) 1378 | : 'an error'; 1379 | 1380 | if (thrown) { 1381 | actuallyGot = ' but #{act} was thrown' 1382 | } 1383 | 1384 | this.assert( 1385 | thrown === true 1386 | , 'expected #{this} to throw ' + expectedThrown + actuallyGot 1387 | , 'expected #{this} to not throw ' + expectedThrown + actuallyGot 1388 | , desiredError 1389 | , thrownError 1390 | ); 1391 | }; 1392 | 1393 | Assertion.addMethod('throw', assertThrows); 1394 | Assertion.addMethod('throws', assertThrows); 1395 | Assertion.addMethod('Throw', assertThrows); 1396 | 1397 | /** 1398 | * ### .respondTo(method) 1399 | * 1400 | * Asserts that the object or class target will respond to a method. 1401 | * 1402 | * Klass.prototype.bar = function(){}; 1403 | * expect(Klass).to.respondTo('bar'); 1404 | * expect(obj).to.respondTo('bar'); 1405 | * 1406 | * To check if a constructor will respond to a static function, 1407 | * set the `itself` flag. 1408 | * 1409 | * Klass.baz = function(){}; 1410 | * expect(Klass).itself.to.respondTo('baz'); 1411 | * 1412 | * @name respondTo 1413 | * @param {String} method 1414 | * @param {String} message _optional_ 1415 | * @api public 1416 | */ 1417 | 1418 | Assertion.addMethod('respondTo', function (method, msg) { 1419 | if (msg) flag(this, 'message', msg); 1420 | var obj = flag(this, 'object') 1421 | , itself = flag(this, 'itself') 1422 | , context = ('function' === _.type(obj) && !itself) 1423 | ? obj.prototype[method] 1424 | : obj[method]; 1425 | 1426 | this.assert( 1427 | 'function' === typeof context 1428 | , 'expected #{this} to respond to ' + _.inspect(method) 1429 | , 'expected #{this} to not respond to ' + _.inspect(method) 1430 | ); 1431 | }); 1432 | 1433 | /** 1434 | * ### .itself 1435 | * 1436 | * Sets the `itself` flag, later used by the `respondTo` assertion. 1437 | * 1438 | * function Foo() {} 1439 | * Foo.bar = function() {} 1440 | * Foo.prototype.baz = function() {} 1441 | * 1442 | * expect(Foo).itself.to.respondTo('bar'); 1443 | * expect(Foo).itself.not.to.respondTo('baz'); 1444 | * 1445 | * @name itself 1446 | * @api public 1447 | */ 1448 | 1449 | Assertion.addProperty('itself', function () { 1450 | flag(this, 'itself', true); 1451 | }); 1452 | 1453 | /** 1454 | * ### .satisfy(method) 1455 | * 1456 | * Asserts that the target passes a given truth test. 1457 | * 1458 | * expect(1).to.satisfy(function(num) { return num > 0; }); 1459 | * 1460 | * @name satisfy 1461 | * @param {Function} matcher 1462 | * @param {String} message _optional_ 1463 | * @api public 1464 | */ 1465 | 1466 | Assertion.addMethod('satisfy', function (matcher, msg) { 1467 | if (msg) flag(this, 'message', msg); 1468 | var obj = flag(this, 'object'); 1469 | this.assert( 1470 | matcher(obj) 1471 | , 'expected #{this} to satisfy ' + _.objDisplay(matcher) 1472 | , 'expected #{this} to not satisfy' + _.objDisplay(matcher) 1473 | , this.negate ? false : true 1474 | , matcher(obj) 1475 | ); 1476 | }); 1477 | 1478 | /** 1479 | * ### .closeTo(expected, delta) 1480 | * 1481 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 1482 | * 1483 | * expect(1.5).to.be.closeTo(1, 0.5); 1484 | * 1485 | * @name closeTo 1486 | * @param {Number} expected 1487 | * @param {Number} delta 1488 | * @param {String} message _optional_ 1489 | * @api public 1490 | */ 1491 | 1492 | Assertion.addMethod('closeTo', function (expected, delta, msg) { 1493 | if (msg) flag(this, 'message', msg); 1494 | var obj = flag(this, 'object'); 1495 | this.assert( 1496 | Math.abs(obj - expected) <= delta 1497 | , 'expected #{this} to be close to ' + expected + ' +/- ' + delta 1498 | , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta 1499 | ); 1500 | }); 1501 | 1502 | }; 1503 | 1504 | }); // module: chai/core/assertions.js 1505 | 1506 | require.register("chai/error.js", function(module, exports, require){ 1507 | /*! 1508 | * chai 1509 | * Copyright(c) 2011-2013 Jake Luer 1510 | * MIT Licensed 1511 | */ 1512 | 1513 | /*! 1514 | * Main export 1515 | */ 1516 | 1517 | module.exports = AssertionError; 1518 | 1519 | /** 1520 | * # AssertionError (constructor) 1521 | * 1522 | * Create a new assertion error based on the Javascript 1523 | * `Error` prototype. 1524 | * 1525 | * **Options** 1526 | * - message 1527 | * - actual 1528 | * - expected 1529 | * - operator 1530 | * - startStackFunction 1531 | * 1532 | * @param {Object} options 1533 | * @api public 1534 | */ 1535 | 1536 | function AssertionError (options) { 1537 | options = options || {}; 1538 | this.message = options.message; 1539 | this.actual = options.actual; 1540 | this.expected = options.expected; 1541 | this.operator = options.operator; 1542 | this.showDiff = options.showDiff; 1543 | 1544 | if (options.stackStartFunction && Error.captureStackTrace) { 1545 | var stackStartFunction = options.stackStartFunction; 1546 | Error.captureStackTrace(this, stackStartFunction); 1547 | } 1548 | } 1549 | 1550 | /*! 1551 | * Inherit from Error 1552 | */ 1553 | 1554 | AssertionError.prototype = Object.create(Error.prototype); 1555 | AssertionError.prototype.name = 'AssertionError'; 1556 | AssertionError.prototype.constructor = AssertionError; 1557 | 1558 | /** 1559 | * # toString() 1560 | * 1561 | * Override default to string method 1562 | */ 1563 | 1564 | AssertionError.prototype.toString = function() { 1565 | return this.message; 1566 | }; 1567 | 1568 | }); // module: chai/error.js 1569 | 1570 | require.register("chai/interface/assert.js", function(module, exports, require){ 1571 | /*! 1572 | * chai 1573 | * Copyright(c) 2011-2013 Jake Luer 1574 | * MIT Licensed 1575 | */ 1576 | 1577 | 1578 | module.exports = function (chai, util) { 1579 | 1580 | /*! 1581 | * Chai dependencies. 1582 | */ 1583 | 1584 | var Assertion = chai.Assertion 1585 | , flag = util.flag; 1586 | 1587 | /*! 1588 | * Module export. 1589 | */ 1590 | 1591 | /** 1592 | * ### assert(expression, message) 1593 | * 1594 | * Write your own test expressions. 1595 | * 1596 | * assert('foo' !== 'bar', 'foo is not bar'); 1597 | * assert(Array.isArray([]), 'empty arrays are arrays'); 1598 | * 1599 | * @param {Mixed} expression to test for truthiness 1600 | * @param {String} message to display on error 1601 | * @name assert 1602 | * @api public 1603 | */ 1604 | 1605 | var assert = chai.assert = function (express, errmsg) { 1606 | var test = new Assertion(null); 1607 | test.assert( 1608 | express 1609 | , errmsg 1610 | , '[ negation message unavailable ]' 1611 | ); 1612 | }; 1613 | 1614 | /** 1615 | * ### .fail(actual, expected, [message], [operator]) 1616 | * 1617 | * Throw a failure. Node.js `assert` module-compatible. 1618 | * 1619 | * @name fail 1620 | * @param {Mixed} actual 1621 | * @param {Mixed} expected 1622 | * @param {String} message 1623 | * @param {String} operator 1624 | * @api public 1625 | */ 1626 | 1627 | assert.fail = function (actual, expected, message, operator) { 1628 | throw new chai.AssertionError({ 1629 | actual: actual 1630 | , expected: expected 1631 | , message: message 1632 | , operator: operator 1633 | , stackStartFunction: assert.fail 1634 | }); 1635 | }; 1636 | 1637 | /** 1638 | * ### .ok(object, [message]) 1639 | * 1640 | * Asserts that `object` is truthy. 1641 | * 1642 | * assert.ok('everything', 'everything is ok'); 1643 | * assert.ok(false, 'this will fail'); 1644 | * 1645 | * @name ok 1646 | * @param {Mixed} object to test 1647 | * @param {String} message 1648 | * @api public 1649 | */ 1650 | 1651 | assert.ok = function (val, msg) { 1652 | new Assertion(val, msg).is.ok; 1653 | }; 1654 | 1655 | /** 1656 | * ### .equal(actual, expected, [message]) 1657 | * 1658 | * Asserts non-strict equality (`==`) of `actual` and `expected`. 1659 | * 1660 | * assert.equal(3, '3', '== coerces values to strings'); 1661 | * 1662 | * @name equal 1663 | * @param {Mixed} actual 1664 | * @param {Mixed} expected 1665 | * @param {String} message 1666 | * @api public 1667 | */ 1668 | 1669 | assert.equal = function (act, exp, msg) { 1670 | var test = new Assertion(act, msg); 1671 | 1672 | test.assert( 1673 | exp == flag(test, 'object') 1674 | , 'expected #{this} to equal #{exp}' 1675 | , 'expected #{this} to not equal #{act}' 1676 | , exp 1677 | , act 1678 | ); 1679 | }; 1680 | 1681 | /** 1682 | * ### .notEqual(actual, expected, [message]) 1683 | * 1684 | * Asserts non-strict inequality (`!=`) of `actual` and `expected`. 1685 | * 1686 | * assert.notEqual(3, 4, 'these numbers are not equal'); 1687 | * 1688 | * @name notEqual 1689 | * @param {Mixed} actual 1690 | * @param {Mixed} expected 1691 | * @param {String} message 1692 | * @api public 1693 | */ 1694 | 1695 | assert.notEqual = function (act, exp, msg) { 1696 | var test = new Assertion(act, msg); 1697 | 1698 | test.assert( 1699 | exp != flag(test, 'object') 1700 | , 'expected #{this} to not equal #{exp}' 1701 | , 'expected #{this} to equal #{act}' 1702 | , exp 1703 | , act 1704 | ); 1705 | }; 1706 | 1707 | /** 1708 | * ### .strictEqual(actual, expected, [message]) 1709 | * 1710 | * Asserts strict equality (`===`) of `actual` and `expected`. 1711 | * 1712 | * assert.strictEqual(true, true, 'these booleans are strictly equal'); 1713 | * 1714 | * @name strictEqual 1715 | * @param {Mixed} actual 1716 | * @param {Mixed} expected 1717 | * @param {String} message 1718 | * @api public 1719 | */ 1720 | 1721 | assert.strictEqual = function (act, exp, msg) { 1722 | new Assertion(act, msg).to.equal(exp); 1723 | }; 1724 | 1725 | /** 1726 | * ### .notStrictEqual(actual, expected, [message]) 1727 | * 1728 | * Asserts strict inequality (`!==`) of `actual` and `expected`. 1729 | * 1730 | * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); 1731 | * 1732 | * @name notStrictEqual 1733 | * @param {Mixed} actual 1734 | * @param {Mixed} expected 1735 | * @param {String} message 1736 | * @api public 1737 | */ 1738 | 1739 | assert.notStrictEqual = function (act, exp, msg) { 1740 | new Assertion(act, msg).to.not.equal(exp); 1741 | }; 1742 | 1743 | /** 1744 | * ### .deepEqual(actual, expected, [message]) 1745 | * 1746 | * Asserts that `actual` is deeply equal to `expected`. 1747 | * 1748 | * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); 1749 | * 1750 | * @name deepEqual 1751 | * @param {Mixed} actual 1752 | * @param {Mixed} expected 1753 | * @param {String} message 1754 | * @api public 1755 | */ 1756 | 1757 | assert.deepEqual = function (act, exp, msg) { 1758 | new Assertion(act, msg).to.eql(exp); 1759 | }; 1760 | 1761 | /** 1762 | * ### .notDeepEqual(actual, expected, [message]) 1763 | * 1764 | * Assert that `actual` is not deeply equal to `expected`. 1765 | * 1766 | * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); 1767 | * 1768 | * @name notDeepEqual 1769 | * @param {Mixed} actual 1770 | * @param {Mixed} expected 1771 | * @param {String} message 1772 | * @api public 1773 | */ 1774 | 1775 | assert.notDeepEqual = function (act, exp, msg) { 1776 | new Assertion(act, msg).to.not.eql(exp); 1777 | }; 1778 | 1779 | /** 1780 | * ### .isTrue(value, [message]) 1781 | * 1782 | * Asserts that `value` is true. 1783 | * 1784 | * var teaServed = true; 1785 | * assert.isTrue(teaServed, 'the tea has been served'); 1786 | * 1787 | * @name isTrue 1788 | * @param {Mixed} value 1789 | * @param {String} message 1790 | * @api public 1791 | */ 1792 | 1793 | assert.isTrue = function (val, msg) { 1794 | new Assertion(val, msg).is['true']; 1795 | }; 1796 | 1797 | /** 1798 | * ### .isFalse(value, [message]) 1799 | * 1800 | * Asserts that `value` is false. 1801 | * 1802 | * var teaServed = false; 1803 | * assert.isFalse(teaServed, 'no tea yet? hmm...'); 1804 | * 1805 | * @name isFalse 1806 | * @param {Mixed} value 1807 | * @param {String} message 1808 | * @api public 1809 | */ 1810 | 1811 | assert.isFalse = function (val, msg) { 1812 | new Assertion(val, msg).is['false']; 1813 | }; 1814 | 1815 | /** 1816 | * ### .isNull(value, [message]) 1817 | * 1818 | * Asserts that `value` is null. 1819 | * 1820 | * assert.isNull(err, 'there was no error'); 1821 | * 1822 | * @name isNull 1823 | * @param {Mixed} value 1824 | * @param {String} message 1825 | * @api public 1826 | */ 1827 | 1828 | assert.isNull = function (val, msg) { 1829 | new Assertion(val, msg).to.equal(null); 1830 | }; 1831 | 1832 | /** 1833 | * ### .isNotNull(value, [message]) 1834 | * 1835 | * Asserts that `value` is not null. 1836 | * 1837 | * var tea = 'tasty chai'; 1838 | * assert.isNotNull(tea, 'great, time for tea!'); 1839 | * 1840 | * @name isNotNull 1841 | * @param {Mixed} value 1842 | * @param {String} message 1843 | * @api public 1844 | */ 1845 | 1846 | assert.isNotNull = function (val, msg) { 1847 | new Assertion(val, msg).to.not.equal(null); 1848 | }; 1849 | 1850 | /** 1851 | * ### .isUndefined(value, [message]) 1852 | * 1853 | * Asserts that `value` is `undefined`. 1854 | * 1855 | * var tea; 1856 | * assert.isUndefined(tea, 'no tea defined'); 1857 | * 1858 | * @name isUndefined 1859 | * @param {Mixed} value 1860 | * @param {String} message 1861 | * @api public 1862 | */ 1863 | 1864 | assert.isUndefined = function (val, msg) { 1865 | new Assertion(val, msg).to.equal(undefined); 1866 | }; 1867 | 1868 | /** 1869 | * ### .isDefined(value, [message]) 1870 | * 1871 | * Asserts that `value` is not `undefined`. 1872 | * 1873 | * var tea = 'cup of chai'; 1874 | * assert.isDefined(tea, 'tea has been defined'); 1875 | * 1876 | * @name isUndefined 1877 | * @param {Mixed} value 1878 | * @param {String} message 1879 | * @api public 1880 | */ 1881 | 1882 | assert.isDefined = function (val, msg) { 1883 | new Assertion(val, msg).to.not.equal(undefined); 1884 | }; 1885 | 1886 | /** 1887 | * ### .isFunction(value, [message]) 1888 | * 1889 | * Asserts that `value` is a function. 1890 | * 1891 | * function serveTea() { return 'cup of tea'; }; 1892 | * assert.isFunction(serveTea, 'great, we can have tea now'); 1893 | * 1894 | * @name isFunction 1895 | * @param {Mixed} value 1896 | * @param {String} message 1897 | * @api public 1898 | */ 1899 | 1900 | assert.isFunction = function (val, msg) { 1901 | new Assertion(val, msg).to.be.a('function'); 1902 | }; 1903 | 1904 | /** 1905 | * ### .isNotFunction(value, [message]) 1906 | * 1907 | * Asserts that `value` is _not_ a function. 1908 | * 1909 | * var serveTea = [ 'heat', 'pour', 'sip' ]; 1910 | * assert.isNotFunction(serveTea, 'great, we have listed the steps'); 1911 | * 1912 | * @name isNotFunction 1913 | * @param {Mixed} value 1914 | * @param {String} message 1915 | * @api public 1916 | */ 1917 | 1918 | assert.isNotFunction = function (val, msg) { 1919 | new Assertion(val, msg).to.not.be.a('function'); 1920 | }; 1921 | 1922 | /** 1923 | * ### .isObject(value, [message]) 1924 | * 1925 | * Asserts that `value` is an object (as revealed by 1926 | * `Object.prototype.toString`). 1927 | * 1928 | * var selection = { name: 'Chai', serve: 'with spices' }; 1929 | * assert.isObject(selection, 'tea selection is an object'); 1930 | * 1931 | * @name isObject 1932 | * @param {Mixed} value 1933 | * @param {String} message 1934 | * @api public 1935 | */ 1936 | 1937 | assert.isObject = function (val, msg) { 1938 | new Assertion(val, msg).to.be.a('object'); 1939 | }; 1940 | 1941 | /** 1942 | * ### .isNotObject(value, [message]) 1943 | * 1944 | * Asserts that `value` is _not_ an object. 1945 | * 1946 | * var selection = 'chai' 1947 | * assert.isObject(selection, 'tea selection is not an object'); 1948 | * assert.isObject(null, 'null is not an object'); 1949 | * 1950 | * @name isNotObject 1951 | * @param {Mixed} value 1952 | * @param {String} message 1953 | * @api public 1954 | */ 1955 | 1956 | assert.isNotObject = function (val, msg) { 1957 | new Assertion(val, msg).to.not.be.a('object'); 1958 | }; 1959 | 1960 | /** 1961 | * ### .isArray(value, [message]) 1962 | * 1963 | * Asserts that `value` is an array. 1964 | * 1965 | * var menu = [ 'green', 'chai', 'oolong' ]; 1966 | * assert.isArray(menu, 'what kind of tea do we want?'); 1967 | * 1968 | * @name isArray 1969 | * @param {Mixed} value 1970 | * @param {String} message 1971 | * @api public 1972 | */ 1973 | 1974 | assert.isArray = function (val, msg) { 1975 | new Assertion(val, msg).to.be.an('array'); 1976 | }; 1977 | 1978 | /** 1979 | * ### .isNotArray(value, [message]) 1980 | * 1981 | * Asserts that `value` is _not_ an array. 1982 | * 1983 | * var menu = 'green|chai|oolong'; 1984 | * assert.isNotArray(menu, 'what kind of tea do we want?'); 1985 | * 1986 | * @name isNotArray 1987 | * @param {Mixed} value 1988 | * @param {String} message 1989 | * @api public 1990 | */ 1991 | 1992 | assert.isNotArray = function (val, msg) { 1993 | new Assertion(val, msg).to.not.be.an('array'); 1994 | }; 1995 | 1996 | /** 1997 | * ### .isString(value, [message]) 1998 | * 1999 | * Asserts that `value` is a string. 2000 | * 2001 | * var teaOrder = 'chai'; 2002 | * assert.isString(teaOrder, 'order placed'); 2003 | * 2004 | * @name isString 2005 | * @param {Mixed} value 2006 | * @param {String} message 2007 | * @api public 2008 | */ 2009 | 2010 | assert.isString = function (val, msg) { 2011 | new Assertion(val, msg).to.be.a('string'); 2012 | }; 2013 | 2014 | /** 2015 | * ### .isNotString(value, [message]) 2016 | * 2017 | * Asserts that `value` is _not_ a string. 2018 | * 2019 | * var teaOrder = 4; 2020 | * assert.isNotString(teaOrder, 'order placed'); 2021 | * 2022 | * @name isNotString 2023 | * @param {Mixed} value 2024 | * @param {String} message 2025 | * @api public 2026 | */ 2027 | 2028 | assert.isNotString = function (val, msg) { 2029 | new Assertion(val, msg).to.not.be.a('string'); 2030 | }; 2031 | 2032 | /** 2033 | * ### .isNumber(value, [message]) 2034 | * 2035 | * Asserts that `value` is a number. 2036 | * 2037 | * var cups = 2; 2038 | * assert.isNumber(cups, 'how many cups'); 2039 | * 2040 | * @name isNumber 2041 | * @param {Number} value 2042 | * @param {String} message 2043 | * @api public 2044 | */ 2045 | 2046 | assert.isNumber = function (val, msg) { 2047 | new Assertion(val, msg).to.be.a('number'); 2048 | }; 2049 | 2050 | /** 2051 | * ### .isNotNumber(value, [message]) 2052 | * 2053 | * Asserts that `value` is _not_ a number. 2054 | * 2055 | * var cups = '2 cups please'; 2056 | * assert.isNotNumber(cups, 'how many cups'); 2057 | * 2058 | * @name isNotNumber 2059 | * @param {Mixed} value 2060 | * @param {String} message 2061 | * @api public 2062 | */ 2063 | 2064 | assert.isNotNumber = function (val, msg) { 2065 | new Assertion(val, msg).to.not.be.a('number'); 2066 | }; 2067 | 2068 | /** 2069 | * ### .isBoolean(value, [message]) 2070 | * 2071 | * Asserts that `value` is a boolean. 2072 | * 2073 | * var teaReady = true 2074 | * , teaServed = false; 2075 | * 2076 | * assert.isBoolean(teaReady, 'is the tea ready'); 2077 | * assert.isBoolean(teaServed, 'has tea been served'); 2078 | * 2079 | * @name isBoolean 2080 | * @param {Mixed} value 2081 | * @param {String} message 2082 | * @api public 2083 | */ 2084 | 2085 | assert.isBoolean = function (val, msg) { 2086 | new Assertion(val, msg).to.be.a('boolean'); 2087 | }; 2088 | 2089 | /** 2090 | * ### .isNotBoolean(value, [message]) 2091 | * 2092 | * Asserts that `value` is _not_ a boolean. 2093 | * 2094 | * var teaReady = 'yep' 2095 | * , teaServed = 'nope'; 2096 | * 2097 | * assert.isNotBoolean(teaReady, 'is the tea ready'); 2098 | * assert.isNotBoolean(teaServed, 'has tea been served'); 2099 | * 2100 | * @name isNotBoolean 2101 | * @param {Mixed} value 2102 | * @param {String} message 2103 | * @api public 2104 | */ 2105 | 2106 | assert.isNotBoolean = function (val, msg) { 2107 | new Assertion(val, msg).to.not.be.a('boolean'); 2108 | }; 2109 | 2110 | /** 2111 | * ### .typeOf(value, name, [message]) 2112 | * 2113 | * Asserts that `value`'s type is `name`, as determined by 2114 | * `Object.prototype.toString`. 2115 | * 2116 | * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); 2117 | * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); 2118 | * assert.typeOf('tea', 'string', 'we have a string'); 2119 | * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); 2120 | * assert.typeOf(null, 'null', 'we have a null'); 2121 | * assert.typeOf(undefined, 'undefined', 'we have an undefined'); 2122 | * 2123 | * @name typeOf 2124 | * @param {Mixed} value 2125 | * @param {String} name 2126 | * @param {String} message 2127 | * @api public 2128 | */ 2129 | 2130 | assert.typeOf = function (val, type, msg) { 2131 | new Assertion(val, msg).to.be.a(type); 2132 | }; 2133 | 2134 | /** 2135 | * ### .notTypeOf(value, name, [message]) 2136 | * 2137 | * Asserts that `value`'s type is _not_ `name`, as determined by 2138 | * `Object.prototype.toString`. 2139 | * 2140 | * assert.notTypeOf('tea', 'number', 'strings are not numbers'); 2141 | * 2142 | * @name notTypeOf 2143 | * @param {Mixed} value 2144 | * @param {String} typeof name 2145 | * @param {String} message 2146 | * @api public 2147 | */ 2148 | 2149 | assert.notTypeOf = function (val, type, msg) { 2150 | new Assertion(val, msg).to.not.be.a(type); 2151 | }; 2152 | 2153 | /** 2154 | * ### .instanceOf(object, constructor, [message]) 2155 | * 2156 | * Asserts that `value` is an instance of `constructor`. 2157 | * 2158 | * var Tea = function (name) { this.name = name; } 2159 | * , chai = new Tea('chai'); 2160 | * 2161 | * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); 2162 | * 2163 | * @name instanceOf 2164 | * @param {Object} object 2165 | * @param {Constructor} constructor 2166 | * @param {String} message 2167 | * @api public 2168 | */ 2169 | 2170 | assert.instanceOf = function (val, type, msg) { 2171 | new Assertion(val, msg).to.be.instanceOf(type); 2172 | }; 2173 | 2174 | /** 2175 | * ### .notInstanceOf(object, constructor, [message]) 2176 | * 2177 | * Asserts `value` is not an instance of `constructor`. 2178 | * 2179 | * var Tea = function (name) { this.name = name; } 2180 | * , chai = new String('chai'); 2181 | * 2182 | * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); 2183 | * 2184 | * @name notInstanceOf 2185 | * @param {Object} object 2186 | * @param {Constructor} constructor 2187 | * @param {String} message 2188 | * @api public 2189 | */ 2190 | 2191 | assert.notInstanceOf = function (val, type, msg) { 2192 | new Assertion(val, msg).to.not.be.instanceOf(type); 2193 | }; 2194 | 2195 | /** 2196 | * ### .include(haystack, needle, [message]) 2197 | * 2198 | * Asserts that `haystack` includes `needle`. Works 2199 | * for strings and arrays. 2200 | * 2201 | * assert.include('foobar', 'bar', 'foobar contains string "bar"'); 2202 | * assert.include([ 1, 2, 3 ], 3, 'array contains value'); 2203 | * 2204 | * @name include 2205 | * @param {Array|String} haystack 2206 | * @param {Mixed} needle 2207 | * @param {String} message 2208 | * @api public 2209 | */ 2210 | 2211 | assert.include = function (exp, inc, msg) { 2212 | var obj = new Assertion(exp, msg); 2213 | 2214 | if (Array.isArray(exp)) { 2215 | obj.to.include(inc); 2216 | } else if ('string' === typeof exp) { 2217 | obj.to.contain.string(inc); 2218 | } 2219 | }; 2220 | 2221 | /** 2222 | * ### .match(value, regexp, [message]) 2223 | * 2224 | * Asserts that `value` matches the regular expression `regexp`. 2225 | * 2226 | * assert.match('foobar', /^foo/, 'regexp matches'); 2227 | * 2228 | * @name match 2229 | * @param {Mixed} value 2230 | * @param {RegExp} regexp 2231 | * @param {String} message 2232 | * @api public 2233 | */ 2234 | 2235 | assert.match = function (exp, re, msg) { 2236 | new Assertion(exp, msg).to.match(re); 2237 | }; 2238 | 2239 | /** 2240 | * ### .notMatch(value, regexp, [message]) 2241 | * 2242 | * Asserts that `value` does not match the regular expression `regexp`. 2243 | * 2244 | * assert.notMatch('foobar', /^foo/, 'regexp does not match'); 2245 | * 2246 | * @name notMatch 2247 | * @param {Mixed} value 2248 | * @param {RegExp} regexp 2249 | * @param {String} message 2250 | * @api public 2251 | */ 2252 | 2253 | assert.notMatch = function (exp, re, msg) { 2254 | new Assertion(exp, msg).to.not.match(re); 2255 | }; 2256 | 2257 | /** 2258 | * ### .property(object, property, [message]) 2259 | * 2260 | * Asserts that `object` has a property named by `property`. 2261 | * 2262 | * assert.property({ tea: { green: 'matcha' }}, 'tea'); 2263 | * 2264 | * @name property 2265 | * @param {Object} object 2266 | * @param {String} property 2267 | * @param {String} message 2268 | * @api public 2269 | */ 2270 | 2271 | assert.property = function (obj, prop, msg) { 2272 | new Assertion(obj, msg).to.have.property(prop); 2273 | }; 2274 | 2275 | /** 2276 | * ### .notProperty(object, property, [message]) 2277 | * 2278 | * Asserts that `object` does _not_ have a property named by `property`. 2279 | * 2280 | * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); 2281 | * 2282 | * @name notProperty 2283 | * @param {Object} object 2284 | * @param {String} property 2285 | * @param {String} message 2286 | * @api public 2287 | */ 2288 | 2289 | assert.notProperty = function (obj, prop, msg) { 2290 | new Assertion(obj, msg).to.not.have.property(prop); 2291 | }; 2292 | 2293 | /** 2294 | * ### .deepProperty(object, property, [message]) 2295 | * 2296 | * Asserts that `object` has a property named by `property`, which can be a 2297 | * string using dot- and bracket-notation for deep reference. 2298 | * 2299 | * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); 2300 | * 2301 | * @name deepProperty 2302 | * @param {Object} object 2303 | * @param {String} property 2304 | * @param {String} message 2305 | * @api public 2306 | */ 2307 | 2308 | assert.deepProperty = function (obj, prop, msg) { 2309 | new Assertion(obj, msg).to.have.deep.property(prop); 2310 | }; 2311 | 2312 | /** 2313 | * ### .notDeepProperty(object, property, [message]) 2314 | * 2315 | * Asserts that `object` does _not_ have a property named by `property`, which 2316 | * can be a string using dot- and bracket-notation for deep reference. 2317 | * 2318 | * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); 2319 | * 2320 | * @name notDeepProperty 2321 | * @param {Object} object 2322 | * @param {String} property 2323 | * @param {String} message 2324 | * @api public 2325 | */ 2326 | 2327 | assert.notDeepProperty = function (obj, prop, msg) { 2328 | new Assertion(obj, msg).to.not.have.deep.property(prop); 2329 | }; 2330 | 2331 | /** 2332 | * ### .propertyVal(object, property, value, [message]) 2333 | * 2334 | * Asserts that `object` has a property named by `property` with value given 2335 | * by `value`. 2336 | * 2337 | * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); 2338 | * 2339 | * @name propertyVal 2340 | * @param {Object} object 2341 | * @param {String} property 2342 | * @param {Mixed} value 2343 | * @param {String} message 2344 | * @api public 2345 | */ 2346 | 2347 | assert.propertyVal = function (obj, prop, val, msg) { 2348 | new Assertion(obj, msg).to.have.property(prop, val); 2349 | }; 2350 | 2351 | /** 2352 | * ### .propertyNotVal(object, property, value, [message]) 2353 | * 2354 | * Asserts that `object` has a property named by `property`, but with a value 2355 | * different from that given by `value`. 2356 | * 2357 | * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); 2358 | * 2359 | * @name propertyNotVal 2360 | * @param {Object} object 2361 | * @param {String} property 2362 | * @param {Mixed} value 2363 | * @param {String} message 2364 | * @api public 2365 | */ 2366 | 2367 | assert.propertyNotVal = function (obj, prop, val, msg) { 2368 | new Assertion(obj, msg).to.not.have.property(prop, val); 2369 | }; 2370 | 2371 | /** 2372 | * ### .deepPropertyVal(object, property, value, [message]) 2373 | * 2374 | * Asserts that `object` has a property named by `property` with value given 2375 | * by `value`. `property` can use dot- and bracket-notation for deep 2376 | * reference. 2377 | * 2378 | * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); 2379 | * 2380 | * @name deepPropertyVal 2381 | * @param {Object} object 2382 | * @param {String} property 2383 | * @param {Mixed} value 2384 | * @param {String} message 2385 | * @api public 2386 | */ 2387 | 2388 | assert.deepPropertyVal = function (obj, prop, val, msg) { 2389 | new Assertion(obj, msg).to.have.deep.property(prop, val); 2390 | }; 2391 | 2392 | /** 2393 | * ### .deepPropertyNotVal(object, property, value, [message]) 2394 | * 2395 | * Asserts that `object` has a property named by `property`, but with a value 2396 | * different from that given by `value`. `property` can use dot- and 2397 | * bracket-notation for deep reference. 2398 | * 2399 | * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); 2400 | * 2401 | * @name deepPropertyNotVal 2402 | * @param {Object} object 2403 | * @param {String} property 2404 | * @param {Mixed} value 2405 | * @param {String} message 2406 | * @api public 2407 | */ 2408 | 2409 | assert.deepPropertyNotVal = function (obj, prop, val, msg) { 2410 | new Assertion(obj, msg).to.not.have.deep.property(prop, val); 2411 | }; 2412 | 2413 | /** 2414 | * ### .lengthOf(object, length, [message]) 2415 | * 2416 | * Asserts that `object` has a `length` property with the expected value. 2417 | * 2418 | * assert.lengthOf([1,2,3], 3, 'array has length of 3'); 2419 | * assert.lengthOf('foobar', 5, 'string has length of 6'); 2420 | * 2421 | * @name lengthOf 2422 | * @param {Mixed} object 2423 | * @param {Number} length 2424 | * @param {String} message 2425 | * @api public 2426 | */ 2427 | 2428 | assert.lengthOf = function (exp, len, msg) { 2429 | new Assertion(exp, msg).to.have.length(len); 2430 | }; 2431 | 2432 | /** 2433 | * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) 2434 | * 2435 | * Asserts that `function` will throw an error that is an instance of 2436 | * `constructor`, or alternately that it will throw an error with message 2437 | * matching `regexp`. 2438 | * 2439 | * assert.throw(fn, 'function throws a reference error'); 2440 | * assert.throw(fn, /function throws a reference error/); 2441 | * assert.throw(fn, ReferenceError); 2442 | * assert.throw(fn, ReferenceError, 'function throws a reference error'); 2443 | * assert.throw(fn, ReferenceError, /function throws a reference error/); 2444 | * 2445 | * @name throws 2446 | * @alias throw 2447 | * @alias Throw 2448 | * @param {Function} function 2449 | * @param {ErrorConstructor} constructor 2450 | * @param {RegExp} regexp 2451 | * @param {String} message 2452 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 2453 | * @api public 2454 | */ 2455 | 2456 | assert.Throw = function (fn, errt, errs, msg) { 2457 | if ('string' === typeof errt || errt instanceof RegExp) { 2458 | errs = errt; 2459 | errt = null; 2460 | } 2461 | 2462 | new Assertion(fn, msg).to.Throw(errt, errs); 2463 | }; 2464 | 2465 | /** 2466 | * ### .doesNotThrow(function, [constructor/regexp], [message]) 2467 | * 2468 | * Asserts that `function` will _not_ throw an error that is an instance of 2469 | * `constructor`, or alternately that it will not throw an error with message 2470 | * matching `regexp`. 2471 | * 2472 | * assert.doesNotThrow(fn, Error, 'function does not throw'); 2473 | * 2474 | * @name doesNotThrow 2475 | * @param {Function} function 2476 | * @param {ErrorConstructor} constructor 2477 | * @param {RegExp} regexp 2478 | * @param {String} message 2479 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 2480 | * @api public 2481 | */ 2482 | 2483 | assert.doesNotThrow = function (fn, type, msg) { 2484 | if ('string' === typeof type) { 2485 | msg = type; 2486 | type = null; 2487 | } 2488 | 2489 | new Assertion(fn, msg).to.not.Throw(type); 2490 | }; 2491 | 2492 | /** 2493 | * ### .operator(val1, operator, val2, [message]) 2494 | * 2495 | * Compares two values using `operator`. 2496 | * 2497 | * assert.operator(1, '<', 2, 'everything is ok'); 2498 | * assert.operator(1, '>', 2, 'this will fail'); 2499 | * 2500 | * @name operator 2501 | * @param {Mixed} val1 2502 | * @param {String} operator 2503 | * @param {Mixed} val2 2504 | * @param {String} message 2505 | * @api public 2506 | */ 2507 | 2508 | assert.operator = function (val, operator, val2, msg) { 2509 | if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) { 2510 | throw new Error('Invalid operator "' + operator + '"'); 2511 | } 2512 | var test = new Assertion(eval(val + operator + val2), msg); 2513 | test.assert( 2514 | true === flag(test, 'object') 2515 | , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) 2516 | , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); 2517 | }; 2518 | 2519 | /** 2520 | * ### .closeTo(actual, expected, delta, [message]) 2521 | * 2522 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 2523 | * 2524 | * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); 2525 | * 2526 | * @name closeTo 2527 | * @param {Number} actual 2528 | * @param {Number} expected 2529 | * @param {Number} delta 2530 | * @param {String} message 2531 | * @api public 2532 | */ 2533 | 2534 | assert.closeTo = function (act, exp, delta, msg) { 2535 | new Assertion(act, msg).to.be.closeTo(exp, delta); 2536 | }; 2537 | 2538 | /*! 2539 | * Undocumented / untested 2540 | */ 2541 | 2542 | assert.ifError = function (val, msg) { 2543 | new Assertion(val, msg).to.not.be.ok; 2544 | }; 2545 | 2546 | /*! 2547 | * Aliases. 2548 | */ 2549 | 2550 | (function alias(name, as){ 2551 | assert[as] = assert[name]; 2552 | return alias; 2553 | }) 2554 | ('Throw', 'throw') 2555 | ('Throw', 'throws'); 2556 | }; 2557 | 2558 | }); // module: chai/interface/assert.js 2559 | 2560 | require.register("chai/interface/expect.js", function(module, exports, require){ 2561 | /*! 2562 | * chai 2563 | * Copyright(c) 2011-2013 Jake Luer 2564 | * MIT Licensed 2565 | */ 2566 | 2567 | module.exports = function (chai, util) { 2568 | chai.expect = function (val, message) { 2569 | return new chai.Assertion(val, message); 2570 | }; 2571 | }; 2572 | 2573 | 2574 | }); // module: chai/interface/expect.js 2575 | 2576 | require.register("chai/interface/should.js", function(module, exports, require){ 2577 | /*! 2578 | * chai 2579 | * Copyright(c) 2011-2013 Jake Luer 2580 | * MIT Licensed 2581 | */ 2582 | 2583 | module.exports = function (chai, util) { 2584 | var Assertion = chai.Assertion; 2585 | 2586 | function loadShould () { 2587 | // modify Object.prototype to have `should` 2588 | Object.defineProperty(Object.prototype, 'should', 2589 | { 2590 | set: function (value) { 2591 | // See https://github.com/chaijs/chai/issues/86: this makes 2592 | // `whatever.should = someValue` actually set `someValue`, which is 2593 | // especially useful for `global.should = require('chai').should()`. 2594 | // 2595 | // Note that we have to use [[DefineProperty]] instead of [[Put]] 2596 | // since otherwise we would trigger this very setter! 2597 | Object.defineProperty(this, 'should', { 2598 | value: value, 2599 | enumerable: true, 2600 | configurable: true, 2601 | writable: true 2602 | }); 2603 | } 2604 | , get: function(){ 2605 | if (this instanceof String || this instanceof Number) { 2606 | return new Assertion(this.constructor(this)); 2607 | } else if (this instanceof Boolean) { 2608 | return new Assertion(this == true); 2609 | } 2610 | return new Assertion(this); 2611 | } 2612 | , configurable: true 2613 | }); 2614 | 2615 | var should = {}; 2616 | 2617 | should.equal = function (val1, val2, msg) { 2618 | new Assertion(val1, msg).to.equal(val2); 2619 | }; 2620 | 2621 | should.Throw = function (fn, errt, errs, msg) { 2622 | new Assertion(fn, msg).to.Throw(errt, errs); 2623 | }; 2624 | 2625 | should.exist = function (val, msg) { 2626 | new Assertion(val, msg).to.exist; 2627 | } 2628 | 2629 | // negation 2630 | should.not = {} 2631 | 2632 | should.not.equal = function (val1, val2, msg) { 2633 | new Assertion(val1, msg).to.not.equal(val2); 2634 | }; 2635 | 2636 | should.not.Throw = function (fn, errt, errs, msg) { 2637 | new Assertion(fn, msg).to.not.Throw(errt, errs); 2638 | }; 2639 | 2640 | should.not.exist = function (val, msg) { 2641 | new Assertion(val, msg).to.not.exist; 2642 | } 2643 | 2644 | should['throw'] = should['Throw']; 2645 | should.not['throw'] = should.not['Throw']; 2646 | 2647 | return should; 2648 | }; 2649 | 2650 | chai.should = loadShould; 2651 | chai.Should = loadShould; 2652 | }; 2653 | 2654 | }); // module: chai/interface/should.js 2655 | 2656 | require.register("chai/utils/addChainableMethod.js", function(module, exports, require){ 2657 | /*! 2658 | * Chai - addChainingMethod utility 2659 | * Copyright(c) 2012-2013 Jake Luer 2660 | * MIT Licensed 2661 | */ 2662 | 2663 | /*! 2664 | * Module dependencies 2665 | */ 2666 | 2667 | var transferFlags = require('./transferFlags'); 2668 | 2669 | /*! 2670 | * Module variables 2671 | */ 2672 | 2673 | // Check whether `__proto__` is supported 2674 | var hasProtoSupport = '__proto__' in Object; 2675 | 2676 | // Without `__proto__` support, this module will need to add properties to a function. 2677 | // However, some Function.prototype methods cannot be overwritten, 2678 | // and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). 2679 | var excludeNames = /^(?:length|name|arguments|caller)$/; 2680 | 2681 | /** 2682 | * ### addChainableMethod (ctx, name, method, chainingBehavior) 2683 | * 2684 | * Adds a method to an object, such that the method can also be chained. 2685 | * 2686 | * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { 2687 | * var obj = utils.flag(this, 'object'); 2688 | * new chai.Assertion(obj).to.be.equal(str); 2689 | * }); 2690 | * 2691 | * Can also be accessed directly from `chai.Assertion`. 2692 | * 2693 | * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); 2694 | * 2695 | * The result can then be used as both a method assertion, executing both `method` and 2696 | * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. 2697 | * 2698 | * expect(fooStr).to.be.foo('bar'); 2699 | * expect(fooStr).to.be.foo.equal('foo'); 2700 | * 2701 | * @param {Object} ctx object to which the method is added 2702 | * @param {String} name of method to add 2703 | * @param {Function} method function to be used for `name`, when called 2704 | * @param {Function} chainingBehavior function to be called every time the property is accessed 2705 | * @name addChainableMethod 2706 | * @api public 2707 | */ 2708 | 2709 | module.exports = function (ctx, name, method, chainingBehavior) { 2710 | if (typeof chainingBehavior !== 'function') 2711 | chainingBehavior = function () { }; 2712 | 2713 | Object.defineProperty(ctx, name, 2714 | { get: function () { 2715 | chainingBehavior.call(this); 2716 | 2717 | var assert = function () { 2718 | var result = method.apply(this, arguments); 2719 | return result === undefined ? this : result; 2720 | }; 2721 | 2722 | // Use `__proto__` if available 2723 | if (hasProtoSupport) { 2724 | assert.__proto__ = this; 2725 | } 2726 | // Otherwise, redefine all properties (slow!) 2727 | else { 2728 | var asserterNames = Object.getOwnPropertyNames(ctx); 2729 | asserterNames.forEach(function (asserterName) { 2730 | if (!excludeNames.test(asserterName)) { 2731 | var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); 2732 | Object.defineProperty(assert, asserterName, pd); 2733 | } 2734 | }); 2735 | } 2736 | 2737 | transferFlags(this, assert); 2738 | return assert; 2739 | } 2740 | , configurable: true 2741 | }); 2742 | }; 2743 | 2744 | }); // module: chai/utils/addChainableMethod.js 2745 | 2746 | require.register("chai/utils/addMethod.js", function(module, exports, require){ 2747 | /*! 2748 | * Chai - addMethod utility 2749 | * Copyright(c) 2012-2013 Jake Luer 2750 | * MIT Licensed 2751 | */ 2752 | 2753 | /** 2754 | * ### .addMethod (ctx, name, method) 2755 | * 2756 | * Adds a method to the prototype of an object. 2757 | * 2758 | * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { 2759 | * var obj = utils.flag(this, 'object'); 2760 | * new chai.Assertion(obj).to.be.equal(str); 2761 | * }); 2762 | * 2763 | * Can also be accessed directly from `chai.Assertion`. 2764 | * 2765 | * chai.Assertion.addMethod('foo', fn); 2766 | * 2767 | * Then can be used as any other assertion. 2768 | * 2769 | * expect(fooStr).to.be.foo('bar'); 2770 | * 2771 | * @param {Object} ctx object to which the method is added 2772 | * @param {String} name of method to add 2773 | * @param {Function} method function to be used for name 2774 | * @name addMethod 2775 | * @api public 2776 | */ 2777 | 2778 | module.exports = function (ctx, name, method) { 2779 | ctx[name] = function () { 2780 | var result = method.apply(this, arguments); 2781 | return result === undefined ? this : result; 2782 | }; 2783 | }; 2784 | 2785 | }); // module: chai/utils/addMethod.js 2786 | 2787 | require.register("chai/utils/addProperty.js", function(module, exports, require){ 2788 | /*! 2789 | * Chai - addProperty utility 2790 | * Copyright(c) 2012-2013 Jake Luer 2791 | * MIT Licensed 2792 | */ 2793 | 2794 | /** 2795 | * ### addProperty (ctx, name, getter) 2796 | * 2797 | * Adds a property to the prototype of an object. 2798 | * 2799 | * utils.addProperty(chai.Assertion.prototype, 'foo', function () { 2800 | * var obj = utils.flag(this, 'object'); 2801 | * new chai.Assertion(obj).to.be.instanceof(Foo); 2802 | * }); 2803 | * 2804 | * Can also be accessed directly from `chai.Assertion`. 2805 | * 2806 | * chai.Assertion.addProperty('foo', fn); 2807 | * 2808 | * Then can be used as any other assertion. 2809 | * 2810 | * expect(myFoo).to.be.foo; 2811 | * 2812 | * @param {Object} ctx object to which the property is added 2813 | * @param {String} name of property to add 2814 | * @param {Function} getter function to be used for name 2815 | * @name addProperty 2816 | * @api public 2817 | */ 2818 | 2819 | module.exports = function (ctx, name, getter) { 2820 | Object.defineProperty(ctx, name, 2821 | { get: function () { 2822 | var result = getter.call(this); 2823 | return result === undefined ? this : result; 2824 | } 2825 | , configurable: true 2826 | }); 2827 | }; 2828 | 2829 | }); // module: chai/utils/addProperty.js 2830 | 2831 | require.register("chai/utils/eql.js", function(module, exports, require){ 2832 | // This is (almost) directly from Node.js assert 2833 | // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js 2834 | 2835 | module.exports = _deepEqual; 2836 | 2837 | var getEnumerableProperties = require('./getEnumerableProperties'); 2838 | 2839 | // for the browser 2840 | var Buffer; 2841 | try { 2842 | Buffer = require('buffer').Buffer; 2843 | } catch (ex) { 2844 | Buffer = { 2845 | isBuffer: function () { return false; } 2846 | }; 2847 | } 2848 | 2849 | function _deepEqual(actual, expected, memos) { 2850 | 2851 | // 7.1. All identical values are equivalent, as determined by ===. 2852 | if (actual === expected) { 2853 | return true; 2854 | 2855 | } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { 2856 | if (actual.length != expected.length) return false; 2857 | 2858 | for (var i = 0; i < actual.length; i++) { 2859 | if (actual[i] !== expected[i]) return false; 2860 | } 2861 | 2862 | return true; 2863 | 2864 | // 7.2. If the expected value is a Date object, the actual value is 2865 | // equivalent if it is also a Date object that refers to the same time. 2866 | } else if (actual instanceof Date && expected instanceof Date) { 2867 | return actual.getTime() === expected.getTime(); 2868 | 2869 | // 7.3. Other pairs that do not both pass typeof value == 'object', 2870 | // equivalence is determined by ==. 2871 | } else if (typeof actual != 'object' && typeof expected != 'object') { 2872 | return actual === expected; 2873 | 2874 | // 7.4. For all other Object pairs, including Array objects, equivalence is 2875 | // determined by having the same number of owned properties (as verified 2876 | // with Object.prototype.hasOwnProperty.call), the same set of keys 2877 | // (although not necessarily the same order), equivalent values for every 2878 | // corresponding key, and an identical 'prototype' property. Note: this 2879 | // accounts for both named and indexed properties on Arrays. 2880 | } else { 2881 | return objEquiv(actual, expected, memos); 2882 | } 2883 | } 2884 | 2885 | function isUndefinedOrNull(value) { 2886 | return value === null || value === undefined; 2887 | } 2888 | 2889 | function isArguments(object) { 2890 | return Object.prototype.toString.call(object) == '[object Arguments]'; 2891 | } 2892 | 2893 | function objEquiv(a, b, memos) { 2894 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) 2895 | return false; 2896 | 2897 | // an identical 'prototype' property. 2898 | if (a.prototype !== b.prototype) return false; 2899 | 2900 | // check if we have already compared a and b 2901 | var i; 2902 | if (memos) { 2903 | for(i = 0; i < memos.length; i++) { 2904 | if ((memos[i][0] === a && memos[i][1] === b) || 2905 | (memos[i][0] === b && memos[i][1] === a)) 2906 | return true; 2907 | } 2908 | } else { 2909 | memos = []; 2910 | } 2911 | 2912 | //~~~I've managed to break Object.keys through screwy arguments passing. 2913 | // Converting to array solves the problem. 2914 | if (isArguments(a)) { 2915 | if (!isArguments(b)) { 2916 | return false; 2917 | } 2918 | a = pSlice.call(a); 2919 | b = pSlice.call(b); 2920 | return _deepEqual(a, b, memos); 2921 | } 2922 | try { 2923 | var ka = getEnumerableProperties(a), 2924 | kb = getEnumerableProperties(b), 2925 | key; 2926 | } catch (e) {//happens when one is a string literal and the other isn't 2927 | return false; 2928 | } 2929 | 2930 | // having the same number of owned properties (keys incorporates 2931 | // hasOwnProperty) 2932 | if (ka.length != kb.length) 2933 | return false; 2934 | 2935 | //the same set of keys (although not necessarily the same order), 2936 | ka.sort(); 2937 | kb.sort(); 2938 | //~~~cheap key test 2939 | for (i = ka.length - 1; i >= 0; i--) { 2940 | if (ka[i] != kb[i]) 2941 | return false; 2942 | } 2943 | 2944 | // remember objects we have compared to guard against circular references 2945 | memos.push([ a, b ]); 2946 | 2947 | //equivalent values for every corresponding key, and 2948 | //~~~possibly expensive deep test 2949 | for (i = ka.length - 1; i >= 0; i--) { 2950 | key = ka[i]; 2951 | if (!_deepEqual(a[key], b[key], memos)) return false; 2952 | } 2953 | 2954 | return true; 2955 | } 2956 | 2957 | }); // module: chai/utils/eql.js 2958 | 2959 | require.register("chai/utils/flag.js", function(module, exports, require){ 2960 | /*! 2961 | * Chai - flag utility 2962 | * Copyright(c) 2012-2013 Jake Luer 2963 | * MIT Licensed 2964 | */ 2965 | 2966 | /** 2967 | * ### flag(object ,key, [value]) 2968 | * 2969 | * Get or set a flag value on an object. If a 2970 | * value is provided it will be set, else it will 2971 | * return the currently set value or `undefined` if 2972 | * the value is not set. 2973 | * 2974 | * utils.flag(this, 'foo', 'bar'); // setter 2975 | * utils.flag(this, 'foo'); // getter, returns `bar` 2976 | * 2977 | * @param {Object} object (constructed Assertion 2978 | * @param {String} key 2979 | * @param {Mixed} value (optional) 2980 | * @name flag 2981 | * @api private 2982 | */ 2983 | 2984 | module.exports = function (obj, key, value) { 2985 | var flags = obj.__flags || (obj.__flags = Object.create(null)); 2986 | if (arguments.length === 3) { 2987 | flags[key] = value; 2988 | } else { 2989 | return flags[key]; 2990 | } 2991 | }; 2992 | 2993 | }); // module: chai/utils/flag.js 2994 | 2995 | require.register("chai/utils/getActual.js", function(module, exports, require){ 2996 | /*! 2997 | * Chai - getActual utility 2998 | * Copyright(c) 2012-2013 Jake Luer 2999 | * MIT Licensed 3000 | */ 3001 | 3002 | /** 3003 | * # getActual(object, [actual]) 3004 | * 3005 | * Returns the `actual` value for an Assertion 3006 | * 3007 | * @param {Object} object (constructed Assertion) 3008 | * @param {Arguments} chai.Assertion.prototype.assert arguments 3009 | */ 3010 | 3011 | module.exports = function (obj, args) { 3012 | var actual = args[4]; 3013 | return 'undefined' !== typeof actual ? actual : obj._obj; 3014 | }; 3015 | 3016 | }); // module: chai/utils/getActual.js 3017 | 3018 | require.register("chai/utils/getEnumerableProperties.js", function(module, exports, require){ 3019 | /*! 3020 | * Chai - getEnumerableProperties utility 3021 | * Copyright(c) 2012-2013 Jake Luer 3022 | * MIT Licensed 3023 | */ 3024 | 3025 | /** 3026 | * ### .getEnumerableProperties(object) 3027 | * 3028 | * This allows the retrieval of enumerable property names of an object, 3029 | * inherited or not. 3030 | * 3031 | * @param {Object} object 3032 | * @returns {Array} 3033 | * @name getEnumerableProperties 3034 | * @api public 3035 | */ 3036 | 3037 | module.exports = function getEnumerableProperties(object) { 3038 | var result = []; 3039 | for (var name in object) { 3040 | result.push(name); 3041 | } 3042 | return result; 3043 | }; 3044 | 3045 | }); // module: chai/utils/getEnumerableProperties.js 3046 | 3047 | require.register("chai/utils/getMessage.js", function(module, exports, require){ 3048 | /*! 3049 | * Chai - message composition utility 3050 | * Copyright(c) 2012-2013 Jake Luer 3051 | * MIT Licensed 3052 | */ 3053 | 3054 | /*! 3055 | * Module dependancies 3056 | */ 3057 | 3058 | var flag = require('./flag') 3059 | , getActual = require('./getActual') 3060 | , inspect = require('./inspect') 3061 | , objDisplay = require('./objDisplay'); 3062 | 3063 | /** 3064 | * ### .getMessage(object, message, negateMessage) 3065 | * 3066 | * Construct the error message based on flags 3067 | * and template tags. Template tags will return 3068 | * a stringified inspection of the object referenced. 3069 | * 3070 | * Messsage template tags: 3071 | * - `#{this}` current asserted object 3072 | * - `#{act}` actual value 3073 | * - `#{exp}` expected value 3074 | * 3075 | * @param {Object} object (constructed Assertion) 3076 | * @param {Arguments} chai.Assertion.prototype.assert arguments 3077 | * @name getMessage 3078 | * @api public 3079 | */ 3080 | 3081 | module.exports = function (obj, args) { 3082 | var negate = flag(obj, 'negate') 3083 | , val = flag(obj, 'object') 3084 | , expected = args[3] 3085 | , actual = getActual(obj, args) 3086 | , msg = negate ? args[2] : args[1] 3087 | , flagMsg = flag(obj, 'message'); 3088 | 3089 | msg = msg || ''; 3090 | msg = msg 3091 | .replace(/#{this}/g, objDisplay(val)) 3092 | .replace(/#{act}/g, objDisplay(actual)) 3093 | .replace(/#{exp}/g, objDisplay(expected)); 3094 | 3095 | return flagMsg ? flagMsg + ': ' + msg : msg; 3096 | }; 3097 | 3098 | }); // module: chai/utils/getMessage.js 3099 | 3100 | require.register("chai/utils/getName.js", function(module, exports, require){ 3101 | /*! 3102 | * Chai - getName utility 3103 | * Copyright(c) 2012-2013 Jake Luer 3104 | * MIT Licensed 3105 | */ 3106 | 3107 | /** 3108 | * # getName(func) 3109 | * 3110 | * Gets the name of a function, in a cross-browser way. 3111 | * 3112 | * @param {Function} a function (usually a constructor) 3113 | */ 3114 | 3115 | module.exports = function (func) { 3116 | if (func.name) return func.name; 3117 | 3118 | var match = /^\s?function ([^(]*)\(/.exec(func); 3119 | return match && match[1] ? match[1] : ""; 3120 | }; 3121 | 3122 | }); // module: chai/utils/getName.js 3123 | 3124 | require.register("chai/utils/getPathValue.js", function(module, exports, require){ 3125 | /*! 3126 | * Chai - getPathValue utility 3127 | * Copyright(c) 2012-2013 Jake Luer 3128 | * @see https://github.com/logicalparadox/filtr 3129 | * MIT Licensed 3130 | */ 3131 | 3132 | /** 3133 | * ### .getPathValue(path, object) 3134 | * 3135 | * This allows the retrieval of values in an 3136 | * object given a string path. 3137 | * 3138 | * var obj = { 3139 | * prop1: { 3140 | * arr: ['a', 'b', 'c'] 3141 | * , str: 'Hello' 3142 | * } 3143 | * , prop2: { 3144 | * arr: [ { nested: 'Universe' } ] 3145 | * , str: 'Hello again!' 3146 | * } 3147 | * } 3148 | * 3149 | * The following would be the results. 3150 | * 3151 | * getPathValue('prop1.str', obj); // Hello 3152 | * getPathValue('prop1.att[2]', obj); // b 3153 | * getPathValue('prop2.arr[0].nested', obj); // Universe 3154 | * 3155 | * @param {String} path 3156 | * @param {Object} object 3157 | * @returns {Object} value or `undefined` 3158 | * @name getPathValue 3159 | * @api public 3160 | */ 3161 | 3162 | var getPathValue = module.exports = function (path, obj) { 3163 | var parsed = parsePath(path); 3164 | return _getPathValue(parsed, obj); 3165 | }; 3166 | 3167 | /*! 3168 | * ## parsePath(path) 3169 | * 3170 | * Helper function used to parse string object 3171 | * paths. Use in conjunction with `_getPathValue`. 3172 | * 3173 | * var parsed = parsePath('myobject.property.subprop'); 3174 | * 3175 | * ### Paths: 3176 | * 3177 | * * Can be as near infinitely deep and nested 3178 | * * Arrays are also valid using the formal `myobject.document[3].property`. 3179 | * 3180 | * @param {String} path 3181 | * @returns {Object} parsed 3182 | * @api private 3183 | */ 3184 | 3185 | function parsePath (path) { 3186 | var str = path.replace(/\[/g, '.[') 3187 | , parts = str.match(/(\\\.|[^.]+?)+/g); 3188 | return parts.map(function (value) { 3189 | var re = /\[(\d+)\]$/ 3190 | , mArr = re.exec(value) 3191 | if (mArr) return { i: parseFloat(mArr[1]) }; 3192 | else return { p: value }; 3193 | }); 3194 | }; 3195 | 3196 | /*! 3197 | * ## _getPathValue(parsed, obj) 3198 | * 3199 | * Helper companion function for `.parsePath` that returns 3200 | * the value located at the parsed address. 3201 | * 3202 | * var value = getPathValue(parsed, obj); 3203 | * 3204 | * @param {Object} parsed definition from `parsePath`. 3205 | * @param {Object} object to search against 3206 | * @returns {Object|Undefined} value 3207 | * @api private 3208 | */ 3209 | 3210 | function _getPathValue (parsed, obj) { 3211 | var tmp = obj 3212 | , res; 3213 | for (var i = 0, l = parsed.length; i < l; i++) { 3214 | var part = parsed[i]; 3215 | if (tmp) { 3216 | if ('undefined' !== typeof part.p) 3217 | tmp = tmp[part.p]; 3218 | else if ('undefined' !== typeof part.i) 3219 | tmp = tmp[part.i]; 3220 | if (i == (l - 1)) res = tmp; 3221 | } else { 3222 | res = undefined; 3223 | } 3224 | } 3225 | return res; 3226 | }; 3227 | 3228 | }); // module: chai/utils/getPathValue.js 3229 | 3230 | require.register("chai/utils/getProperties.js", function(module, exports, require){ 3231 | /*! 3232 | * Chai - getProperties utility 3233 | * Copyright(c) 2012-2013 Jake Luer 3234 | * MIT Licensed 3235 | */ 3236 | 3237 | /** 3238 | * ### .getProperties(object) 3239 | * 3240 | * This allows the retrieval of property names of an object, enumerable or not, 3241 | * inherited or not. 3242 | * 3243 | * @param {Object} object 3244 | * @returns {Array} 3245 | * @name getProperties 3246 | * @api public 3247 | */ 3248 | 3249 | module.exports = function getProperties(object) { 3250 | var result = Object.getOwnPropertyNames(subject); 3251 | 3252 | function addProperty(property) { 3253 | if (result.indexOf(property) === -1) { 3254 | result.push(property); 3255 | } 3256 | } 3257 | 3258 | var proto = Object.getPrototypeOf(subject); 3259 | while (proto !== null) { 3260 | Object.getOwnPropertyNames(proto).forEach(addProperty); 3261 | proto = Object.getPrototypeOf(proto); 3262 | } 3263 | 3264 | return result; 3265 | }; 3266 | 3267 | }); // module: chai/utils/getProperties.js 3268 | 3269 | require.register("chai/utils/index.js", function(module, exports, require){ 3270 | /*! 3271 | * chai 3272 | * Copyright(c) 2011 Jake Luer 3273 | * MIT Licensed 3274 | */ 3275 | 3276 | /*! 3277 | * Main exports 3278 | */ 3279 | 3280 | var exports = module.exports = {}; 3281 | 3282 | /*! 3283 | * test utility 3284 | */ 3285 | 3286 | exports.test = require('./test'); 3287 | 3288 | /*! 3289 | * type utility 3290 | */ 3291 | 3292 | exports.type = require('./type'); 3293 | 3294 | /*! 3295 | * message utility 3296 | */ 3297 | 3298 | exports.getMessage = require('./getMessage'); 3299 | 3300 | /*! 3301 | * actual utility 3302 | */ 3303 | 3304 | exports.getActual = require('./getActual'); 3305 | 3306 | /*! 3307 | * Inspect util 3308 | */ 3309 | 3310 | exports.inspect = require('./inspect'); 3311 | 3312 | /*! 3313 | * Object Display util 3314 | */ 3315 | 3316 | exports.objDisplay = require('./objDisplay'); 3317 | 3318 | /*! 3319 | * Flag utility 3320 | */ 3321 | 3322 | exports.flag = require('./flag'); 3323 | 3324 | /*! 3325 | * Flag transferring utility 3326 | */ 3327 | 3328 | exports.transferFlags = require('./transferFlags'); 3329 | 3330 | /*! 3331 | * Deep equal utility 3332 | */ 3333 | 3334 | exports.eql = require('./eql'); 3335 | 3336 | /*! 3337 | * Deep path value 3338 | */ 3339 | 3340 | exports.getPathValue = require('./getPathValue'); 3341 | 3342 | /*! 3343 | * Function name 3344 | */ 3345 | 3346 | exports.getName = require('./getName'); 3347 | 3348 | /*! 3349 | * add Property 3350 | */ 3351 | 3352 | exports.addProperty = require('./addProperty'); 3353 | 3354 | /*! 3355 | * add Method 3356 | */ 3357 | 3358 | exports.addMethod = require('./addMethod'); 3359 | 3360 | /*! 3361 | * overwrite Property 3362 | */ 3363 | 3364 | exports.overwriteProperty = require('./overwriteProperty'); 3365 | 3366 | /*! 3367 | * overwrite Method 3368 | */ 3369 | 3370 | exports.overwriteMethod = require('./overwriteMethod'); 3371 | 3372 | /*! 3373 | * Add a chainable method 3374 | */ 3375 | 3376 | exports.addChainableMethod = require('./addChainableMethod'); 3377 | 3378 | 3379 | }); // module: chai/utils/index.js 3380 | 3381 | require.register("chai/utils/inspect.js", function(module, exports, require){ 3382 | // This is (almost) directly from Node.js utils 3383 | // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js 3384 | 3385 | var getName = require('./getName'); 3386 | var getProperties = require('./getProperties'); 3387 | var getEnumerableProperties = require('./getEnumerableProperties'); 3388 | 3389 | module.exports = inspect; 3390 | 3391 | /** 3392 | * Echos the value of a value. Trys to print the value out 3393 | * in the best way possible given the different types. 3394 | * 3395 | * @param {Object} obj The object to print out. 3396 | * @param {Boolean} showHidden Flag that shows hidden (not enumerable) 3397 | * properties of objects. 3398 | * @param {Number} depth Depth in which to descend in object. Default is 2. 3399 | * @param {Boolean} colors Flag to turn on ANSI escape codes to color the 3400 | * output. Default is false (no coloring). 3401 | */ 3402 | function inspect(obj, showHidden, depth, colors) { 3403 | var ctx = { 3404 | showHidden: showHidden, 3405 | seen: [], 3406 | stylize: function (str) { return str; } 3407 | }; 3408 | return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); 3409 | } 3410 | 3411 | // https://gist.github.com/1044128/ 3412 | var getOuterHTML = function(element) { 3413 | if ('outerHTML' in element) return element.outerHTML; 3414 | var ns = "http://www.w3.org/1999/xhtml"; 3415 | var container = document.createElementNS(ns, '_'); 3416 | var elemProto = (window.HTMLElement || window.Element).prototype; 3417 | var xmlSerializer = new XMLSerializer(); 3418 | var html; 3419 | if (document.xmlVersion) { 3420 | return xmlSerializer.serializeToString(element); 3421 | } else { 3422 | container.appendChild(element.cloneNode(false)); 3423 | html = container.innerHTML.replace('><', '>' + element.innerHTML + '<'); 3424 | container.innerHTML = ''; 3425 | return html; 3426 | } 3427 | }; 3428 | 3429 | // Returns true if object is a DOM element. 3430 | var isDOMElement = function (object) { 3431 | if (typeof HTMLElement === 'object') { 3432 | return object instanceof HTMLElement; 3433 | } else { 3434 | return object && 3435 | typeof object === 'object' && 3436 | object.nodeType === 1 && 3437 | typeof object.nodeName === 'string'; 3438 | } 3439 | }; 3440 | 3441 | function formatValue(ctx, value, recurseTimes) { 3442 | // Provide a hook for user-specified inspect functions. 3443 | // Check that value is an object with an inspect function on it 3444 | if (value && typeof value.inspect === 'function' && 3445 | // Filter out the util module, it's inspect function is special 3446 | value.inspect !== exports.inspect && 3447 | // Also filter out any prototype objects using the circular check. 3448 | !(value.constructor && value.constructor.prototype === value)) { 3449 | return value.inspect(recurseTimes); 3450 | } 3451 | 3452 | // Primitive types cannot have properties 3453 | var primitive = formatPrimitive(ctx, value); 3454 | if (primitive) { 3455 | return primitive; 3456 | } 3457 | 3458 | // If it's DOM elem, get outer HTML. 3459 | if (isDOMElement(value)) { 3460 | return getOuterHTML(value); 3461 | } 3462 | 3463 | // Look up the keys of the object. 3464 | var visibleKeys = getEnumerableProperties(value); 3465 | var keys = ctx.showHidden ? getProperties(value) : visibleKeys; 3466 | 3467 | // Some type of object without properties can be shortcutted. 3468 | // In IE, errors have a single `stack` property, or if they are vanilla `Error`, 3469 | // a `stack` plus `description` property; ignore those for consistency. 3470 | if (keys.length === 0 || (isError(value) && ( 3471 | (keys.length === 1 && keys[0] === 'stack') || 3472 | (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') 3473 | ))) { 3474 | if (typeof value === 'function') { 3475 | var name = getName(value); 3476 | var nameSuffix = name ? ': ' + name : ''; 3477 | return ctx.stylize('[Function' + nameSuffix + ']', 'special'); 3478 | } 3479 | if (isRegExp(value)) { 3480 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 3481 | } 3482 | if (isDate(value)) { 3483 | return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); 3484 | } 3485 | if (isError(value)) { 3486 | return formatError(value); 3487 | } 3488 | } 3489 | 3490 | var base = '', array = false, braces = ['{', '}']; 3491 | 3492 | // Make Array say that they are Array 3493 | if (isArray(value)) { 3494 | array = true; 3495 | braces = ['[', ']']; 3496 | } 3497 | 3498 | // Make functions say that they are functions 3499 | if (typeof value === 'function') { 3500 | var name = getName(value); 3501 | var nameSuffix = name ? ': ' + name : ''; 3502 | base = ' [Function' + nameSuffix + ']'; 3503 | } 3504 | 3505 | // Make RegExps say that they are RegExps 3506 | if (isRegExp(value)) { 3507 | base = ' ' + RegExp.prototype.toString.call(value); 3508 | } 3509 | 3510 | // Make dates with properties first say the date 3511 | if (isDate(value)) { 3512 | base = ' ' + Date.prototype.toUTCString.call(value); 3513 | } 3514 | 3515 | // Make error with message first say the error 3516 | if (isError(value)) { 3517 | return formatError(value); 3518 | } 3519 | 3520 | if (keys.length === 0 && (!array || value.length == 0)) { 3521 | return braces[0] + base + braces[1]; 3522 | } 3523 | 3524 | if (recurseTimes < 0) { 3525 | if (isRegExp(value)) { 3526 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 3527 | } else { 3528 | return ctx.stylize('[Object]', 'special'); 3529 | } 3530 | } 3531 | 3532 | ctx.seen.push(value); 3533 | 3534 | var output; 3535 | if (array) { 3536 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 3537 | } else { 3538 | output = keys.map(function(key) { 3539 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 3540 | }); 3541 | } 3542 | 3543 | ctx.seen.pop(); 3544 | 3545 | return reduceToSingleString(output, base, braces); 3546 | } 3547 | 3548 | 3549 | function formatPrimitive(ctx, value) { 3550 | switch (typeof value) { 3551 | case 'undefined': 3552 | return ctx.stylize('undefined', 'undefined'); 3553 | 3554 | case 'string': 3555 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 3556 | .replace(/'/g, "\\'") 3557 | .replace(/\\"/g, '"') + '\''; 3558 | return ctx.stylize(simple, 'string'); 3559 | 3560 | case 'number': 3561 | return ctx.stylize('' + value, 'number'); 3562 | 3563 | case 'boolean': 3564 | return ctx.stylize('' + value, 'boolean'); 3565 | } 3566 | // For some reason typeof null is "object", so special case here. 3567 | if (value === null) { 3568 | return ctx.stylize('null', 'null'); 3569 | } 3570 | } 3571 | 3572 | 3573 | function formatError(value) { 3574 | return '[' + Error.prototype.toString.call(value) + ']'; 3575 | } 3576 | 3577 | 3578 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 3579 | var output = []; 3580 | for (var i = 0, l = value.length; i < l; ++i) { 3581 | if (Object.prototype.hasOwnProperty.call(value, String(i))) { 3582 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 3583 | String(i), true)); 3584 | } else { 3585 | output.push(''); 3586 | } 3587 | } 3588 | keys.forEach(function(key) { 3589 | if (!key.match(/^\d+$/)) { 3590 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 3591 | key, true)); 3592 | } 3593 | }); 3594 | return output; 3595 | } 3596 | 3597 | 3598 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 3599 | var name, str; 3600 | if (value.__lookupGetter__) { 3601 | if (value.__lookupGetter__(key)) { 3602 | if (value.__lookupSetter__(key)) { 3603 | str = ctx.stylize('[Getter/Setter]', 'special'); 3604 | } else { 3605 | str = ctx.stylize('[Getter]', 'special'); 3606 | } 3607 | } else { 3608 | if (value.__lookupSetter__(key)) { 3609 | str = ctx.stylize('[Setter]', 'special'); 3610 | } 3611 | } 3612 | } 3613 | if (visibleKeys.indexOf(key) < 0) { 3614 | name = '[' + key + ']'; 3615 | } 3616 | if (!str) { 3617 | if (ctx.seen.indexOf(value[key]) < 0) { 3618 | if (recurseTimes === null) { 3619 | str = formatValue(ctx, value[key], null); 3620 | } else { 3621 | str = formatValue(ctx, value[key], recurseTimes - 1); 3622 | } 3623 | if (str.indexOf('\n') > -1) { 3624 | if (array) { 3625 | str = str.split('\n').map(function(line) { 3626 | return ' ' + line; 3627 | }).join('\n').substr(2); 3628 | } else { 3629 | str = '\n' + str.split('\n').map(function(line) { 3630 | return ' ' + line; 3631 | }).join('\n'); 3632 | } 3633 | } 3634 | } else { 3635 | str = ctx.stylize('[Circular]', 'special'); 3636 | } 3637 | } 3638 | if (typeof name === 'undefined') { 3639 | if (array && key.match(/^\d+$/)) { 3640 | return str; 3641 | } 3642 | name = JSON.stringify('' + key); 3643 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 3644 | name = name.substr(1, name.length - 2); 3645 | name = ctx.stylize(name, 'name'); 3646 | } else { 3647 | name = name.replace(/'/g, "\\'") 3648 | .replace(/\\"/g, '"') 3649 | .replace(/(^"|"$)/g, "'"); 3650 | name = ctx.stylize(name, 'string'); 3651 | } 3652 | } 3653 | 3654 | return name + ': ' + str; 3655 | } 3656 | 3657 | 3658 | function reduceToSingleString(output, base, braces) { 3659 | var numLinesEst = 0; 3660 | var length = output.reduce(function(prev, cur) { 3661 | numLinesEst++; 3662 | if (cur.indexOf('\n') >= 0) numLinesEst++; 3663 | return prev + cur.length + 1; 3664 | }, 0); 3665 | 3666 | if (length > 60) { 3667 | return braces[0] + 3668 | (base === '' ? '' : base + '\n ') + 3669 | ' ' + 3670 | output.join(',\n ') + 3671 | ' ' + 3672 | braces[1]; 3673 | } 3674 | 3675 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 3676 | } 3677 | 3678 | function isArray(ar) { 3679 | return Array.isArray(ar) || 3680 | (typeof ar === 'object' && objectToString(ar) === '[object Array]'); 3681 | } 3682 | 3683 | function isRegExp(re) { 3684 | return typeof re === 'object' && objectToString(re) === '[object RegExp]'; 3685 | } 3686 | 3687 | function isDate(d) { 3688 | return typeof d === 'object' && objectToString(d) === '[object Date]'; 3689 | } 3690 | 3691 | function isError(e) { 3692 | return typeof e === 'object' && objectToString(e) === '[object Error]'; 3693 | } 3694 | 3695 | function objectToString(o) { 3696 | return Object.prototype.toString.call(o); 3697 | } 3698 | 3699 | }); // module: chai/utils/inspect.js 3700 | 3701 | require.register("chai/utils/objDisplay.js", function(module, exports, require){ 3702 | /*! 3703 | * Chai - flag utility 3704 | * Copyright(c) 2012-2013 Jake Luer 3705 | * MIT Licensed 3706 | */ 3707 | 3708 | /*! 3709 | * Module dependancies 3710 | */ 3711 | 3712 | var inspect = require('./inspect'); 3713 | 3714 | /** 3715 | * ### .objDisplay (object) 3716 | * 3717 | * Determines if an object or an array matches 3718 | * criteria to be inspected in-line for error 3719 | * messages or should be truncated. 3720 | * 3721 | * @param {Mixed} javascript object to inspect 3722 | * @name objDisplay 3723 | * @api public 3724 | */ 3725 | 3726 | module.exports = function (obj) { 3727 | var str = inspect(obj) 3728 | , type = Object.prototype.toString.call(obj); 3729 | 3730 | if (str.length >= 40) { 3731 | if (type === '[object Function]') { 3732 | return !obj.name || obj.name === '' 3733 | ? '[Function]' 3734 | : '[Function: ' + obj.name + ']'; 3735 | } else if (type === '[object Array]') { 3736 | return '[ Array(' + obj.length + ') ]'; 3737 | } else if (type === '[object Object]') { 3738 | var keys = Object.keys(obj) 3739 | , kstr = keys.length > 2 3740 | ? keys.splice(0, 2).join(', ') + ', ...' 3741 | : keys.join(', '); 3742 | return '{ Object (' + kstr + ') }'; 3743 | } else { 3744 | return str; 3745 | } 3746 | } else { 3747 | return str; 3748 | } 3749 | }; 3750 | 3751 | }); // module: chai/utils/objDisplay.js 3752 | 3753 | require.register("chai/utils/overwriteMethod.js", function(module, exports, require){ 3754 | /*! 3755 | * Chai - overwriteMethod utility 3756 | * Copyright(c) 2012-2013 Jake Luer 3757 | * MIT Licensed 3758 | */ 3759 | 3760 | /** 3761 | * ### overwriteMethod (ctx, name, fn) 3762 | * 3763 | * Overwites an already existing method and provides 3764 | * access to previous function. Must return function 3765 | * to be used for name. 3766 | * 3767 | * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { 3768 | * return function (str) { 3769 | * var obj = utils.flag(this, 'object'); 3770 | * if (obj instanceof Foo) { 3771 | * new chai.Assertion(obj.value).to.equal(str); 3772 | * } else { 3773 | * _super.apply(this, arguments); 3774 | * } 3775 | * } 3776 | * }); 3777 | * 3778 | * Can also be accessed directly from `chai.Assertion`. 3779 | * 3780 | * chai.Assertion.overwriteMethod('foo', fn); 3781 | * 3782 | * Then can be used as any other assertion. 3783 | * 3784 | * expect(myFoo).to.equal('bar'); 3785 | * 3786 | * @param {Object} ctx object whose method is to be overwritten 3787 | * @param {String} name of method to overwrite 3788 | * @param {Function} method function that returns a function to be used for name 3789 | * @name overwriteMethod 3790 | * @api public 3791 | */ 3792 | 3793 | module.exports = function (ctx, name, method) { 3794 | var _method = ctx[name] 3795 | , _super = function () { return this; }; 3796 | 3797 | if (_method && 'function' === typeof _method) 3798 | _super = _method; 3799 | 3800 | ctx[name] = function () { 3801 | var result = method(_super).apply(this, arguments); 3802 | return result === undefined ? this : result; 3803 | } 3804 | }; 3805 | 3806 | }); // module: chai/utils/overwriteMethod.js 3807 | 3808 | require.register("chai/utils/overwriteProperty.js", function(module, exports, require){ 3809 | /*! 3810 | * Chai - overwriteProperty utility 3811 | * Copyright(c) 2012-2013 Jake Luer 3812 | * MIT Licensed 3813 | */ 3814 | 3815 | /** 3816 | * ### overwriteProperty (ctx, name, fn) 3817 | * 3818 | * Overwites an already existing property getter and provides 3819 | * access to previous value. Must return function to use as getter. 3820 | * 3821 | * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { 3822 | * return function () { 3823 | * var obj = utils.flag(this, 'object'); 3824 | * if (obj instanceof Foo) { 3825 | * new chai.Assertion(obj.name).to.equal('bar'); 3826 | * } else { 3827 | * _super.call(this); 3828 | * } 3829 | * } 3830 | * }); 3831 | * 3832 | * 3833 | * Can also be accessed directly from `chai.Assertion`. 3834 | * 3835 | * chai.Assertion.overwriteProperty('foo', fn); 3836 | * 3837 | * Then can be used as any other assertion. 3838 | * 3839 | * expect(myFoo).to.be.ok; 3840 | * 3841 | * @param {Object} ctx object whose property is to be overwritten 3842 | * @param {String} name of property to overwrite 3843 | * @param {Function} getter function that returns a getter function to be used for name 3844 | * @name overwriteProperty 3845 | * @api public 3846 | */ 3847 | 3848 | module.exports = function (ctx, name, getter) { 3849 | var _get = Object.getOwnPropertyDescriptor(ctx, name) 3850 | , _super = function () {}; 3851 | 3852 | if (_get && 'function' === typeof _get.get) 3853 | _super = _get.get 3854 | 3855 | Object.defineProperty(ctx, name, 3856 | { get: function () { 3857 | var result = getter(_super).call(this); 3858 | return result === undefined ? this : result; 3859 | } 3860 | , configurable: true 3861 | }); 3862 | }; 3863 | 3864 | }); // module: chai/utils/overwriteProperty.js 3865 | 3866 | require.register("chai/utils/test.js", function(module, exports, require){ 3867 | /*! 3868 | * Chai - test utility 3869 | * Copyright(c) 2012-2013 Jake Luer 3870 | * MIT Licensed 3871 | */ 3872 | 3873 | /*! 3874 | * Module dependancies 3875 | */ 3876 | 3877 | var flag = require('./flag'); 3878 | 3879 | /** 3880 | * # test(object, expression) 3881 | * 3882 | * Test and object for expression. 3883 | * 3884 | * @param {Object} object (constructed Assertion) 3885 | * @param {Arguments} chai.Assertion.prototype.assert arguments 3886 | */ 3887 | 3888 | module.exports = function (obj, args) { 3889 | var negate = flag(obj, 'negate') 3890 | , expr = args[0]; 3891 | return negate ? !expr : expr; 3892 | }; 3893 | 3894 | }); // module: chai/utils/test.js 3895 | 3896 | require.register("chai/utils/transferFlags.js", function(module, exports, require){ 3897 | /*! 3898 | * Chai - transferFlags utility 3899 | * Copyright(c) 2012-2013 Jake Luer 3900 | * MIT Licensed 3901 | */ 3902 | 3903 | /** 3904 | * ### transferFlags(assertion, object, includeAll = true) 3905 | * 3906 | * Transfer all the flags for `assertion` to `object`. If 3907 | * `includeAll` is set to `false`, then the base Chai 3908 | * assertion flags (namely `object`, `ssfi`, and `message`) 3909 | * will not be transferred. 3910 | * 3911 | * 3912 | * var newAssertion = new Assertion(); 3913 | * utils.transferFlags(assertion, newAssertion); 3914 | * 3915 | * var anotherAsseriton = new Assertion(myObj); 3916 | * utils.transferFlags(assertion, anotherAssertion, false); 3917 | * 3918 | * @param {Assertion} assertion the assertion to transfer the flags from 3919 | * @param {Object} object the object to transfer the flags too; usually a new assertion 3920 | * @param {Boolean} includeAll 3921 | * @name getAllFlags 3922 | * @api private 3923 | */ 3924 | 3925 | module.exports = function (assertion, object, includeAll) { 3926 | var flags = assertion.__flags || (assertion.__flags = Object.create(null)); 3927 | 3928 | if (!object.__flags) { 3929 | object.__flags = Object.create(null); 3930 | } 3931 | 3932 | includeAll = arguments.length === 3 ? includeAll : true; 3933 | 3934 | for (var flag in flags) { 3935 | if (includeAll || 3936 | (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { 3937 | object.__flags[flag] = flags[flag]; 3938 | } 3939 | } 3940 | }; 3941 | 3942 | }); // module: chai/utils/transferFlags.js 3943 | 3944 | require.register("chai/utils/type.js", function(module, exports, require){ 3945 | /*! 3946 | * Chai - type utility 3947 | * Copyright(c) 2012-2013 Jake Luer 3948 | * MIT Licensed 3949 | */ 3950 | 3951 | /*! 3952 | * Detectable javascript natives 3953 | */ 3954 | 3955 | var natives = { 3956 | '[object Arguments]': 'arguments' 3957 | , '[object Array]': 'array' 3958 | , '[object Date]': 'date' 3959 | , '[object Function]': 'function' 3960 | , '[object Number]': 'number' 3961 | , '[object RegExp]': 'regexp' 3962 | , '[object String]': 'string' 3963 | }; 3964 | 3965 | /** 3966 | * ### type(object) 3967 | * 3968 | * Better implementation of `typeof` detection that can 3969 | * be used cross-browser. Handles the inconsistencies of 3970 | * Array, `null`, and `undefined` detection. 3971 | * 3972 | * utils.type({}) // 'object' 3973 | * utils.type(null) // `null' 3974 | * utils.type(undefined) // `undefined` 3975 | * utils.type([]) // `array` 3976 | * 3977 | * @param {Mixed} object to detect type of 3978 | * @name type 3979 | * @api private 3980 | */ 3981 | 3982 | module.exports = function (obj) { 3983 | var str = Object.prototype.toString.call(obj); 3984 | if (natives[str]) return natives[str]; 3985 | if (obj === null) return 'null'; 3986 | if (obj === undefined) return 'undefined'; 3987 | if (obj === Object(obj)) return 'object'; 3988 | return typeof obj; 3989 | }; 3990 | 3991 | }); // module: chai/utils/type.js 3992 | 3993 | require.alias("./chai.js", "chai"); 3994 | 3995 | return require('chai'); 3996 | }); -------------------------------------------------------------------------------- /scope/lib/mocha/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 5 | padding: 60px 50px; 6 | } 7 | 8 | #mocha ul, #mocha li { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | 13 | #mocha ul { 14 | list-style: none; 15 | } 16 | 17 | #mocha h1, #mocha h2 { 18 | margin: 0; 19 | } 20 | 21 | #mocha h1 { 22 | margin-top: 15px; 23 | font-size: 1em; 24 | font-weight: 200; 25 | } 26 | 27 | #mocha h1 a { 28 | text-decoration: none; 29 | color: inherit; 30 | } 31 | 32 | #mocha h1 a:hover { 33 | text-decoration: underline; 34 | } 35 | 36 | #mocha .suite .suite h1 { 37 | margin-top: 0; 38 | font-size: .8em; 39 | } 40 | 41 | .hidden { 42 | display: none; 43 | } 44 | 45 | #mocha h2 { 46 | font-size: 12px; 47 | font-weight: normal; 48 | cursor: pointer; 49 | } 50 | 51 | #mocha .suite { 52 | margin-left: 15px; 53 | } 54 | 55 | #mocha .test { 56 | margin-left: 15px; 57 | overflow: hidden; 58 | } 59 | 60 | #mocha .test.pending:hover h2::after { 61 | content: '(pending)'; 62 | font-family: arial; 63 | } 64 | 65 | #mocha .test.pass.medium .duration { 66 | background: #C09853; 67 | } 68 | 69 | #mocha .test.pass.slow .duration { 70 | background: #B94A48; 71 | } 72 | 73 | #mocha .test.pass::before { 74 | content: '✓'; 75 | font-size: 12px; 76 | display: block; 77 | float: left; 78 | margin-right: 5px; 79 | color: #00d6b2; 80 | } 81 | 82 | #mocha .test.pass .duration { 83 | font-size: 9px; 84 | margin-left: 5px; 85 | padding: 2px 5px; 86 | color: white; 87 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 88 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 89 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 90 | -webkit-border-radius: 5px; 91 | -moz-border-radius: 5px; 92 | -ms-border-radius: 5px; 93 | -o-border-radius: 5px; 94 | border-radius: 5px; 95 | } 96 | 97 | #mocha .test.pass.fast .duration { 98 | display: none; 99 | } 100 | 101 | #mocha .test.pending { 102 | color: #0b97c4; 103 | } 104 | 105 | #mocha .test.pending::before { 106 | content: '◦'; 107 | color: #0b97c4; 108 | } 109 | 110 | #mocha .test.fail { 111 | color: #c00; 112 | } 113 | 114 | #mocha .test.fail pre { 115 | color: black; 116 | } 117 | 118 | #mocha .test.fail::before { 119 | content: '✖'; 120 | font-size: 12px; 121 | display: block; 122 | float: left; 123 | margin-right: 5px; 124 | color: #c00; 125 | } 126 | 127 | #mocha .test pre.error { 128 | color: #c00; 129 | max-height: 300px; 130 | overflow: auto; 131 | } 132 | 133 | #mocha .test pre { 134 | display: block; 135 | float: left; 136 | clear: left; 137 | font: 12px/1.5 monaco, monospace; 138 | margin: 5px; 139 | padding: 15px; 140 | border: 1px solid #eee; 141 | border-bottom-color: #ddd; 142 | -webkit-border-radius: 3px; 143 | -webkit-box-shadow: 0 1px 3px #eee; 144 | -moz-border-radius: 3px; 145 | -moz-box-shadow: 0 1px 3px #eee; 146 | } 147 | 148 | #mocha .test h2 { 149 | position: relative; 150 | } 151 | 152 | #mocha .test a.replay { 153 | position: absolute; 154 | top: 3px; 155 | right: 0; 156 | text-decoration: none; 157 | vertical-align: middle; 158 | display: block; 159 | width: 15px; 160 | height: 15px; 161 | line-height: 15px; 162 | text-align: center; 163 | background: #eee; 164 | font-size: 15px; 165 | -moz-border-radius: 15px; 166 | border-radius: 15px; 167 | -webkit-transition: opacity 200ms; 168 | -moz-transition: opacity 200ms; 169 | transition: opacity 200ms; 170 | opacity: 0.3; 171 | color: #888; 172 | } 173 | 174 | #mocha .test:hover a.replay { 175 | opacity: 1; 176 | } 177 | 178 | #mocha-report.pass .test.fail { 179 | display: none; 180 | } 181 | 182 | #mocha-report.fail .test.pass { 183 | display: none; 184 | } 185 | 186 | #mocha-error { 187 | color: #c00; 188 | font-size: 1.5 em; 189 | font-weight: 100; 190 | letter-spacing: 1px; 191 | } 192 | 193 | #mocha-stats { 194 | position: fixed; 195 | top: 15px; 196 | right: 10px; 197 | font-size: 12px; 198 | margin: 0; 199 | color: #888; 200 | } 201 | 202 | #mocha-stats .progress { 203 | float: right; 204 | padding-top: 0; 205 | } 206 | 207 | #mocha-stats em { 208 | color: black; 209 | } 210 | 211 | #mocha-stats a { 212 | text-decoration: none; 213 | color: inherit; 214 | } 215 | 216 | #mocha-stats a:hover { 217 | border-bottom: 1px solid #eee; 218 | } 219 | 220 | #mocha-stats li { 221 | display: inline-block; 222 | margin: 0 5px; 223 | list-style: none; 224 | padding-top: 11px; 225 | } 226 | 227 | #mocha-stats canvas { 228 | width: 40px; 229 | height: 40px; 230 | } 231 | 232 | code .comment { color: #ddd } 233 | code .init { color: #2F6FAD } 234 | code .string { color: #5890AD } 235 | code .keyword { color: #8A6343 } 236 | code .number { color: #2F6FAD } 237 | 238 | @media screen and (max-device-width: 480px) { 239 | body { 240 | padding: 60px 0px; 241 | } 242 | 243 | #stats { 244 | position: absolute; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /scope/scopeExercises.md: -------------------------------------------------------------------------------- 1 | # [Function Scope Exercises](id:xcredit) 2 | 3 | 4 | ##### It is your mission to go through the function.js file and change all the `'???'` in such a way that all the tests pass true. 5 | 6 | ### Let's get started... 7 | 8 | 9 | Run the file in a browser. This document shows one passed test and a series of failing tests. 10 | 11 | The **functions.js** folder holds all the failing tests that are being displayed in **SpecRunner.html**. You will be editing this file and using the **SpecRunner.html** to check your progress on making these tests pass. This is just a javascript file so you can use console.log to help debug and inspect these functions. 12 | 13 | A test block starts with an `it` function. The `it` function takes two arguments. The first one is a statement describing the rule addressed by the test. The second is a function that will either evaluate to true or false using the `expect` function. The expect statement (`expect(ACTUAL === 'inner').to.be.true;`) will evaluate if the statement between the parens `ACTUAL === 'inner'` is true. You can almost read it like plain English. The expect statement below "expects that the variable ACTUAL equals the value 'inner' to be true". 14 | 15 | #### Failing Test Example 16 | 17 | it('a function has access to its own local scope variables', 18 | 19 | function () { 20 | var fn = function () { 21 | var name = 'inner'; 22 | ACTUAL = name; 23 | }; 24 | fn(); 25 | expect(ACTUAL === '???').to.be.true; 26 | //change '???' to what ACTUAL evaluates to. 27 | }); 28 | 29 | #### Passing Test Example 30 | 31 | it('a function has access to its own local scope variables', 32 | 33 | function () { 34 | var fn = function () { 35 | var name = 'inner'; 36 | ACTUAL = name; 37 | }; 38 | fn(); 39 | expect(ACTUAL === 'inner').to.be.true; 40 | //changed '???' to 'inner' 41 | //(because we assigned ACTUAL, a global variable to name inside fn) 42 | }); 43 | 44 | ### Don't forget.. 45 | To read all code to try to understand how the whole testing process works. Welcome to programming :) 46 | 47 | --- 48 | -------------------------------------------------------------------------------- /underscore-extra-credit/underscoreExercises.md: -------------------------------------------------------------------------------- 1 | ## Underscore exercises 2 | 3 | 1. Use _.reduce to multiply all the values in an array. 4 | 5 | 2. Use _.reduce to concatenate all strings in an array. 6 | 7 | input: ['x','y','z'] 8 | output: 'xyz' 9 | 10 | 11 | 3. Write a function that takes an array of names and congratulates them. Make sure to use _.reduce as part of the function. 12 | 13 | input: ['Steve', 'Sally', 'George', 'Gina'] 14 | output: 'Congratulations Steve, Sally, George, Gina!' 15 | 16 | 4. _.pluck takes an object and a property name and returns the property name's value. Write your own version called myPluck. 17 | 18 | myPluck = function(obj, propName){ 19 | //fill in here 20 | } 21 | 22 | 23 | 24 | 6. Use _.filter to return all strings in an array that start with the letter 'Z'. 25 | 26 | 7. Use _.where on your farm animals from the lecture slides to return all animals who contain the value 3 at the property name space. 27 | 28 | input: [ {speak: function(){console.log('My name is ' + name);}, name: "Tiger", space: 7}, 29 | {speak: function(){console.log('My name is ' + name);}, name: "Tiger2", space: 1}, 30 | {speak: function(){console.log('My name is ' + name);}, name: "Tiger3", space: 3}, 31 | {speak: function(){console.log('My name is ' + name);}, name: "Tiger4", space: 3} ] 32 | 33 | output: [{speak: function, name: "Tiger3", space: 3}, 34 | {speak: function(){}, name: "Tiger4", space: 3}] 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /underscore-loops/callbackExercises.md: -------------------------------------------------------------------------------- 1 | ## Callback exercises 2 | 3 | 1. Use _.each to loop through an array and console.log() all the values. Now use it to console.log() the indices. How would this be different if you were looping through an object? 4 | 5 | 2. Write a function called checkValue that searches an array for a value. It takes an array and a value and returns true if the value exists in the array, otherwise it returns false. 6 | 7 | var helloArr = ['bonjour', 'hello', 'hola']; 8 | 9 | var checkValue = function(arr, val) { 10 | //checks if the val is in arr 11 | } 12 | 13 | 3. Rewrite checkValue using _.each. Make sure that you have underscore.js included where you are running your code. 14 | 15 | 4. Write a loop that pushes all the values in an object to an array. 16 | 17 | input: {two: 2, four: 4, three: 3, twelve: 12} 18 | output: [2, 4, 3, 12] 19 | 20 | 5. Use _.map to mimic the previous behavior. 21 | 22 | input: {two: 2, four: 4, three: 3, twelve: 12} 23 | output: [2, 4, 3, 12] 24 | 6. Use _.filter to return all the even numbers in an array. 25 | 26 | input: [9,8,7,6,5,2] 27 | output: [8,6,2] 28 | 29 | --------------------------------------------------------------------------------