├── examples ├── logo.png └── simple.html ├── .gitignore ├── test ├── tests.js ├── index.html └── utils │ ├── mocha.css │ └── chai.js ├── src └── index.js ├── LICENSE.md ├── package.json ├── README.md └── dist └── font-feature-fibbing.js /examples/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennethormandy/font-feature-fibbing/HEAD/examples/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | .DS_Store 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Compiled binary addons (http://nodejs.org/api/addons.html) 9 | build/Release 10 | 11 | # Dependency directory 12 | node_modules 13 | components 14 | bower_components 15 | 16 | # Compile directories 17 | www/ 18 | _book/ 19 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | describe('supports `font-feature-settings`', function(){ 2 | describe('basic', function(){ 3 | it('should exist', function(){ 4 | chai.assert.typeOf(fontFeatureFibbing, 'function', 'fontFeatureFibbing is a function'); 5 | }) 6 | // it('should return true in Chrome', function(){ 7 | // chai.assert(supportsFontFeatureSettings(), true); 8 | // }) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | var ua = require('vigour-ua') 2 | 3 | module.exports = function () { 4 | 5 | if (typeof document === 'undefined') { 6 | return false 7 | } else { 8 | // If font-feature-settings or -webkit-font-feature-settings are present 9 | if (document.body.style['fontFeatureSettings'] === '' || document.body.style['webkitFontFeatureSettings'] === '') { 10 | var agent = ua(navigator.userAgent) 11 | if (agent.browser === 'safari' && agent.version < 9.1) { 12 | return false 13 | } else { 14 | // Otherwise, font-feature-settings is supported in some capacity 15 | return true 16 | } 17 | } else if (document.body.style['mozFontFeatureSettings'] === '' || document.body.style['MozFontFeatureSettings'] === '' || typeof document.body.style['msFontFeatureSettings'] === '') { 18 | // If font-feature-settings isn’t supported, we’re still good if -moz- or -ms- are here 19 | return true 20 | } 21 | return false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2014–2015 [Kenneth Ormandy](http://kennethormandy.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the “Software”), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "font-feature-fibbing", 3 | "version": "0.4.1", 4 | "description": "Hey, do you support the font-feature-settings CSS property? Safari, look—I know you’re lying!", 5 | "homepage": "https://github.com/kennethormandy/font-feature-fibbing", 6 | "repository": "https://github.com/kennethormandy/font-feature-fibbing.git", 7 | "license": "MIT", 8 | "main": "src/index.js", 9 | "author": "Kenneth Ormandy (http://kennethormandy.com)", 10 | "scripts": { 11 | "test": "http-server -s -p 8095 & open http://localhost:8095/test", 12 | "build-js": "browserify src/index.js -s fontFeatureFibbing -o dist/font-feature-fibbing.js && minify dist/font-feature-fibbing.js dist/font-feature-fibbing.js", 13 | "build": "npm run build-js", 14 | "lint": "standard src/", 15 | "posttest": "npm run lint" 16 | }, 17 | "keywords": [ 18 | "type", 19 | "typograhpy", 20 | "font", 21 | "tester" 22 | ], 23 | "devDependencies": { 24 | "browserify": "^8.0.0", 25 | "http-server": "^0.7.4", 26 | "minify": "git://github.com/ianstormtaylor/minify#0.2.0", 27 | "mocha": "~1.18.2", 28 | "standard": "5.4.1" 29 | }, 30 | "dependencies": { 31 | "vigour-ua": "0.0.5" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hi 5 | 6 | 24 | 25 | 26 |
27 |

different left

28 |

different left

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