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