├── .gitignore ├── .jshintrc ├── .csslintrc ├── LICENSE ├── dist ├── msgBox.min.css └── msgBox.min.js ├── package.json ├── test ├── msgBox-spec.js └── chai.js ├── example └── example.html ├── README.md ├── src ├── msgBox.css └── msgBox.js ├── scss ├── msgBox.scss └── .scsslint.yml ├── karma.conf.js └── Gruntfile.js /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ project files 2 | /.idea 3 | /node_modules -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss":false, 3 | "curly":true, 4 | "eqeqeq":true, 5 | "eqnull":true, 6 | "expr":true, 7 | "immed":true, 8 | "newcap":true, 9 | "noempty":true, 10 | "noarg":true, 11 | "undef":true, 12 | "regexp":true, 13 | "browser":true, 14 | "devel":true, 15 | "node":true 16 | } -------------------------------------------------------------------------------- /.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "adjoining-classes":false, 3 | "box-sizing":false, 4 | "box-model":false, 5 | "compatible-vendor-prefixes":false, 6 | "floats":false, 7 | "font-sizes":false, 8 | "gradients":false, 9 | "important":false, 10 | "known-properties":false, 11 | "outline-none":false, 12 | "qualified-headings":false, 13 | "regex-selectors":false, 14 | "shorthand":false, 15 | "text-indent":false, 16 | "unique-headings":false, 17 | "universal-selector":false, 18 | "unqualified-attributes":false 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 reamd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/msgBox.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * msgbox v1.0.0 (https://github.com/reamd/msgbox.git) 3 | * Copyright 2016 reamd 4 | * Licensed under MIT 5 | */ 6 | 7 | *{padding:0;margin:0}.noScroll{overflow:hidden}.ui-dialog{position:fixed;z-index:100;display:none;width:100%;height:100%;box-sizing:border-box;background-color:rgba(0,0,0,.4)}.ui-dialog.show{display:block}.ui-dialog .ui-dialog-cnt{position:relative;top:50%;width:270px;box-sizing:border-box;margin:0 auto;background-color:rgba(253,253,253,.95);border-radius:6px}.ui-dialog .ui-dialog-hd{padding:10px;border-bottom:1px solid #e6e6e6}.ui-dialog .ui-dialog-hd h3{text-align:center}.ui-dialog .ui-dialog-close{float:right;margin-top:-32px}.ui-dialog .ui-dialog-close:before{font-size:26px;color:#00a5e0;cursor:pointer;content:"\00D7"}.ui-dialog .ui-dialog-bd{padding:18px}.ui-dialog .ui-dialog-bd h4{padding-bottom:10px;text-align:center}.ui-dialog .ui-dialog-ft button{width:50%;box-sizing:border-box;padding:10px 0;color:#00a5e0;cursor:pointer;background:#f8f8f8;border:0;border-top:1px solid #e6e6e6;outline:0}.ui-dialog .ui-dialog-ft button:nth-child(2){border-left:1px solid #e6e6e6}.ui-dialog .ui-dialog-ft button.alone{width:99%} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msgbox", 3 | "version": "1.0.0", 4 | "description": "原生js写的一个弹窗组件", 5 | "main": "Gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/reamd/msgbox.git" 12 | }, 13 | "author": "reamd", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/reamd/msgbox/issues" 17 | }, 18 | "homepage": "https://github.com/reamd/msgbox#readme", 19 | "devDependencies": { 20 | "chai": "^3.5.0", 21 | "grunt": "^0.4.5", 22 | "grunt-banner": "^0.6.0", 23 | "grunt-contrib-clean": "^1.0.0", 24 | "grunt-contrib-cssmin": "^0.14.0", 25 | "grunt-contrib-jshint": "^1.0.0", 26 | "grunt-contrib-sass": "^0.9.2", 27 | "grunt-contrib-uglify": "^0.11.1", 28 | "grunt-contrib-watch": "^0.6.1", 29 | "grunt-html": "^6.0.0", 30 | "grunt-karma": "^0.12.1", 31 | "grunt-scss-lint": "^0.3.8", 32 | "karma": "^0.13.21", 33 | "karma-chrome-launcher": "^0.2.2", 34 | "karma-coverage": "^0.5.3", 35 | "karma-firefox-launcher": "^0.1.7", 36 | "karma-mocha": "^0.2.2", 37 | "load-grunt-tasks": "^3.4.0", 38 | "mocha": "^2.4.5", 39 | "time-grunt": "^1.3.0" 40 | }, 41 | "dependencies": {} 42 | } 43 | -------------------------------------------------------------------------------- /test/msgBox-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by reamd on 2016/2/25. 3 | */ 4 | describe("msgBox", function() { 5 | var should = chai.should(); 6 | it("should is a object", function() { 7 | var msgbox = new msgBox({}); 8 | msgbox.should.be.a('object'); 9 | }); 10 | it("check it property", function() { 11 | var msgbox = new msgBox({}); 12 | msgbox.should.have.property('width').with.equal(''); 13 | msgbox.should.have.property('minWidth').with.equal('0'); 14 | msgbox.should.have.property('maxWidth').with.equal('100%'); 15 | msgbox.should.have.property('height').with.equal(''); 16 | msgbox.should.have.property('title').with.equal(''); 17 | msgbox.should.have.property('body').with.equal(''); 18 | msgbox.should.have.property('btnLabel').with.a('array').with.length(0); 19 | msgbox.should.have.property('visible').with.equal(true); 20 | msgbox.should.have.property('isClose').with.equal(true); 21 | msgbox.should.have.property('openMsg').with.a('function'); 22 | msgbox.should.have.property('closeMsg').with.a('function'); 23 | msgbox.should.have.property('complete').with.a('function'); 24 | msgbox.should.have.property('firstCallback').with.a('function'); 25 | msgbox.should.have.property('secondCallback').with.a('function'); 26 | }); 27 | }); -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 弹窗示例 9 | 10 | 11 | 12 |
1111111111111
13 | 14 | 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # msgBox说明 2 | 原生JavaScript弹窗组件 3 | # msgBox使用说明 4 | - **首先引入库相关的.css .js文件** 5 | - 未压缩版本(src文件夹下) 6 | ```js 7 | 8 | 9 | ``` 10 | - 压缩版本(dist文件夹下) 11 | ```js 12 | 13 | 14 | ``` 15 | - **控件初始化** 16 | ```js 17 | new msgBox({ 18 | width: '200px', //设置弹窗的宽度,不设置的话默认由弹窗内容决定 19 | minWidth: '100px', //设置弹窗的最小宽度,默认0 20 | maxWidth: '300px', //设置弹窗的最大宽度,默认100% 21 | height: '', //设置弹窗的高度,不设置的话默认由弹窗内容决定 22 | title: '提示语', //设置弹窗边框的标题 默认为空 23 | body: '
你好
', //设置弹窗内容,可由html模板组成 默认为空 24 | btnLabel: ['确定', '取消'], //设置弹窗底部按钮标题,数组形式,个数最多两个 默认为空 25 | visible: true, //设置弹窗初始化时是否显示,默认为true 26 | isClose: true, //设置弹窗是否显示右上角的关闭功能,默认为true 27 | callback: function() {}, //设置弹窗初始化完成后运行的回调函数,默认为空函数 28 | firstCallback: function() {}, //设置弹窗底部按钮一回调函数,默认为空函数 29 | secondCallback: function() {} //设置弹窗底部按钮二回调函数,默认为关闭弹窗功能的函数 30 | }); 31 | ``` 32 | - **控件方法** 33 | ```js 34 | //初始化后,通过实例调用 35 | var msg = new msgBox({title: '提示语', body: '你好', visible: false}); 36 | msg.openMsg(); //打开弹窗,一般当初始化时visible为false时使用 37 | msg.closeMsg();//关闭弹窗(注意无论调用方法还是手动关闭弹窗,都将销毁弹窗DOM节点,关闭后将无法使用openMsg方法打开) 38 | ``` -------------------------------------------------------------------------------- /src/msgBox.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; } 4 | 5 | .noScroll { 6 | overflow: hidden; 7 | } 8 | 9 | .ui-dialog { 10 | position: fixed; 11 | z-index: 100; 12 | display: none; 13 | width: 100%; 14 | height: 100%; 15 | box-sizing: border-box; 16 | background-color: rgba(0, 0, 0, 0.4); } 17 | .ui-dialog.show { 18 | display: block; } 19 | .ui-dialog .ui-dialog-cnt { 20 | position: relative; 21 | top: 50%; 22 | width: 270px; 23 | box-sizing: border-box; 24 | margin: 0 auto; 25 | background-color: rgba(253, 253, 253, 0.95); 26 | border-radius: 6px; } 27 | .ui-dialog .ui-dialog-hd { 28 | padding: 10px; 29 | border-bottom: 1px solid #e6e6e6; } 30 | .ui-dialog .ui-dialog-hd h3 { 31 | text-align: center; } 32 | .ui-dialog .ui-dialog-close { 33 | float: right; 34 | margin-top: -32px; } 35 | .ui-dialog .ui-dialog-close:before { 36 | font-size: 26px; 37 | color: #00a5e0; 38 | cursor: pointer; 39 | content: "\00D7"; 40 | } 41 | .ui-dialog .ui-dialog-bd { 42 | padding: 18px; } 43 | .ui-dialog .ui-dialog-bd h4 { 44 | padding-bottom: 10px; 45 | text-align: center; } 46 | .ui-dialog .ui-dialog-ft button { 47 | width: 50%; 48 | box-sizing: border-box; 49 | padding: 10px 0; 50 | color: #00a5e0; 51 | cursor: pointer; 52 | background: transparent; 53 | background-color: #f8f8f8; 54 | border: 0; 55 | border-top: 1px solid #e6e6e6; 56 | outline: none; } 57 | .ui-dialog .ui-dialog-ft button:nth-child(2) { 58 | border-left: 1px solid #e6e6e6; } 59 | .ui-dialog .ui-dialog-ft button.alone { 60 | width: 99%; } 61 | 62 | /*# sourceMappingURL=msgBox.css.map */ 63 | -------------------------------------------------------------------------------- /scss/msgBox.scss: -------------------------------------------------------------------------------- 1 | $border-color: #e6e6e6; 2 | $blue-color: #00a5e0; 3 | $button-back-color: #f8f8f8; 4 | * { 5 | padding: 0; 6 | margin: 0; 7 | } 8 | 9 | .noScroll { 10 | overflow: hidden; 11 | } 12 | 13 | .ui-dialog { 14 | position: fixed; 15 | z-index: 100; 16 | display: none; 17 | width: 100%; 18 | height: 100%; 19 | box-sizing: border-box; 20 | background-color: rgba(0,0,0,.4); 21 | &.show { 22 | display: block; 23 | } 24 | .ui-dialog-cnt { 25 | position: relative; 26 | top: 50%; 27 | width: 270px; 28 | box-sizing: border-box; 29 | margin: 0 auto; 30 | background-color: rgba(253,253,253,.95); 31 | border-radius: 6px; 32 | } 33 | .ui-dialog-hd { 34 | padding: 10px; 35 | border-bottom: 1px solid $border-color; 36 | } 37 | .ui-dialog-hd h3 { 38 | text-align: center; 39 | } 40 | .ui-dialog-close { 41 | float: right; 42 | margin-top: -32px; 43 | } 44 | .ui-dialog-close:before { 45 | font-size: 26px; 46 | color: $blue-color; 47 | cursor: pointer; 48 | content: "\00D7"; 49 | } 50 | .ui-dialog-bd { 51 | padding: 18px; 52 | } 53 | .ui-dialog-bd h4 { 54 | padding-bottom: 10px; 55 | text-align: center; 56 | } 57 | .ui-dialog-ft { 58 | button { 59 | width: 50%; 60 | box-sizing: border-box; 61 | padding: 10px 0; 62 | color: $blue-color; 63 | cursor: pointer; 64 | background: transparent; 65 | background-color: $button-back-color; 66 | border: 0; 67 | border-top: 1px solid $border-color; 68 | outline: none; 69 | &:nth-child(2) {border-left: 1px solid $border-color;} 70 | } 71 | button.alone { 72 | width: 99%; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Feb 25 2016 13:34:18 GMT+0800 (中国标准时间) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'src/msgBox.js', 19 | 'test/*.js' 20 | ], 21 | 22 | 23 | // list of files to exclude 24 | exclude: [ 25 | ], 26 | 27 | 28 | // preprocess matching files before serving them to the browser 29 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 30 | preprocessors: { 31 | 'msgBox.js': ['coverage'] 32 | }, 33 | 34 | 35 | // test results reporter to use 36 | // possible values: 'dots', 'progress' 37 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 38 | reporters: ['progress','coverage'], 39 | 40 | coverageReporter: { 41 | type: 'html', 42 | dir: 'test/coverage/' 43 | }, 44 | 45 | // web server port 46 | port: 9876, 47 | 48 | 49 | // enable / disable colors in the output (reporters and logs) 50 | colors: true, 51 | 52 | 53 | // level of logging 54 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 55 | logLevel: config.LOG_INFO, 56 | 57 | 58 | // enable / disable watching file and executing tests whenever any file changes 59 | autoWatch: true, 60 | 61 | 62 | // start these browsers 63 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 64 | browsers: ['Chrome'], 65 | 66 | 67 | // Continuous Integration mode 68 | // if true, Karma captures browsers, runs the tests and exits 69 | singleRun: false, 70 | 71 | // Concurrency level 72 | // how many browser should be started simultaneous 73 | concurrency: Infinity 74 | }); 75 | }; 76 | -------------------------------------------------------------------------------- /dist/msgBox.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * msgbox v1.0.0 (https://github.com/reamd/msgbox.git) 3 | * Copyright 2016 reamd 4 | * Licensed under MIT 5 | */ 6 | 7 | !function(a,b){"use strict";"function"==typeof define&&define.amd?define("msgBox",[],function(){return b}):"object"==typeof exports?module.exports.msgBox=b:a.msgBox=b}("undefined"!=typeof window?window:this,function(a){var b=document.createElement("div"),c=document.createAttribute("class"),d="",e="",f="",g="",h="",i="",j=this;this.width=a.width||"",this.minWidth=a.minWidth||"0",this.maxWidth=a.maxWidth||"100%",this.height=a.height||"",this.title=a.title||"",this.body=a.body||"",this.btnLabel=a.btnLabel||[],this.visible="boolean"!=typeof a.visible||a.visible,this.isClose="boolean"!=typeof a.isClose||a.isClose,this.openMsg=function(){this.classOpt("noScroll",!0),b.setAttribute("class","ui-dialog show")},this.closeMsg=function(){document.body.removeChild(b),this.classOpt("noScroll",!1)},this.complete=a.callback||function(){},this.firstCallback=a.firstCallback||function(){},this.secondCallback=a.secondCallback||function(){j.closeMsg()},this.classOpt=function(a,b){var c=document.body.getAttribute("class"),d="";if(b)if(c){if(c.indexOf(a)>-1)return;c+=" "+a,document.body.setAttribute("class",c)}else document.body.setAttribute("class",a);else c&&c===a?document.body.removeAttribute("class"):(c.indexOf(" "+a+" ")>-1?d=" "+a+" ":c.indexOf(" "+a)>-1?d=" "+a:c.indexOf(a+" ")>-1&&(d=a+" "),document.body.setAttribute("class",c.replace(d,"")))},this.width?(d='style="width:'+this.width+";min-width:"+this.minWidth+";max-width:"+this.maxWidth+'"',this.height&&(d='style="width:'+this.width+";min-width:"+this.minWidth+";max-width:"+this.maxWidth+";height:"+this.height+'"')):this.height&&(d='style="height:'+this.height+'"'),e=""===this.title?"

 

":"

"+this.title+"

",h="
"+this.body+"
",this.isClose&&(f=''),"[object Array]"===Object.prototype.toString.call(this.btnLabel)&&(1===this.btnLabel.length?i='":this.btnLabel.length>1&&(i='")),this.visible?(c.value="ui-dialog show",this.classOpt("noScroll",!0)):c.value="ui-dialog",b.setAttributeNode(c),b.innerHTML='
'+e+f+'
'+g+h+'
'+i+"
",document.body.insertBefore(b,document.body.firstChild),b.firstChild.getAttribute("style")?b.firstChild.setAttribute("style",b.firstChild.getAttribute("style")+";margin-top:-"+b.firstChild.offsetHeight/2+"px"):b.firstChild.setAttribute("style","margin-top:-"+b.firstChild.offsetHeight/2+"px"),setTimeout(this.complete,0),setTimeout(function(){j.isClose&&b.firstChild.firstChild.lastChild.addEventListener("click",function(){j.closeMsg()},!1),1===j.btnLabel.length?b.firstChild.childNodes[2].firstChild.addEventListener("click",j.firstCallback,!1):j.btnLabel.length>1&&(b.firstChild.childNodes[2].firstChild.addEventListener("click",j.firstCallback,!1),b.firstChild.childNodes[2].lastChild.addEventListener("click",j.secondCallback,!1))},0)}); -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function(grunt) { 3 | 4 | require('time-grunt')(grunt); 5 | require( "load-grunt-tasks" )( grunt ); 6 | // Project configuration. 7 | grunt.initConfig({ 8 | pkg: grunt.file.readJSON('package.json'), 9 | banner: '/*!\n' + 10 | ' * <%= pkg.name %> v<%= pkg.version %> (<%= pkg.repository.url %>)\n' + 11 | ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + 12 | ' * Licensed under MIT\n' + 13 | ' */\n', 14 | 15 | //清空style和js 16 | clean: { 17 | dist: { 18 | src: 'dist/' 19 | }, 20 | temp: { 21 | src: ['test/coverage'] 22 | } 23 | }, 24 | 25 | //js语法检查 26 | jshint: { 27 | files: ['src/*.js'], 28 | options: { 29 | globals:{ 30 | jshintrc:'.jshintrc' 31 | } 32 | } 33 | }, 34 | //css语法检查 35 | csslint:{ 36 | files:['src/*.css'], 37 | options:{ 38 | globals:{ 39 | csslintrc:'.csslintrc' 40 | } 41 | } 42 | }, 43 | //scss语法检查 44 | scsslint: { 45 | options: { 46 | config: 'scss/.scsslint.yml', 47 | reporterOutput: null 48 | }, 49 | src: ['scss/*.scss'] 50 | }, 51 | //html语法检查 52 | htmllint: { 53 | options: { 54 | ignore: [ 55 | 'Element “img” is missing required attribute “src”.', 56 | 'Bad value “X-UA-Compatible” for attribute “http-equiv” on element “meta”.', 57 | 'Attribute “autocomplete” not allowed on element “input” at this point.', 58 | 'Attribute “autocomplete” not allowed on element “button” at this point.', 59 | 'Element “div” not allowed as child of element “progress” in this context. (Suppressing further errors from this subtree.)', 60 | 'Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).', 61 | 'The “datetime” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.' 62 | ] 63 | }, 64 | src: 'example/*.html' 65 | }, 66 | 67 | //执行scss编译 68 | sass: { 69 | dist: { 70 | files:[{ 71 | expand: true, 72 | cwd: 'scss', 73 | src: ['*.scss'], 74 | dest: 'src/', 75 | ext: '.css' 76 | }] 77 | } 78 | }, 79 | //js压缩 80 | uglify: { 81 | options: { 82 | //beautify:true, 83 | //mangle: false //不混淆 84 | //banner: '<%= banner %>' 85 | }, 86 | build: { 87 | files: [{ 88 | expand: true, 89 | cwd: 'src/', 90 | src: ['*.js'], 91 | dest: 'dist/', 92 | ext: '.min.js' 93 | }] 94 | } 95 | }, 96 | //css压缩合并 97 | cssmin: { 98 | build: { 99 | files: [{ 100 | expand: true, 101 | cwd: 'src/', 102 | src: '*.css', 103 | dest: 'dist/', 104 | ext: '.min.css' 105 | }] 106 | } 107 | }, 108 | 109 | //为文件插入banner 110 | usebanner: { 111 | options: { 112 | position: 'top', 113 | banner: '<%= banner %>' 114 | }, 115 | files: { 116 | src: ['dist/*.css', 'dist/*.js'] 117 | } 118 | }, 119 | //自动化单元测试 120 | karma: { 121 | unit: { 122 | configFile: 'karma.conf.js', 123 | autoWatch: true 124 | } 125 | }, 126 | //监控,自动化 127 | watch:{ 128 | scss: { 129 | files: ['scss/*.scss'], 130 | tasks: ['sass'] 131 | } 132 | } 133 | 134 | }); 135 | 136 | // 语法校验 137 | grunt.registerTask('check', ['jshint', 'scsslint', 'htmllint']); 138 | 139 | // 推送版本前执行的工作 140 | grunt.registerTask('default', ['clean:dist', 'uglify', 'cssmin', 'usebanner']); 141 | 142 | }; -------------------------------------------------------------------------------- /src/msgBox.js: -------------------------------------------------------------------------------- 1 | //UMD通用接口 2 | (function (root, factory) { 3 | "use strict"; 4 | if (typeof define === 'function' && define.amd) { 5 | // AMD 6 | define('msgBox', [], function () { 7 | return factory; 8 | }); 9 | } else if (typeof exports === 'object') { 10 | // Node.js 11 | module.exports.msgBox = factory; 12 | 13 | } else { 14 | // Browser globals 15 | root.msgBox = factory; 16 | } 17 | }(typeof window !== "undefined" ? window : this, function (opt) { 18 | var newNode = document.createElement('div'), 19 | newClass = document.createAttribute('class'), 20 | cntAttr = '', 21 | h3Node = '', 22 | closeNode = '', 23 | cntTitleNode = '', 24 | cntBodyNode = '', 25 | btnNode = '', 26 | _self = this; 27 | 28 | //构造函数的数据结构 29 | this.width = opt.width || ''; 30 | this.minWidth = opt.minWidth || '0'; 31 | this.maxWidth = opt.maxWidth || '100%'; 32 | this.height = opt.height || ''; 33 | 34 | this.title = opt.title || ''; 35 | this.body = opt.body || ''; 36 | this.btnLabel = opt.btnLabel || []; 37 | 38 | this.visible = typeof opt.visible === 'boolean' ? opt.visible : true; 39 | this.isClose = typeof opt.isClose === 'boolean' ? opt.isClose : true; 40 | 41 | this.openMsg = function () { 42 | this.classOpt('noScroll',true); 43 | newNode.setAttribute('class', 'ui-dialog show'); 44 | }; 45 | this.closeMsg = function () { 46 | document.body.removeChild(newNode); 47 | this.classOpt('noScroll',false); 48 | }; 49 | 50 | this.complete = opt.callback || function () { 51 | }; 52 | this.firstCallback = opt.firstCallback || function () { 53 | }; 54 | this.secondCallback = opt.secondCallback || function () { 55 | _self.closeMsg(); 56 | }; 57 | //增加class相关方法 58 | this.classOpt = function(clsName, flag){ 59 | var className = document.body.getAttribute('class'), 60 | resName = ''; 61 | if(flag){//新增 62 | if(className){//body中存在class 63 | if(className.indexOf(clsName) > -1){ 64 | return; 65 | }else { 66 | className += ' ' + clsName; 67 | document.body.setAttribute('class', className); 68 | } 69 | }else { 70 | document.body.setAttribute('class', clsName); 71 | } 72 | }else {//移除 73 | if(className && className === clsName){ 74 | document.body.removeAttribute('class'); 75 | }else { 76 | if(className.indexOf(' '+ clsName +' ') > -1){ 77 | resName = ' '+ clsName +' '; 78 | }else if(className.indexOf(' '+ clsName) > -1){ 79 | resName = ' '+ clsName; 80 | }else if(className.indexOf(clsName+' ') > -1){ 81 | resName = clsName+' '; 82 | } 83 | document.body.setAttribute('class', className.replace(resName,'')); 84 | } 85 | } 86 | }; 87 | 88 | if (this.width) { 89 | cntAttr = 'style="width:' + this.width + ';min-width:' + this.minWidth + ';max-width:' + this.maxWidth + '"'; 90 | if (this.height) { 91 | cntAttr = 'style="width:' + this.width + ';min-width:' + this.minWidth + ';max-width:' + this.maxWidth + ';height:' + this.height + '"'; 92 | } 93 | } else if (this.height) { 94 | cntAttr = 'style="height:' + this.height + '"'; 95 | } 96 | if(this.title === '') { 97 | h3Node = '

 

'; 98 | }else { 99 | h3Node = '

' + this.title + '

'; 100 | } 101 | cntBodyNode = '
' + this.body + '
'; 102 | 103 | if (this.isClose) { 104 | closeNode = ''; 105 | } 106 | if (Object.prototype.toString.call(this.btnLabel) === "[object Array]") { 107 | if (this.btnLabel.length === 1) { 108 | btnNode = ''; 109 | } else if (this.btnLabel.length > 1) { 110 | btnNode = '' + 111 | ''; 112 | } 113 | } 114 | 115 | if (this.visible) { 116 | newClass.value = 'ui-dialog show'; 117 | this.classOpt('noScroll',true); 118 | } else { 119 | newClass.value = 'ui-dialog'; 120 | } 121 | newNode.setAttributeNode(newClass); 122 | newNode.innerHTML = '
' + 123 | '
' + 124 | h3Node + closeNode + 125 | '
' + 126 | '
' + 127 | cntTitleNode + cntBodyNode + 128 | '
' + 129 | '
' + 130 | btnNode + 131 | '
' + 132 | '
'; 133 | document.body.insertBefore(newNode, document.body.firstChild); 134 | //获取弹窗高度,然后设置margin-top 135 | if (!!newNode.firstChild.getAttribute('style')) { 136 | newNode.firstChild.setAttribute('style', newNode.firstChild.getAttribute('style') + ';margin-top:-' + newNode.firstChild.offsetHeight / 2 + 'px'); 137 | } else { 138 | newNode.firstChild.setAttribute('style', 'margin-top:-' + newNode.firstChild.offsetHeight / 2 + 'px'); 139 | } 140 | setTimeout(this.complete, 0); 141 | setTimeout(function () { 142 | if (_self.isClose) { 143 | newNode.firstChild.firstChild.lastChild.addEventListener('click', function () { 144 | _self.closeMsg(); 145 | }, false); 146 | } 147 | if (_self.btnLabel.length === 1) { 148 | newNode.firstChild.childNodes[2].firstChild.addEventListener('click', _self.firstCallback, false); 149 | } else if (_self.btnLabel.length > 1) { 150 | newNode.firstChild.childNodes[2].firstChild.addEventListener('click', _self.firstCallback, false); 151 | newNode.firstChild.childNodes[2].lastChild.addEventListener('click', _self.secondCallback, false); 152 | } 153 | }, 0); 154 | })); -------------------------------------------------------------------------------- /scss/.scsslint.yml: -------------------------------------------------------------------------------- 1 | scss_files: "scss/*.scss" 2 | 3 | linters: 4 | BangFormat: 5 | enabled: true 6 | space_before_bang: true 7 | space_after_bang: false 8 | #include: [] 9 | #exclude: ['_normalize.scss'] 10 | 11 | BorderZero: 12 | enabled: true 13 | 14 | ColorKeyword: 15 | enabled: true 16 | 17 | Comment: 18 | enabled: true 19 | 20 | DebugStatement: 21 | enabled: true 22 | 23 | DeclarationOrder: 24 | enabled: false 25 | 26 | DuplicateProperty: 27 | enabled: true 28 | 29 | ElsePlacement: 30 | enabled: true 31 | style: same_line # or 'new_line' 32 | 33 | EmptyLineBetweenBlocks: 34 | enabled: false 35 | ignore_single_line_blocks: true 36 | 37 | EmptyRule: 38 | enabled: true 39 | 40 | FinalNewline: 41 | enabled: true 42 | present: true 43 | 44 | HexLength: 45 | enabled: true 46 | style: short # or 'long' 47 | 48 | HexNotation: 49 | enabled: true 50 | style: lowercase # or 'uppercase' 51 | 52 | HexValidation: 53 | enabled: true 54 | 55 | IdSelector: 56 | enabled: true 57 | 58 | ImportPath: 59 | enabled: true 60 | leading_underscore: false 61 | filename_extension: false 62 | 63 | Indentation: 64 | enabled: true 65 | character: space # or 'tab' 66 | width: 2 67 | 68 | LeadingZero: 69 | enabled: false 70 | style: exclude_zero # or 'include_zero' 71 | 72 | MergeableSelector: 73 | enabled: false 74 | force_nesting: true 75 | 76 | NameFormat: 77 | enabled: true 78 | allow_leading_underscore: true 79 | convention: hyphenated_lowercase # or 'BEM', or a regex pattern 80 | 81 | NestingDepth: 82 | enabled: false 83 | 84 | PlaceholderInExtend: 85 | enabled: false 86 | 87 | PropertySortOrder: 88 | enabled: true 89 | ignore_unspecified: false 90 | severity: warning 91 | order: [ 92 | "position", 93 | "top", 94 | "right", 95 | "bottom", 96 | "left", 97 | "z-index", 98 | "display", 99 | "float", 100 | "width", 101 | "min-width", 102 | "max-width", 103 | "height", 104 | "min-height", 105 | "max-height", 106 | "-webkit-box-sizing", 107 | "-moz-box-sizing", 108 | "box-sizing", 109 | "-webkit-appearance", 110 | "flex", 111 | "flex-direction", 112 | "flex-flow", 113 | "flex-order", 114 | "flex-pack", 115 | "flex-align", 116 | "padding", 117 | "padding-top", 118 | "padding-right", 119 | "padding-bottom", 120 | "padding-left", 121 | "margin", 122 | "margin-top", 123 | "margin-right", 124 | "margin-bottom", 125 | "margin-left", 126 | "overflow", 127 | "overflow-x", 128 | "overflow-y", 129 | "-webkit-overflow-scrolling", 130 | "-ms-overflow-x", 131 | "-ms-overflow-y", 132 | "-ms-overflow-style", 133 | "clip", 134 | "clear", 135 | "font", 136 | "font-family", 137 | "font-size", 138 | "font-style", 139 | "font-weight", 140 | "font-variant", 141 | "font-size-adjust", 142 | "font-stretch", 143 | "font-effect", 144 | "font-emphasize", 145 | "font-emphasize-position", 146 | "font-emphasize-style", 147 | "font-smooth", 148 | "-webkit-hyphens", 149 | "-moz-hyphens", 150 | "hyphens", 151 | "line-height", 152 | "color", 153 | "text-align", 154 | "-webkit-text-align-last", 155 | "-moz-text-align-last", 156 | "-ms-text-align-last", 157 | "text-align-last", 158 | "text-emphasis", 159 | "text-emphasis-color", 160 | "text-emphasis-style", 161 | "text-emphasis-position", 162 | "text-decoration", 163 | "text-indent", 164 | "text-justify", 165 | "text-outline", 166 | "-ms-text-overflow", 167 | "text-overflow", 168 | "text-overflow-ellipsis", 169 | "text-overflow-mode", 170 | "text-shadow", 171 | "text-transform", 172 | "text-wrap", 173 | "-webkit-text-size-adjust", 174 | "-ms-text-size-adjust", 175 | "letter-spacing", 176 | "-ms-word-break", 177 | "word-break", 178 | "word-spacing", 179 | "-ms-word-wrap", 180 | "word-wrap", 181 | "-moz-tab-size", 182 | "-o-tab-size", 183 | "tab-size", 184 | "white-space", 185 | "vertical-align", 186 | "list-style", 187 | "list-style-position", 188 | "list-style-type", 189 | "list-style-image", 190 | "pointer-events", 191 | "-ms-touch-action", 192 | "touch-action", 193 | "cursor", 194 | "visibility", 195 | "zoom", 196 | "table-layout", 197 | "empty-cells", 198 | "caption-side", 199 | "border-spacing", 200 | "border-collapse", 201 | "content", 202 | "quotes", 203 | "counter-reset", 204 | "counter-increment", 205 | "resize", 206 | "-webkit-user-select", 207 | "-moz-user-select", 208 | "-ms-user-select", 209 | "-o-user-select", 210 | "user-select", 211 | "nav-index", 212 | "nav-up", 213 | "nav-right", 214 | "nav-down", 215 | "nav-left", 216 | "background", 217 | "background-color", 218 | "background-image", 219 | "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient", 220 | "filter:progid:DXImageTransform.Microsoft.gradient", 221 | "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader", 222 | "filter", 223 | "background-repeat", 224 | "background-attachment", 225 | "background-position", 226 | "background-position-x", 227 | "background-position-y", 228 | "-webkit-background-clip", 229 | "-moz-background-clip", 230 | "background-clip", 231 | "background-origin", 232 | "-webkit-background-size", 233 | "-moz-background-size", 234 | "-o-background-size", 235 | "background-size", 236 | "border", 237 | "border-color", 238 | "border-style", 239 | "border-width", 240 | "border-top", 241 | "border-top-color", 242 | "border-top-style", 243 | "border-top-width", 244 | "border-right", 245 | "border-right-color", 246 | "border-right-style", 247 | "border-right-width", 248 | "border-bottom", 249 | "border-bottom-color", 250 | "border-bottom-style", 251 | "border-bottom-width", 252 | "border-left", 253 | "border-left-color", 254 | "border-left-style", 255 | "border-left-width", 256 | "border-radius", 257 | "border-top-left-radius", 258 | "border-top-right-radius", 259 | "border-bottom-right-radius", 260 | "border-bottom-left-radius", 261 | "-webkit-border-image", 262 | "-moz-border-image", 263 | "-o-border-image", 264 | "border-image", 265 | "-webkit-border-image-source", 266 | "-moz-border-image-source", 267 | "-o-border-image-source", 268 | "border-image-source", 269 | "-webkit-border-image-slice", 270 | "-moz-border-image-slice", 271 | "-o-border-image-slice", 272 | "border-image-slice", 273 | "-webkit-border-image-width", 274 | "-moz-border-image-width", 275 | "-o-border-image-width", 276 | "border-image-width", 277 | "-webkit-border-image-outset", 278 | "-moz-border-image-outset", 279 | "-o-border-image-outset", 280 | "border-image-outset", 281 | "-webkit-border-image-repeat", 282 | "-moz-border-image-repeat", 283 | "-o-border-image-repeat", 284 | "border-image-repeat", 285 | "outline", 286 | "outline-width", 287 | "outline-style", 288 | "outline-color", 289 | "outline-offset", 290 | "-webkit-box-shadow", 291 | "-moz-box-shadow", 292 | "box-shadow", 293 | "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity", 294 | "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha", 295 | "opacity", 296 | "-ms-interpolation-mode", 297 | "-webkit-transition", 298 | "-moz-transition", 299 | "-ms-transition", 300 | "-o-transition", 301 | "transition", 302 | "-webkit-transition-delay", 303 | "-moz-transition-delay", 304 | "-ms-transition-delay", 305 | "-o-transition-delay", 306 | "transition-delay", 307 | "-webkit-transition-timing-function", 308 | "-moz-transition-timing-function", 309 | "-ms-transition-timing-function", 310 | "-o-transition-timing-function", 311 | "transition-timing-function", 312 | "-webkit-transition-duration", 313 | "-moz-transition-duration", 314 | "-ms-transition-duration", 315 | "-o-transition-duration", 316 | "transition-duration", 317 | "-webkit-transition-property", 318 | "-moz-transition-property", 319 | "-ms-transition-property", 320 | "-o-transition-property", 321 | "transition-property", 322 | "-webkit-transform", 323 | "-moz-transform", 324 | "-ms-transform", 325 | "-o-transform", 326 | "transform", 327 | "-webkit-transform-origin", 328 | "-moz-transform-origin", 329 | "-ms-transform-origin", 330 | "-o-transform-origin", 331 | "transform-origin", 332 | "-webkit-animation", 333 | "-moz-animation", 334 | "-ms-animation", 335 | "-o-animation", 336 | "animation", 337 | "-webkit-animation-name", 338 | "-moz-animation-name", 339 | "-ms-animation-name", 340 | "-o-animation-name", 341 | "animation-name", 342 | "-webkit-animation-duration", 343 | "-moz-animation-duration", 344 | "-ms-animation-duration", 345 | "-o-animation-duration", 346 | "animation-duration", 347 | "-webkit-animation-play-state", 348 | "-moz-animation-play-state", 349 | "-ms-animation-play-state", 350 | "-o-animation-play-state", 351 | "animation-play-state", 352 | "-webkit-animation-timing-function", 353 | "-moz-animation-timing-function", 354 | "-ms-animation-timing-function", 355 | "-o-animation-timing-function", 356 | "animation-timing-function", 357 | "-webkit-animation-delay", 358 | "-moz-animation-delay", 359 | "-ms-animation-delay", 360 | "-o-animation-delay", 361 | "animation-delay", 362 | "-webkit-animation-iteration-count", 363 | "-moz-animation-iteration-count", 364 | "-ms-animation-iteration-count", 365 | "-o-animation-iteration-count", 366 | "animation-iteration-count", 367 | "-webkit-animation-direction", 368 | "-moz-animation-direction", 369 | "-ms-animation-direction", 370 | "-o-animation-direction", 371 | "animation-direction" 372 | ] 373 | 374 | PropertySpelling: 375 | enabled: true 376 | extra_properties: [] 377 | 378 | QualifyingElement: 379 | enabled: false 380 | allow_element_with_attribute: false 381 | allow_element_with_class: false 382 | allow_element_with_id: false 383 | 384 | SelectorDepth: 385 | enabled: false 386 | 387 | SelectorFormat: 388 | enabled: true 389 | convention: hyphenated_lowercase # or 'BEM', or 'snake_case', or 'camel_case', or a regex pattern 390 | 391 | Shorthand: 392 | enabled: true 393 | 394 | SingleLinePerProperty: 395 | enabled: true 396 | allow_single_line_rule_sets: true 397 | 398 | SingleLinePerSelector: 399 | enabled: false 400 | 401 | SpaceAfterComma: 402 | enabled: false 403 | 404 | SpaceAfterPropertyColon: 405 | enabled: true 406 | style: at_least_one_space # or 'no_space', or 'at_least_one_space', or 'aligned' 407 | 408 | SpaceAfterPropertyName: 409 | enabled: true 410 | 411 | SpaceBeforeBrace: 412 | enabled: true 413 | style: space 414 | allow_single_line_padding: true 415 | 416 | SpaceBetweenParens: 417 | enabled: true 418 | spaces: 0 419 | 420 | StringQuotes: 421 | enabled: true 422 | style: double_quotes 423 | 424 | TrailingSemicolon: 425 | enabled: true 426 | 427 | TrailingZero: 428 | enabled: false 429 | 430 | UnnecessaryMantissa: 431 | enabled: true 432 | 433 | UnnecessaryParentReference: 434 | enabled: true 435 | 436 | UrlFormat: 437 | enabled: true 438 | 439 | UrlQuotes: 440 | enabled: true 441 | 442 | VendorPrefixes: 443 | enabled: true 444 | identifier_list: base 445 | 446 | ZeroUnit: 447 | enabled: true 448 | 449 | Compass::*: 450 | enabled: false 451 | -------------------------------------------------------------------------------- /test/chai.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chai = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 8 | * MIT Licensed 9 | */ 10 | 11 | var used = [] 12 | , exports = module.exports = {}; 13 | 14 | /*! 15 | * Chai version 16 | */ 17 | 18 | exports.version = '3.5.0'; 19 | 20 | /*! 21 | * Assertion Error 22 | */ 23 | 24 | exports.AssertionError = require('assertion-error'); 25 | 26 | /*! 27 | * Utils for plugins (not exported) 28 | */ 29 | 30 | var util = require('./chai/utils'); 31 | 32 | /** 33 | * # .use(function) 34 | * 35 | * Provides a way to extend the internals of Chai 36 | * 37 | * @param {Function} 38 | * @returns {this} for chaining 39 | * @api public 40 | */ 41 | 42 | exports.use = function (fn) { 43 | if (!~used.indexOf(fn)) { 44 | fn(this, util); 45 | used.push(fn); 46 | } 47 | 48 | return this; 49 | }; 50 | 51 | /*! 52 | * Utility Functions 53 | */ 54 | 55 | exports.util = util; 56 | 57 | /*! 58 | * Configuration 59 | */ 60 | 61 | var config = require('./chai/config'); 62 | exports.config = config; 63 | 64 | /*! 65 | * Primary `Assertion` prototype 66 | */ 67 | 68 | var assertion = require('./chai/assertion'); 69 | exports.use(assertion); 70 | 71 | /*! 72 | * Core Assertions 73 | */ 74 | 75 | var core = require('./chai/core/assertions'); 76 | exports.use(core); 77 | 78 | /*! 79 | * Expect interface 80 | */ 81 | 82 | var expect = require('./chai/interface/expect'); 83 | exports.use(expect); 84 | 85 | /*! 86 | * Should interface 87 | */ 88 | 89 | var should = require('./chai/interface/should'); 90 | exports.use(should); 91 | 92 | /*! 93 | * Assert interface 94 | */ 95 | 96 | var assert = require('./chai/interface/assert'); 97 | exports.use(assert); 98 | 99 | },{"./chai/assertion":3,"./chai/config":4,"./chai/core/assertions":5,"./chai/interface/assert":6,"./chai/interface/expect":7,"./chai/interface/should":8,"./chai/utils":22,"assertion-error":30}],3:[function(require,module,exports){ 100 | /*! 101 | * chai 102 | * http://chaijs.com 103 | * Copyright(c) 2011-2014 Jake Luer 104 | * MIT Licensed 105 | */ 106 | 107 | var config = require('./config'); 108 | 109 | module.exports = function (_chai, util) { 110 | /*! 111 | * Module dependencies. 112 | */ 113 | 114 | var AssertionError = _chai.AssertionError 115 | , flag = util.flag; 116 | 117 | /*! 118 | * Module export. 119 | */ 120 | 121 | _chai.Assertion = Assertion; 122 | 123 | /*! 124 | * Assertion Constructor 125 | * 126 | * Creates object for chaining. 127 | * 128 | * @api private 129 | */ 130 | 131 | function Assertion (obj, msg, stack) { 132 | flag(this, 'ssfi', stack || arguments.callee); 133 | flag(this, 'object', obj); 134 | flag(this, 'message', msg); 135 | } 136 | 137 | Object.defineProperty(Assertion, 'includeStack', { 138 | get: function() { 139 | console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); 140 | return config.includeStack; 141 | }, 142 | set: function(value) { 143 | console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); 144 | config.includeStack = value; 145 | } 146 | }); 147 | 148 | Object.defineProperty(Assertion, 'showDiff', { 149 | get: function() { 150 | console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); 151 | return config.showDiff; 152 | }, 153 | set: function(value) { 154 | console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); 155 | config.showDiff = value; 156 | } 157 | }); 158 | 159 | Assertion.addProperty = function (name, fn) { 160 | util.addProperty(this.prototype, name, fn); 161 | }; 162 | 163 | Assertion.addMethod = function (name, fn) { 164 | util.addMethod(this.prototype, name, fn); 165 | }; 166 | 167 | Assertion.addChainableMethod = function (name, fn, chainingBehavior) { 168 | util.addChainableMethod(this.prototype, name, fn, chainingBehavior); 169 | }; 170 | 171 | Assertion.overwriteProperty = function (name, fn) { 172 | util.overwriteProperty(this.prototype, name, fn); 173 | }; 174 | 175 | Assertion.overwriteMethod = function (name, fn) { 176 | util.overwriteMethod(this.prototype, name, fn); 177 | }; 178 | 179 | Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { 180 | util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); 181 | }; 182 | 183 | /** 184 | * ### .assert(expression, message, negateMessage, expected, actual, showDiff) 185 | * 186 | * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. 187 | * 188 | * @name assert 189 | * @param {Philosophical} expression to be tested 190 | * @param {String|Function} message or function that returns message to display if expression fails 191 | * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails 192 | * @param {Mixed} expected value (remember to check for negation) 193 | * @param {Mixed} actual (optional) will default to `this.obj` 194 | * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails 195 | * @api private 196 | */ 197 | 198 | Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { 199 | var ok = util.test(this, arguments); 200 | if (true !== showDiff) showDiff = false; 201 | if (true !== config.showDiff) showDiff = false; 202 | 203 | if (!ok) { 204 | var msg = util.getMessage(this, arguments) 205 | , actual = util.getActual(this, arguments); 206 | throw new AssertionError(msg, { 207 | actual: actual 208 | , expected: expected 209 | , showDiff: showDiff 210 | }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); 211 | } 212 | }; 213 | 214 | /*! 215 | * ### ._obj 216 | * 217 | * Quick reference to stored `actual` value for plugin developers. 218 | * 219 | * @api private 220 | */ 221 | 222 | Object.defineProperty(Assertion.prototype, '_obj', 223 | { get: function () { 224 | return flag(this, 'object'); 225 | } 226 | , set: function (val) { 227 | flag(this, 'object', val); 228 | } 229 | }); 230 | }; 231 | 232 | },{"./config":4}],4:[function(require,module,exports){ 233 | module.exports = { 234 | 235 | /** 236 | * ### config.includeStack 237 | * 238 | * User configurable property, influences whether stack trace 239 | * is included in Assertion error message. Default of false 240 | * suppresses stack trace in the error message. 241 | * 242 | * chai.config.includeStack = true; // enable stack on error 243 | * 244 | * @param {Boolean} 245 | * @api public 246 | */ 247 | 248 | includeStack: false, 249 | 250 | /** 251 | * ### config.showDiff 252 | * 253 | * User configurable property, influences whether or not 254 | * the `showDiff` flag should be included in the thrown 255 | * AssertionErrors. `false` will always be `false`; `true` 256 | * will be true when the assertion has requested a diff 257 | * be shown. 258 | * 259 | * @param {Boolean} 260 | * @api public 261 | */ 262 | 263 | showDiff: true, 264 | 265 | /** 266 | * ### config.truncateThreshold 267 | * 268 | * User configurable property, sets length threshold for actual and 269 | * expected values in assertion errors. If this threshold is exceeded, for 270 | * example for large data structures, the value is replaced with something 271 | * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. 272 | * 273 | * Set it to zero if you want to disable truncating altogether. 274 | * 275 | * This is especially userful when doing assertions on arrays: having this 276 | * set to a reasonable large value makes the failure messages readily 277 | * inspectable. 278 | * 279 | * chai.config.truncateThreshold = 0; // disable truncating 280 | * 281 | * @param {Number} 282 | * @api public 283 | */ 284 | 285 | truncateThreshold: 40 286 | 287 | }; 288 | 289 | },{}],5:[function(require,module,exports){ 290 | /*! 291 | * chai 292 | * http://chaijs.com 293 | * Copyright(c) 2011-2014 Jake Luer 294 | * MIT Licensed 295 | */ 296 | 297 | module.exports = function (chai, _) { 298 | var Assertion = chai.Assertion 299 | , toString = Object.prototype.toString 300 | , flag = _.flag; 301 | 302 | /** 303 | * ### Language Chains 304 | * 305 | * The following are provided as chainable getters to 306 | * improve the readability of your assertions. They 307 | * do not provide testing capabilities unless they 308 | * have been overwritten by a plugin. 309 | * 310 | * **Chains** 311 | * 312 | * - to 313 | * - be 314 | * - been 315 | * - is 316 | * - that 317 | * - which 318 | * - and 319 | * - has 320 | * - have 321 | * - with 322 | * - at 323 | * - of 324 | * - same 325 | * 326 | * @name language chains 327 | * @namespace BDD 328 | * @api public 329 | */ 330 | 331 | [ 'to', 'be', 'been' 332 | , 'is', 'and', 'has', 'have' 333 | , 'with', 'that', 'which', 'at' 334 | , 'of', 'same' ].forEach(function (chain) { 335 | Assertion.addProperty(chain, function () { 336 | return this; 337 | }); 338 | }); 339 | 340 | /** 341 | * ### .not 342 | * 343 | * Negates any of assertions following in the chain. 344 | * 345 | * expect(foo).to.not.equal('bar'); 346 | * expect(goodFn).to.not.throw(Error); 347 | * expect({ foo: 'baz' }).to.have.property('foo') 348 | * .and.not.equal('bar'); 349 | * 350 | * @name not 351 | * @namespace BDD 352 | * @api public 353 | */ 354 | 355 | Assertion.addProperty('not', function () { 356 | flag(this, 'negate', true); 357 | }); 358 | 359 | /** 360 | * ### .deep 361 | * 362 | * Sets the `deep` flag, later used by the `equal` and 363 | * `property` assertions. 364 | * 365 | * expect(foo).to.deep.equal({ bar: 'baz' }); 366 | * expect({ foo: { bar: { baz: 'quux' } } }) 367 | * .to.have.deep.property('foo.bar.baz', 'quux'); 368 | * 369 | * `.deep.property` special characters can be escaped 370 | * by adding two slashes before the `.` or `[]`. 371 | * 372 | * var deepCss = { '.link': { '[target]': 42 }}; 373 | * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); 374 | * 375 | * @name deep 376 | * @namespace BDD 377 | * @api public 378 | */ 379 | 380 | Assertion.addProperty('deep', function () { 381 | flag(this, 'deep', true); 382 | }); 383 | 384 | /** 385 | * ### .any 386 | * 387 | * Sets the `any` flag, (opposite of the `all` flag) 388 | * later used in the `keys` assertion. 389 | * 390 | * expect(foo).to.have.any.keys('bar', 'baz'); 391 | * 392 | * @name any 393 | * @namespace BDD 394 | * @api public 395 | */ 396 | 397 | Assertion.addProperty('any', function () { 398 | flag(this, 'any', true); 399 | flag(this, 'all', false) 400 | }); 401 | 402 | 403 | /** 404 | * ### .all 405 | * 406 | * Sets the `all` flag (opposite of the `any` flag) 407 | * later used by the `keys` assertion. 408 | * 409 | * expect(foo).to.have.all.keys('bar', 'baz'); 410 | * 411 | * @name all 412 | * @namespace BDD 413 | * @api public 414 | */ 415 | 416 | Assertion.addProperty('all', function () { 417 | flag(this, 'all', true); 418 | flag(this, 'any', false); 419 | }); 420 | 421 | /** 422 | * ### .a(type) 423 | * 424 | * The `a` and `an` assertions are aliases that can be 425 | * used either as language chains or to assert a value's 426 | * type. 427 | * 428 | * // typeof 429 | * expect('test').to.be.a('string'); 430 | * expect({ foo: 'bar' }).to.be.an('object'); 431 | * expect(null).to.be.a('null'); 432 | * expect(undefined).to.be.an('undefined'); 433 | * expect(new Error).to.be.an('error'); 434 | * expect(new Promise).to.be.a('promise'); 435 | * expect(new Float32Array()).to.be.a('float32array'); 436 | * expect(Symbol()).to.be.a('symbol'); 437 | * 438 | * // es6 overrides 439 | * expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo'); 440 | * 441 | * // language chain 442 | * expect(foo).to.be.an.instanceof(Foo); 443 | * 444 | * @name a 445 | * @alias an 446 | * @param {String} type 447 | * @param {String} message _optional_ 448 | * @namespace BDD 449 | * @api public 450 | */ 451 | 452 | function an (type, msg) { 453 | if (msg) flag(this, 'message', msg); 454 | type = type.toLowerCase(); 455 | var obj = flag(this, 'object') 456 | , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; 457 | 458 | this.assert( 459 | type === _.type(obj) 460 | , 'expected #{this} to be ' + article + type 461 | , 'expected #{this} not to be ' + article + type 462 | ); 463 | } 464 | 465 | Assertion.addChainableMethod('an', an); 466 | Assertion.addChainableMethod('a', an); 467 | 468 | /** 469 | * ### .include(value) 470 | * 471 | * The `include` and `contain` assertions can be used as either property 472 | * based language chains or as methods to assert the inclusion of an object 473 | * in an array or a substring in a string. When used as language chains, 474 | * they toggle the `contains` flag for the `keys` assertion. 475 | * 476 | * expect([1,2,3]).to.include(2); 477 | * expect('foobar').to.contain('foo'); 478 | * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); 479 | * 480 | * @name include 481 | * @alias contain 482 | * @alias includes 483 | * @alias contains 484 | * @param {Object|String|Number} obj 485 | * @param {String} message _optional_ 486 | * @namespace BDD 487 | * @api public 488 | */ 489 | 490 | function includeChainingBehavior () { 491 | flag(this, 'contains', true); 492 | } 493 | 494 | function include (val, msg) { 495 | _.expectTypes(this, ['array', 'object', 'string']); 496 | 497 | if (msg) flag(this, 'message', msg); 498 | var obj = flag(this, 'object'); 499 | var expected = false; 500 | 501 | if (_.type(obj) === 'array' && _.type(val) === 'object') { 502 | for (var i in obj) { 503 | if (_.eql(obj[i], val)) { 504 | expected = true; 505 | break; 506 | } 507 | } 508 | } else if (_.type(val) === 'object') { 509 | if (!flag(this, 'negate')) { 510 | for (var k in val) new Assertion(obj).property(k, val[k]); 511 | return; 512 | } 513 | var subset = {}; 514 | for (var k in val) subset[k] = obj[k]; 515 | expected = _.eql(subset, val); 516 | } else { 517 | expected = (obj != undefined) && ~obj.indexOf(val); 518 | } 519 | this.assert( 520 | expected 521 | , 'expected #{this} to include ' + _.inspect(val) 522 | , 'expected #{this} to not include ' + _.inspect(val)); 523 | } 524 | 525 | Assertion.addChainableMethod('include', include, includeChainingBehavior); 526 | Assertion.addChainableMethod('contain', include, includeChainingBehavior); 527 | Assertion.addChainableMethod('contains', include, includeChainingBehavior); 528 | Assertion.addChainableMethod('includes', include, includeChainingBehavior); 529 | 530 | /** 531 | * ### .ok 532 | * 533 | * Asserts that the target is truthy. 534 | * 535 | * expect('everything').to.be.ok; 536 | * expect(1).to.be.ok; 537 | * expect(false).to.not.be.ok; 538 | * expect(undefined).to.not.be.ok; 539 | * expect(null).to.not.be.ok; 540 | * 541 | * @name ok 542 | * @namespace BDD 543 | * @api public 544 | */ 545 | 546 | Assertion.addProperty('ok', function () { 547 | this.assert( 548 | flag(this, 'object') 549 | , 'expected #{this} to be truthy' 550 | , 'expected #{this} to be falsy'); 551 | }); 552 | 553 | /** 554 | * ### .true 555 | * 556 | * Asserts that the target is `true`. 557 | * 558 | * expect(true).to.be.true; 559 | * expect(1).to.not.be.true; 560 | * 561 | * @name true 562 | * @namespace BDD 563 | * @api public 564 | */ 565 | 566 | Assertion.addProperty('true', function () { 567 | this.assert( 568 | true === flag(this, 'object') 569 | , 'expected #{this} to be true' 570 | , 'expected #{this} to be false' 571 | , this.negate ? false : true 572 | ); 573 | }); 574 | 575 | /** 576 | * ### .false 577 | * 578 | * Asserts that the target is `false`. 579 | * 580 | * expect(false).to.be.false; 581 | * expect(0).to.not.be.false; 582 | * 583 | * @name false 584 | * @namespace BDD 585 | * @api public 586 | */ 587 | 588 | Assertion.addProperty('false', function () { 589 | this.assert( 590 | false === flag(this, 'object') 591 | , 'expected #{this} to be false' 592 | , 'expected #{this} to be true' 593 | , this.negate ? true : false 594 | ); 595 | }); 596 | 597 | /** 598 | * ### .null 599 | * 600 | * Asserts that the target is `null`. 601 | * 602 | * expect(null).to.be.null; 603 | * expect(undefined).to.not.be.null; 604 | * 605 | * @name null 606 | * @namespace BDD 607 | * @api public 608 | */ 609 | 610 | Assertion.addProperty('null', function () { 611 | this.assert( 612 | null === flag(this, 'object') 613 | , 'expected #{this} to be null' 614 | , 'expected #{this} not to be null' 615 | ); 616 | }); 617 | 618 | /** 619 | * ### .undefined 620 | * 621 | * Asserts that the target is `undefined`. 622 | * 623 | * expect(undefined).to.be.undefined; 624 | * expect(null).to.not.be.undefined; 625 | * 626 | * @name undefined 627 | * @namespace BDD 628 | * @api public 629 | */ 630 | 631 | Assertion.addProperty('undefined', function () { 632 | this.assert( 633 | undefined === flag(this, 'object') 634 | , 'expected #{this} to be undefined' 635 | , 'expected #{this} not to be undefined' 636 | ); 637 | }); 638 | 639 | /** 640 | * ### .NaN 641 | * Asserts that the target is `NaN`. 642 | * 643 | * expect('foo').to.be.NaN; 644 | * expect(4).not.to.be.NaN; 645 | * 646 | * @name NaN 647 | * @namespace BDD 648 | * @api public 649 | */ 650 | 651 | Assertion.addProperty('NaN', function () { 652 | this.assert( 653 | isNaN(flag(this, 'object')) 654 | , 'expected #{this} to be NaN' 655 | , 'expected #{this} not to be NaN' 656 | ); 657 | }); 658 | 659 | /** 660 | * ### .exist 661 | * 662 | * Asserts that the target is neither `null` nor `undefined`. 663 | * 664 | * var foo = 'hi' 665 | * , bar = null 666 | * , baz; 667 | * 668 | * expect(foo).to.exist; 669 | * expect(bar).to.not.exist; 670 | * expect(baz).to.not.exist; 671 | * 672 | * @name exist 673 | * @namespace BDD 674 | * @api public 675 | */ 676 | 677 | Assertion.addProperty('exist', function () { 678 | this.assert( 679 | null != flag(this, 'object') 680 | , 'expected #{this} to exist' 681 | , 'expected #{this} to not exist' 682 | ); 683 | }); 684 | 685 | 686 | /** 687 | * ### .empty 688 | * 689 | * Asserts that the target's length is `0`. For arrays and strings, it checks 690 | * the `length` property. For objects, it gets the count of 691 | * enumerable keys. 692 | * 693 | * expect([]).to.be.empty; 694 | * expect('').to.be.empty; 695 | * expect({}).to.be.empty; 696 | * 697 | * @name empty 698 | * @namespace BDD 699 | * @api public 700 | */ 701 | 702 | Assertion.addProperty('empty', function () { 703 | var obj = flag(this, 'object') 704 | , expected = obj; 705 | 706 | if (Array.isArray(obj) || 'string' === typeof object) { 707 | expected = obj.length; 708 | } else if (typeof obj === 'object') { 709 | expected = Object.keys(obj).length; 710 | } 711 | 712 | this.assert( 713 | !expected 714 | , 'expected #{this} to be empty' 715 | , 'expected #{this} not to be empty' 716 | ); 717 | }); 718 | 719 | /** 720 | * ### .arguments 721 | * 722 | * Asserts that the target is an arguments object. 723 | * 724 | * function test () { 725 | * expect(arguments).to.be.arguments; 726 | * } 727 | * 728 | * @name arguments 729 | * @alias Arguments 730 | * @namespace BDD 731 | * @api public 732 | */ 733 | 734 | function checkArguments () { 735 | var obj = flag(this, 'object') 736 | , type = Object.prototype.toString.call(obj); 737 | this.assert( 738 | '[object Arguments]' === type 739 | , 'expected #{this} to be arguments but got ' + type 740 | , 'expected #{this} to not be arguments' 741 | ); 742 | } 743 | 744 | Assertion.addProperty('arguments', checkArguments); 745 | Assertion.addProperty('Arguments', checkArguments); 746 | 747 | /** 748 | * ### .equal(value) 749 | * 750 | * Asserts that the target is strictly equal (`===`) to `value`. 751 | * Alternately, if the `deep` flag is set, asserts that 752 | * the target is deeply equal to `value`. 753 | * 754 | * expect('hello').to.equal('hello'); 755 | * expect(42).to.equal(42); 756 | * expect(1).to.not.equal(true); 757 | * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); 758 | * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); 759 | * 760 | * @name equal 761 | * @alias equals 762 | * @alias eq 763 | * @alias deep.equal 764 | * @param {Mixed} value 765 | * @param {String} message _optional_ 766 | * @namespace BDD 767 | * @api public 768 | */ 769 | 770 | function assertEqual (val, msg) { 771 | if (msg) flag(this, 'message', msg); 772 | var obj = flag(this, 'object'); 773 | if (flag(this, 'deep')) { 774 | return this.eql(val); 775 | } else { 776 | this.assert( 777 | val === obj 778 | , 'expected #{this} to equal #{exp}' 779 | , 'expected #{this} to not equal #{exp}' 780 | , val 781 | , this._obj 782 | , true 783 | ); 784 | } 785 | } 786 | 787 | Assertion.addMethod('equal', assertEqual); 788 | Assertion.addMethod('equals', assertEqual); 789 | Assertion.addMethod('eq', assertEqual); 790 | 791 | /** 792 | * ### .eql(value) 793 | * 794 | * Asserts that the target is deeply equal to `value`. 795 | * 796 | * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); 797 | * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); 798 | * 799 | * @name eql 800 | * @alias eqls 801 | * @param {Mixed} value 802 | * @param {String} message _optional_ 803 | * @namespace BDD 804 | * @api public 805 | */ 806 | 807 | function assertEql(obj, msg) { 808 | if (msg) flag(this, 'message', msg); 809 | this.assert( 810 | _.eql(obj, flag(this, 'object')) 811 | , 'expected #{this} to deeply equal #{exp}' 812 | , 'expected #{this} to not deeply equal #{exp}' 813 | , obj 814 | , this._obj 815 | , true 816 | ); 817 | } 818 | 819 | Assertion.addMethod('eql', assertEql); 820 | Assertion.addMethod('eqls', assertEql); 821 | 822 | /** 823 | * ### .above(value) 824 | * 825 | * Asserts that the target is greater than `value`. 826 | * 827 | * expect(10).to.be.above(5); 828 | * 829 | * Can also be used in conjunction with `length` to 830 | * assert a minimum length. The benefit being a 831 | * more informative error message than if the length 832 | * was supplied directly. 833 | * 834 | * expect('foo').to.have.length.above(2); 835 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 836 | * 837 | * @name above 838 | * @alias gt 839 | * @alias greaterThan 840 | * @param {Number} value 841 | * @param {String} message _optional_ 842 | * @namespace BDD 843 | * @api public 844 | */ 845 | 846 | function assertAbove (n, msg) { 847 | if (msg) flag(this, 'message', msg); 848 | var obj = flag(this, 'object'); 849 | if (flag(this, 'doLength')) { 850 | new Assertion(obj, msg).to.have.property('length'); 851 | var len = obj.length; 852 | this.assert( 853 | len > n 854 | , 'expected #{this} to have a length above #{exp} but got #{act}' 855 | , 'expected #{this} to not have a length above #{exp}' 856 | , n 857 | , len 858 | ); 859 | } else { 860 | this.assert( 861 | obj > n 862 | , 'expected #{this} to be above ' + n 863 | , 'expected #{this} to be at most ' + n 864 | ); 865 | } 866 | } 867 | 868 | Assertion.addMethod('above', assertAbove); 869 | Assertion.addMethod('gt', assertAbove); 870 | Assertion.addMethod('greaterThan', assertAbove); 871 | 872 | /** 873 | * ### .least(value) 874 | * 875 | * Asserts that the target is greater than or equal to `value`. 876 | * 877 | * expect(10).to.be.at.least(10); 878 | * 879 | * Can also be used in conjunction with `length` to 880 | * assert a minimum length. The benefit being a 881 | * more informative error message than if the length 882 | * was supplied directly. 883 | * 884 | * expect('foo').to.have.length.of.at.least(2); 885 | * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); 886 | * 887 | * @name least 888 | * @alias gte 889 | * @param {Number} value 890 | * @param {String} message _optional_ 891 | * @namespace BDD 892 | * @api public 893 | */ 894 | 895 | function assertLeast (n, msg) { 896 | if (msg) flag(this, 'message', msg); 897 | var obj = flag(this, 'object'); 898 | if (flag(this, 'doLength')) { 899 | new Assertion(obj, msg).to.have.property('length'); 900 | var len = obj.length; 901 | this.assert( 902 | len >= n 903 | , 'expected #{this} to have a length at least #{exp} but got #{act}' 904 | , 'expected #{this} to have a length below #{exp}' 905 | , n 906 | , len 907 | ); 908 | } else { 909 | this.assert( 910 | obj >= n 911 | , 'expected #{this} to be at least ' + n 912 | , 'expected #{this} to be below ' + n 913 | ); 914 | } 915 | } 916 | 917 | Assertion.addMethod('least', assertLeast); 918 | Assertion.addMethod('gte', assertLeast); 919 | 920 | /** 921 | * ### .below(value) 922 | * 923 | * Asserts that the target is less than `value`. 924 | * 925 | * expect(5).to.be.below(10); 926 | * 927 | * Can also be used in conjunction with `length` to 928 | * assert a maximum length. The benefit being a 929 | * more informative error message than if the length 930 | * was supplied directly. 931 | * 932 | * expect('foo').to.have.length.below(4); 933 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 934 | * 935 | * @name below 936 | * @alias lt 937 | * @alias lessThan 938 | * @param {Number} value 939 | * @param {String} message _optional_ 940 | * @namespace BDD 941 | * @api public 942 | */ 943 | 944 | function assertBelow (n, msg) { 945 | if (msg) flag(this, 'message', msg); 946 | var obj = flag(this, 'object'); 947 | if (flag(this, 'doLength')) { 948 | new Assertion(obj, msg).to.have.property('length'); 949 | var len = obj.length; 950 | this.assert( 951 | len < n 952 | , 'expected #{this} to have a length below #{exp} but got #{act}' 953 | , 'expected #{this} to not have a length below #{exp}' 954 | , n 955 | , len 956 | ); 957 | } else { 958 | this.assert( 959 | obj < n 960 | , 'expected #{this} to be below ' + n 961 | , 'expected #{this} to be at least ' + n 962 | ); 963 | } 964 | } 965 | 966 | Assertion.addMethod('below', assertBelow); 967 | Assertion.addMethod('lt', assertBelow); 968 | Assertion.addMethod('lessThan', assertBelow); 969 | 970 | /** 971 | * ### .most(value) 972 | * 973 | * Asserts that the target is less than or equal to `value`. 974 | * 975 | * expect(5).to.be.at.most(5); 976 | * 977 | * Can also be used in conjunction with `length` to 978 | * assert a maximum length. The benefit being a 979 | * more informative error message than if the length 980 | * was supplied directly. 981 | * 982 | * expect('foo').to.have.length.of.at.most(4); 983 | * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); 984 | * 985 | * @name most 986 | * @alias lte 987 | * @param {Number} value 988 | * @param {String} message _optional_ 989 | * @namespace BDD 990 | * @api public 991 | */ 992 | 993 | function assertMost (n, msg) { 994 | if (msg) flag(this, 'message', msg); 995 | var obj = flag(this, 'object'); 996 | if (flag(this, 'doLength')) { 997 | new Assertion(obj, msg).to.have.property('length'); 998 | var len = obj.length; 999 | this.assert( 1000 | len <= n 1001 | , 'expected #{this} to have a length at most #{exp} but got #{act}' 1002 | , 'expected #{this} to have a length above #{exp}' 1003 | , n 1004 | , len 1005 | ); 1006 | } else { 1007 | this.assert( 1008 | obj <= n 1009 | , 'expected #{this} to be at most ' + n 1010 | , 'expected #{this} to be above ' + n 1011 | ); 1012 | } 1013 | } 1014 | 1015 | Assertion.addMethod('most', assertMost); 1016 | Assertion.addMethod('lte', assertMost); 1017 | 1018 | /** 1019 | * ### .within(start, finish) 1020 | * 1021 | * Asserts that the target is within a range. 1022 | * 1023 | * expect(7).to.be.within(5,10); 1024 | * 1025 | * Can also be used in conjunction with `length` to 1026 | * assert a length range. The benefit being a 1027 | * more informative error message than if the length 1028 | * was supplied directly. 1029 | * 1030 | * expect('foo').to.have.length.within(2,4); 1031 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1032 | * 1033 | * @name within 1034 | * @param {Number} start lowerbound inclusive 1035 | * @param {Number} finish upperbound inclusive 1036 | * @param {String} message _optional_ 1037 | * @namespace BDD 1038 | * @api public 1039 | */ 1040 | 1041 | Assertion.addMethod('within', function (start, finish, msg) { 1042 | if (msg) flag(this, 'message', msg); 1043 | var obj = flag(this, 'object') 1044 | , range = start + '..' + finish; 1045 | if (flag(this, 'doLength')) { 1046 | new Assertion(obj, msg).to.have.property('length'); 1047 | var len = obj.length; 1048 | this.assert( 1049 | len >= start && len <= finish 1050 | , 'expected #{this} to have a length within ' + range 1051 | , 'expected #{this} to not have a length within ' + range 1052 | ); 1053 | } else { 1054 | this.assert( 1055 | obj >= start && obj <= finish 1056 | , 'expected #{this} to be within ' + range 1057 | , 'expected #{this} to not be within ' + range 1058 | ); 1059 | } 1060 | }); 1061 | 1062 | /** 1063 | * ### .instanceof(constructor) 1064 | * 1065 | * Asserts that the target is an instance of `constructor`. 1066 | * 1067 | * var Tea = function (name) { this.name = name; } 1068 | * , Chai = new Tea('chai'); 1069 | * 1070 | * expect(Chai).to.be.an.instanceof(Tea); 1071 | * expect([ 1, 2, 3 ]).to.be.instanceof(Array); 1072 | * 1073 | * @name instanceof 1074 | * @param {Constructor} constructor 1075 | * @param {String} message _optional_ 1076 | * @alias instanceOf 1077 | * @namespace BDD 1078 | * @api public 1079 | */ 1080 | 1081 | function assertInstanceOf (constructor, msg) { 1082 | if (msg) flag(this, 'message', msg); 1083 | var name = _.getName(constructor); 1084 | this.assert( 1085 | flag(this, 'object') instanceof constructor 1086 | , 'expected #{this} to be an instance of ' + name 1087 | , 'expected #{this} to not be an instance of ' + name 1088 | ); 1089 | }; 1090 | 1091 | Assertion.addMethod('instanceof', assertInstanceOf); 1092 | Assertion.addMethod('instanceOf', assertInstanceOf); 1093 | 1094 | /** 1095 | * ### .property(name, [value]) 1096 | * 1097 | * Asserts that the target has a property `name`, optionally asserting that 1098 | * the value of that property is strictly equal to `value`. 1099 | * If the `deep` flag is set, you can use dot- and bracket-notation for deep 1100 | * references into objects and arrays. 1101 | * 1102 | * // simple referencing 1103 | * var obj = { foo: 'bar' }; 1104 | * expect(obj).to.have.property('foo'); 1105 | * expect(obj).to.have.property('foo', 'bar'); 1106 | * 1107 | * // deep referencing 1108 | * var deepObj = { 1109 | * green: { tea: 'matcha' } 1110 | * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] 1111 | * }; 1112 | * 1113 | * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); 1114 | * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); 1115 | * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); 1116 | * 1117 | * You can also use an array as the starting point of a `deep.property` 1118 | * assertion, or traverse nested arrays. 1119 | * 1120 | * var arr = [ 1121 | * [ 'chai', 'matcha', 'konacha' ] 1122 | * , [ { tea: 'chai' } 1123 | * , { tea: 'matcha' } 1124 | * , { tea: 'konacha' } ] 1125 | * ]; 1126 | * 1127 | * expect(arr).to.have.deep.property('[0][1]', 'matcha'); 1128 | * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); 1129 | * 1130 | * Furthermore, `property` changes the subject of the assertion 1131 | * to be the value of that property from the original object. This 1132 | * permits for further chainable assertions on that property. 1133 | * 1134 | * expect(obj).to.have.property('foo') 1135 | * .that.is.a('string'); 1136 | * expect(deepObj).to.have.property('green') 1137 | * .that.is.an('object') 1138 | * .that.deep.equals({ tea: 'matcha' }); 1139 | * expect(deepObj).to.have.property('teas') 1140 | * .that.is.an('array') 1141 | * .with.deep.property('[2]') 1142 | * .that.deep.equals({ tea: 'konacha' }); 1143 | * 1144 | * Note that dots and bracket in `name` must be backslash-escaped when 1145 | * the `deep` flag is set, while they must NOT be escaped when the `deep` 1146 | * flag is not set. 1147 | * 1148 | * // simple referencing 1149 | * var css = { '.link[target]': 42 }; 1150 | * expect(css).to.have.property('.link[target]', 42); 1151 | * 1152 | * // deep referencing 1153 | * var deepCss = { '.link': { '[target]': 42 }}; 1154 | * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); 1155 | * 1156 | * @name property 1157 | * @alias deep.property 1158 | * @param {String} name 1159 | * @param {Mixed} value (optional) 1160 | * @param {String} message _optional_ 1161 | * @returns value of property for chaining 1162 | * @namespace BDD 1163 | * @api public 1164 | */ 1165 | 1166 | Assertion.addMethod('property', function (name, val, msg) { 1167 | if (msg) flag(this, 'message', msg); 1168 | 1169 | var isDeep = !!flag(this, 'deep') 1170 | , descriptor = isDeep ? 'deep property ' : 'property ' 1171 | , negate = flag(this, 'negate') 1172 | , obj = flag(this, 'object') 1173 | , pathInfo = isDeep ? _.getPathInfo(name, obj) : null 1174 | , hasProperty = isDeep 1175 | ? pathInfo.exists 1176 | : _.hasProperty(name, obj) 1177 | , value = isDeep 1178 | ? pathInfo.value 1179 | : obj[name]; 1180 | 1181 | if (negate && arguments.length > 1) { 1182 | if (undefined === value) { 1183 | msg = (msg != null) ? msg + ': ' : ''; 1184 | throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); 1185 | } 1186 | } else { 1187 | this.assert( 1188 | hasProperty 1189 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) 1190 | , 'expected #{this} to not have ' + descriptor + _.inspect(name)); 1191 | } 1192 | 1193 | if (arguments.length > 1) { 1194 | this.assert( 1195 | val === value 1196 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' 1197 | , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' 1198 | , val 1199 | , value 1200 | ); 1201 | } 1202 | 1203 | flag(this, 'object', value); 1204 | }); 1205 | 1206 | 1207 | /** 1208 | * ### .ownProperty(name) 1209 | * 1210 | * Asserts that the target has an own property `name`. 1211 | * 1212 | * expect('test').to.have.ownProperty('length'); 1213 | * 1214 | * @name ownProperty 1215 | * @alias haveOwnProperty 1216 | * @param {String} name 1217 | * @param {String} message _optional_ 1218 | * @namespace BDD 1219 | * @api public 1220 | */ 1221 | 1222 | function assertOwnProperty (name, msg) { 1223 | if (msg) flag(this, 'message', msg); 1224 | var obj = flag(this, 'object'); 1225 | this.assert( 1226 | obj.hasOwnProperty(name) 1227 | , 'expected #{this} to have own property ' + _.inspect(name) 1228 | , 'expected #{this} to not have own property ' + _.inspect(name) 1229 | ); 1230 | } 1231 | 1232 | Assertion.addMethod('ownProperty', assertOwnProperty); 1233 | Assertion.addMethod('haveOwnProperty', assertOwnProperty); 1234 | 1235 | /** 1236 | * ### .ownPropertyDescriptor(name[, descriptor[, message]]) 1237 | * 1238 | * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. 1239 | * 1240 | * expect('test').to.have.ownPropertyDescriptor('length'); 1241 | * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); 1242 | * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); 1243 | * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); 1244 | * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); 1245 | * 1246 | * @name ownPropertyDescriptor 1247 | * @alias haveOwnPropertyDescriptor 1248 | * @param {String} name 1249 | * @param {Object} descriptor _optional_ 1250 | * @param {String} message _optional_ 1251 | * @namespace BDD 1252 | * @api public 1253 | */ 1254 | 1255 | function assertOwnPropertyDescriptor (name, descriptor, msg) { 1256 | if (typeof descriptor === 'string') { 1257 | msg = descriptor; 1258 | descriptor = null; 1259 | } 1260 | if (msg) flag(this, 'message', msg); 1261 | var obj = flag(this, 'object'); 1262 | var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); 1263 | if (actualDescriptor && descriptor) { 1264 | this.assert( 1265 | _.eql(descriptor, actualDescriptor) 1266 | , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) 1267 | , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) 1268 | , descriptor 1269 | , actualDescriptor 1270 | , true 1271 | ); 1272 | } else { 1273 | this.assert( 1274 | actualDescriptor 1275 | , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) 1276 | , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) 1277 | ); 1278 | } 1279 | flag(this, 'object', actualDescriptor); 1280 | } 1281 | 1282 | Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); 1283 | Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); 1284 | 1285 | /** 1286 | * ### .length 1287 | * 1288 | * Sets the `doLength` flag later used as a chain precursor to a value 1289 | * comparison for the `length` property. 1290 | * 1291 | * expect('foo').to.have.length.above(2); 1292 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 1293 | * expect('foo').to.have.length.below(4); 1294 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 1295 | * expect('foo').to.have.length.within(2,4); 1296 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1297 | * 1298 | * *Deprecation notice:* Using `length` as an assertion will be deprecated 1299 | * in version 2.4.0 and removed in 3.0.0. Code using the old style of 1300 | * asserting for `length` property value using `length(value)` should be 1301 | * switched to use `lengthOf(value)` instead. 1302 | * 1303 | * @name length 1304 | * @namespace BDD 1305 | * @api public 1306 | */ 1307 | 1308 | /** 1309 | * ### .lengthOf(value[, message]) 1310 | * 1311 | * Asserts that the target's `length` property has 1312 | * the expected value. 1313 | * 1314 | * expect([ 1, 2, 3]).to.have.lengthOf(3); 1315 | * expect('foobar').to.have.lengthOf(6); 1316 | * 1317 | * @name lengthOf 1318 | * @param {Number} length 1319 | * @param {String} message _optional_ 1320 | * @namespace BDD 1321 | * @api public 1322 | */ 1323 | 1324 | function assertLengthChain () { 1325 | flag(this, 'doLength', true); 1326 | } 1327 | 1328 | function assertLength (n, msg) { 1329 | if (msg) flag(this, 'message', msg); 1330 | var obj = flag(this, 'object'); 1331 | new Assertion(obj, msg).to.have.property('length'); 1332 | var len = obj.length; 1333 | 1334 | this.assert( 1335 | len == n 1336 | , 'expected #{this} to have a length of #{exp} but got #{act}' 1337 | , 'expected #{this} to not have a length of #{act}' 1338 | , n 1339 | , len 1340 | ); 1341 | } 1342 | 1343 | Assertion.addChainableMethod('length', assertLength, assertLengthChain); 1344 | Assertion.addMethod('lengthOf', assertLength); 1345 | 1346 | /** 1347 | * ### .match(regexp) 1348 | * 1349 | * Asserts that the target matches a regular expression. 1350 | * 1351 | * expect('foobar').to.match(/^foo/); 1352 | * 1353 | * @name match 1354 | * @alias matches 1355 | * @param {RegExp} RegularExpression 1356 | * @param {String} message _optional_ 1357 | * @namespace BDD 1358 | * @api public 1359 | */ 1360 | function assertMatch(re, msg) { 1361 | if (msg) flag(this, 'message', msg); 1362 | var obj = flag(this, 'object'); 1363 | this.assert( 1364 | re.exec(obj) 1365 | , 'expected #{this} to match ' + re 1366 | , 'expected #{this} not to match ' + re 1367 | ); 1368 | } 1369 | 1370 | Assertion.addMethod('match', assertMatch); 1371 | Assertion.addMethod('matches', assertMatch); 1372 | 1373 | /** 1374 | * ### .string(string) 1375 | * 1376 | * Asserts that the string target contains another string. 1377 | * 1378 | * expect('foobar').to.have.string('bar'); 1379 | * 1380 | * @name string 1381 | * @param {String} string 1382 | * @param {String} message _optional_ 1383 | * @namespace BDD 1384 | * @api public 1385 | */ 1386 | 1387 | Assertion.addMethod('string', function (str, msg) { 1388 | if (msg) flag(this, 'message', msg); 1389 | var obj = flag(this, 'object'); 1390 | new Assertion(obj, msg).is.a('string'); 1391 | 1392 | this.assert( 1393 | ~obj.indexOf(str) 1394 | , 'expected #{this} to contain ' + _.inspect(str) 1395 | , 'expected #{this} to not contain ' + _.inspect(str) 1396 | ); 1397 | }); 1398 | 1399 | 1400 | /** 1401 | * ### .keys(key1, [key2], [...]) 1402 | * 1403 | * Asserts that the target contains any or all of the passed-in keys. 1404 | * Use in combination with `any`, `all`, `contains`, or `have` will affect 1405 | * what will pass. 1406 | * 1407 | * When used in conjunction with `any`, at least one key that is passed 1408 | * in must exist in the target object. This is regardless whether or not 1409 | * the `have` or `contain` qualifiers are used. Note, either `any` or `all` 1410 | * should be used in the assertion. If neither are used, the assertion is 1411 | * defaulted to `all`. 1412 | * 1413 | * When both `all` and `contain` are used, the target object must have at 1414 | * least all of the passed-in keys but may have more keys not listed. 1415 | * 1416 | * When both `all` and `have` are used, the target object must both contain 1417 | * all of the passed-in keys AND the number of keys in the target object must 1418 | * match the number of keys passed in (in other words, a target object must 1419 | * have all and only all of the passed-in keys). 1420 | * 1421 | * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); 1422 | * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); 1423 | * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); 1424 | * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); 1425 | * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); 1426 | * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); 1427 | * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); 1428 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); 1429 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); 1430 | * 1431 | * 1432 | * @name keys 1433 | * @alias key 1434 | * @param {...String|Array|Object} keys 1435 | * @namespace BDD 1436 | * @api public 1437 | */ 1438 | 1439 | function assertKeys (keys) { 1440 | var obj = flag(this, 'object') 1441 | , str 1442 | , ok = true 1443 | , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; 1444 | 1445 | switch (_.type(keys)) { 1446 | case "array": 1447 | if (arguments.length > 1) throw (new Error(mixedArgsMsg)); 1448 | break; 1449 | case "object": 1450 | if (arguments.length > 1) throw (new Error(mixedArgsMsg)); 1451 | keys = Object.keys(keys); 1452 | break; 1453 | default: 1454 | keys = Array.prototype.slice.call(arguments); 1455 | } 1456 | 1457 | if (!keys.length) throw new Error('keys required'); 1458 | 1459 | var actual = Object.keys(obj) 1460 | , expected = keys 1461 | , len = keys.length 1462 | , any = flag(this, 'any') 1463 | , all = flag(this, 'all'); 1464 | 1465 | if (!any && !all) { 1466 | all = true; 1467 | } 1468 | 1469 | // Has any 1470 | if (any) { 1471 | var intersection = expected.filter(function(key) { 1472 | return ~actual.indexOf(key); 1473 | }); 1474 | ok = intersection.length > 0; 1475 | } 1476 | 1477 | // Has all 1478 | if (all) { 1479 | ok = keys.every(function(key){ 1480 | return ~actual.indexOf(key); 1481 | }); 1482 | if (!flag(this, 'negate') && !flag(this, 'contains')) { 1483 | ok = ok && keys.length == actual.length; 1484 | } 1485 | } 1486 | 1487 | // Key string 1488 | if (len > 1) { 1489 | keys = keys.map(function(key){ 1490 | return _.inspect(key); 1491 | }); 1492 | var last = keys.pop(); 1493 | if (all) { 1494 | str = keys.join(', ') + ', and ' + last; 1495 | } 1496 | if (any) { 1497 | str = keys.join(', ') + ', or ' + last; 1498 | } 1499 | } else { 1500 | str = _.inspect(keys[0]); 1501 | } 1502 | 1503 | // Form 1504 | str = (len > 1 ? 'keys ' : 'key ') + str; 1505 | 1506 | // Have / include 1507 | str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; 1508 | 1509 | // Assertion 1510 | this.assert( 1511 | ok 1512 | , 'expected #{this} to ' + str 1513 | , 'expected #{this} to not ' + str 1514 | , expected.slice(0).sort() 1515 | , actual.sort() 1516 | , true 1517 | ); 1518 | } 1519 | 1520 | Assertion.addMethod('keys', assertKeys); 1521 | Assertion.addMethod('key', assertKeys); 1522 | 1523 | /** 1524 | * ### .throw(constructor) 1525 | * 1526 | * Asserts that the function target will throw a specific error, or specific type of error 1527 | * (as determined using `instanceof`), optionally with a RegExp or string inclusion test 1528 | * for the error's message. 1529 | * 1530 | * var err = new ReferenceError('This is a bad function.'); 1531 | * var fn = function () { throw err; } 1532 | * expect(fn).to.throw(ReferenceError); 1533 | * expect(fn).to.throw(Error); 1534 | * expect(fn).to.throw(/bad function/); 1535 | * expect(fn).to.not.throw('good function'); 1536 | * expect(fn).to.throw(ReferenceError, /bad function/); 1537 | * expect(fn).to.throw(err); 1538 | * 1539 | * Please note that when a throw expectation is negated, it will check each 1540 | * parameter independently, starting with error constructor type. The appropriate way 1541 | * to check for the existence of a type of error but for a message that does not match 1542 | * is to use `and`. 1543 | * 1544 | * expect(fn).to.throw(ReferenceError) 1545 | * .and.not.throw(/good function/); 1546 | * 1547 | * @name throw 1548 | * @alias throws 1549 | * @alias Throw 1550 | * @param {ErrorConstructor} constructor 1551 | * @param {String|RegExp} expected error message 1552 | * @param {String} message _optional_ 1553 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 1554 | * @returns error for chaining (null if no error) 1555 | * @namespace BDD 1556 | * @api public 1557 | */ 1558 | 1559 | function assertThrows (constructor, errMsg, msg) { 1560 | if (msg) flag(this, 'message', msg); 1561 | var obj = flag(this, 'object'); 1562 | new Assertion(obj, msg).is.a('function'); 1563 | 1564 | var thrown = false 1565 | , desiredError = null 1566 | , name = null 1567 | , thrownError = null; 1568 | 1569 | if (arguments.length === 0) { 1570 | errMsg = null; 1571 | constructor = null; 1572 | } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { 1573 | errMsg = constructor; 1574 | constructor = null; 1575 | } else if (constructor && constructor instanceof Error) { 1576 | desiredError = constructor; 1577 | constructor = null; 1578 | errMsg = null; 1579 | } else if (typeof constructor === 'function') { 1580 | name = constructor.prototype.name; 1581 | if (!name || (name === 'Error' && constructor !== Error)) { 1582 | name = constructor.name || (new constructor()).name; 1583 | } 1584 | } else { 1585 | constructor = null; 1586 | } 1587 | 1588 | try { 1589 | obj(); 1590 | } catch (err) { 1591 | // first, check desired error 1592 | if (desiredError) { 1593 | this.assert( 1594 | err === desiredError 1595 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 1596 | , 'expected #{this} to not throw #{exp}' 1597 | , (desiredError instanceof Error ? desiredError.toString() : desiredError) 1598 | , (err instanceof Error ? err.toString() : err) 1599 | ); 1600 | 1601 | flag(this, 'object', err); 1602 | return this; 1603 | } 1604 | 1605 | // next, check constructor 1606 | if (constructor) { 1607 | this.assert( 1608 | err instanceof constructor 1609 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 1610 | , 'expected #{this} to not throw #{exp} but #{act} was thrown' 1611 | , name 1612 | , (err instanceof Error ? err.toString() : err) 1613 | ); 1614 | 1615 | if (!errMsg) { 1616 | flag(this, 'object', err); 1617 | return this; 1618 | } 1619 | } 1620 | 1621 | // next, check message 1622 | var message = 'error' === _.type(err) && "message" in err 1623 | ? err.message 1624 | : '' + err; 1625 | 1626 | if ((message != null) && errMsg && errMsg instanceof RegExp) { 1627 | this.assert( 1628 | errMsg.exec(message) 1629 | , 'expected #{this} to throw error matching #{exp} but got #{act}' 1630 | , 'expected #{this} to throw error not matching #{exp}' 1631 | , errMsg 1632 | , message 1633 | ); 1634 | 1635 | flag(this, 'object', err); 1636 | return this; 1637 | } else if ((message != null) && errMsg && 'string' === typeof errMsg) { 1638 | this.assert( 1639 | ~message.indexOf(errMsg) 1640 | , 'expected #{this} to throw error including #{exp} but got #{act}' 1641 | , 'expected #{this} to throw error not including #{act}' 1642 | , errMsg 1643 | , message 1644 | ); 1645 | 1646 | flag(this, 'object', err); 1647 | return this; 1648 | } else { 1649 | thrown = true; 1650 | thrownError = err; 1651 | } 1652 | } 1653 | 1654 | var actuallyGot = '' 1655 | , expectedThrown = name !== null 1656 | ? name 1657 | : desiredError 1658 | ? '#{exp}' //_.inspect(desiredError) 1659 | : 'an error'; 1660 | 1661 | if (thrown) { 1662 | actuallyGot = ' but #{act} was thrown' 1663 | } 1664 | 1665 | this.assert( 1666 | thrown === true 1667 | , 'expected #{this} to throw ' + expectedThrown + actuallyGot 1668 | , 'expected #{this} to not throw ' + expectedThrown + actuallyGot 1669 | , (desiredError instanceof Error ? desiredError.toString() : desiredError) 1670 | , (thrownError instanceof Error ? thrownError.toString() : thrownError) 1671 | ); 1672 | 1673 | flag(this, 'object', thrownError); 1674 | }; 1675 | 1676 | Assertion.addMethod('throw', assertThrows); 1677 | Assertion.addMethod('throws', assertThrows); 1678 | Assertion.addMethod('Throw', assertThrows); 1679 | 1680 | /** 1681 | * ### .respondTo(method) 1682 | * 1683 | * Asserts that the object or class target will respond to a method. 1684 | * 1685 | * Klass.prototype.bar = function(){}; 1686 | * expect(Klass).to.respondTo('bar'); 1687 | * expect(obj).to.respondTo('bar'); 1688 | * 1689 | * To check if a constructor will respond to a static function, 1690 | * set the `itself` flag. 1691 | * 1692 | * Klass.baz = function(){}; 1693 | * expect(Klass).itself.to.respondTo('baz'); 1694 | * 1695 | * @name respondTo 1696 | * @alias respondsTo 1697 | * @param {String} method 1698 | * @param {String} message _optional_ 1699 | * @namespace BDD 1700 | * @api public 1701 | */ 1702 | 1703 | function respondTo (method, msg) { 1704 | if (msg) flag(this, 'message', msg); 1705 | var obj = flag(this, 'object') 1706 | , itself = flag(this, 'itself') 1707 | , context = ('function' === _.type(obj) && !itself) 1708 | ? obj.prototype[method] 1709 | : obj[method]; 1710 | 1711 | this.assert( 1712 | 'function' === typeof context 1713 | , 'expected #{this} to respond to ' + _.inspect(method) 1714 | , 'expected #{this} to not respond to ' + _.inspect(method) 1715 | ); 1716 | } 1717 | 1718 | Assertion.addMethod('respondTo', respondTo); 1719 | Assertion.addMethod('respondsTo', respondTo); 1720 | 1721 | /** 1722 | * ### .itself 1723 | * 1724 | * Sets the `itself` flag, later used by the `respondTo` assertion. 1725 | * 1726 | * function Foo() {} 1727 | * Foo.bar = function() {} 1728 | * Foo.prototype.baz = function() {} 1729 | * 1730 | * expect(Foo).itself.to.respondTo('bar'); 1731 | * expect(Foo).itself.not.to.respondTo('baz'); 1732 | * 1733 | * @name itself 1734 | * @namespace BDD 1735 | * @api public 1736 | */ 1737 | 1738 | Assertion.addProperty('itself', function () { 1739 | flag(this, 'itself', true); 1740 | }); 1741 | 1742 | /** 1743 | * ### .satisfy(method) 1744 | * 1745 | * Asserts that the target passes a given truth test. 1746 | * 1747 | * expect(1).to.satisfy(function(num) { return num > 0; }); 1748 | * 1749 | * @name satisfy 1750 | * @alias satisfies 1751 | * @param {Function} matcher 1752 | * @param {String} message _optional_ 1753 | * @namespace BDD 1754 | * @api public 1755 | */ 1756 | 1757 | function satisfy (matcher, msg) { 1758 | if (msg) flag(this, 'message', msg); 1759 | var obj = flag(this, 'object'); 1760 | var result = matcher(obj); 1761 | this.assert( 1762 | result 1763 | , 'expected #{this} to satisfy ' + _.objDisplay(matcher) 1764 | , 'expected #{this} to not satisfy' + _.objDisplay(matcher) 1765 | , this.negate ? false : true 1766 | , result 1767 | ); 1768 | } 1769 | 1770 | Assertion.addMethod('satisfy', satisfy); 1771 | Assertion.addMethod('satisfies', satisfy); 1772 | 1773 | /** 1774 | * ### .closeTo(expected, delta) 1775 | * 1776 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 1777 | * 1778 | * expect(1.5).to.be.closeTo(1, 0.5); 1779 | * 1780 | * @name closeTo 1781 | * @alias approximately 1782 | * @param {Number} expected 1783 | * @param {Number} delta 1784 | * @param {String} message _optional_ 1785 | * @namespace BDD 1786 | * @api public 1787 | */ 1788 | 1789 | function closeTo(expected, delta, msg) { 1790 | if (msg) flag(this, 'message', msg); 1791 | var obj = flag(this, 'object'); 1792 | 1793 | new Assertion(obj, msg).is.a('number'); 1794 | if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { 1795 | throw new Error('the arguments to closeTo or approximately must be numbers'); 1796 | } 1797 | 1798 | this.assert( 1799 | Math.abs(obj - expected) <= delta 1800 | , 'expected #{this} to be close to ' + expected + ' +/- ' + delta 1801 | , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta 1802 | ); 1803 | } 1804 | 1805 | Assertion.addMethod('closeTo', closeTo); 1806 | Assertion.addMethod('approximately', closeTo); 1807 | 1808 | function isSubsetOf(subset, superset, cmp) { 1809 | return subset.every(function(elem) { 1810 | if (!cmp) return superset.indexOf(elem) !== -1; 1811 | 1812 | return superset.some(function(elem2) { 1813 | return cmp(elem, elem2); 1814 | }); 1815 | }) 1816 | } 1817 | 1818 | /** 1819 | * ### .members(set) 1820 | * 1821 | * Asserts that the target is a superset of `set`, 1822 | * or that the target and `set` have the same strictly-equal (===) members. 1823 | * Alternately, if the `deep` flag is set, set members are compared for deep 1824 | * equality. 1825 | * 1826 | * expect([1, 2, 3]).to.include.members([3, 2]); 1827 | * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); 1828 | * 1829 | * expect([4, 2]).to.have.members([2, 4]); 1830 | * expect([5, 2]).to.not.have.members([5, 2, 1]); 1831 | * 1832 | * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); 1833 | * 1834 | * @name members 1835 | * @param {Array} set 1836 | * @param {String} message _optional_ 1837 | * @namespace BDD 1838 | * @api public 1839 | */ 1840 | 1841 | Assertion.addMethod('members', function (subset, msg) { 1842 | if (msg) flag(this, 'message', msg); 1843 | var obj = flag(this, 'object'); 1844 | 1845 | new Assertion(obj).to.be.an('array'); 1846 | new Assertion(subset).to.be.an('array'); 1847 | 1848 | var cmp = flag(this, 'deep') ? _.eql : undefined; 1849 | 1850 | if (flag(this, 'contains')) { 1851 | return this.assert( 1852 | isSubsetOf(subset, obj, cmp) 1853 | , 'expected #{this} to be a superset of #{act}' 1854 | , 'expected #{this} to not be a superset of #{act}' 1855 | , obj 1856 | , subset 1857 | ); 1858 | } 1859 | 1860 | this.assert( 1861 | isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) 1862 | , 'expected #{this} to have the same members as #{act}' 1863 | , 'expected #{this} to not have the same members as #{act}' 1864 | , obj 1865 | , subset 1866 | ); 1867 | }); 1868 | 1869 | /** 1870 | * ### .oneOf(list) 1871 | * 1872 | * Assert that a value appears somewhere in the top level of array `list`. 1873 | * 1874 | * expect('a').to.be.oneOf(['a', 'b', 'c']); 1875 | * expect(9).to.not.be.oneOf(['z']); 1876 | * expect([3]).to.not.be.oneOf([1, 2, [3]]); 1877 | * 1878 | * var three = [3]; 1879 | * // for object-types, contents are not compared 1880 | * expect(three).to.not.be.oneOf([1, 2, [3]]); 1881 | * // comparing references works 1882 | * expect(three).to.be.oneOf([1, 2, three]); 1883 | * 1884 | * @name oneOf 1885 | * @param {Array<*>} list 1886 | * @param {String} message _optional_ 1887 | * @namespace BDD 1888 | * @api public 1889 | */ 1890 | 1891 | function oneOf (list, msg) { 1892 | if (msg) flag(this, 'message', msg); 1893 | var expected = flag(this, 'object'); 1894 | new Assertion(list).to.be.an('array'); 1895 | 1896 | this.assert( 1897 | list.indexOf(expected) > -1 1898 | , 'expected #{this} to be one of #{exp}' 1899 | , 'expected #{this} to not be one of #{exp}' 1900 | , list 1901 | , expected 1902 | ); 1903 | } 1904 | 1905 | Assertion.addMethod('oneOf', oneOf); 1906 | 1907 | 1908 | /** 1909 | * ### .change(function) 1910 | * 1911 | * Asserts that a function changes an object property 1912 | * 1913 | * var obj = { val: 10 }; 1914 | * var fn = function() { obj.val += 3 }; 1915 | * var noChangeFn = function() { return 'foo' + 'bar'; } 1916 | * expect(fn).to.change(obj, 'val'); 1917 | * expect(noChangeFn).to.not.change(obj, 'val') 1918 | * 1919 | * @name change 1920 | * @alias changes 1921 | * @alias Change 1922 | * @param {String} object 1923 | * @param {String} property name 1924 | * @param {String} message _optional_ 1925 | * @namespace BDD 1926 | * @api public 1927 | */ 1928 | 1929 | function assertChanges (object, prop, msg) { 1930 | if (msg) flag(this, 'message', msg); 1931 | var fn = flag(this, 'object'); 1932 | new Assertion(object, msg).to.have.property(prop); 1933 | new Assertion(fn).is.a('function'); 1934 | 1935 | var initial = object[prop]; 1936 | fn(); 1937 | 1938 | this.assert( 1939 | initial !== object[prop] 1940 | , 'expected .' + prop + ' to change' 1941 | , 'expected .' + prop + ' to not change' 1942 | ); 1943 | } 1944 | 1945 | Assertion.addChainableMethod('change', assertChanges); 1946 | Assertion.addChainableMethod('changes', assertChanges); 1947 | 1948 | /** 1949 | * ### .increase(function) 1950 | * 1951 | * Asserts that a function increases an object property 1952 | * 1953 | * var obj = { val: 10 }; 1954 | * var fn = function() { obj.val = 15 }; 1955 | * expect(fn).to.increase(obj, 'val'); 1956 | * 1957 | * @name increase 1958 | * @alias increases 1959 | * @alias Increase 1960 | * @param {String} object 1961 | * @param {String} property name 1962 | * @param {String} message _optional_ 1963 | * @namespace BDD 1964 | * @api public 1965 | */ 1966 | 1967 | function assertIncreases (object, prop, msg) { 1968 | if (msg) flag(this, 'message', msg); 1969 | var fn = flag(this, 'object'); 1970 | new Assertion(object, msg).to.have.property(prop); 1971 | new Assertion(fn).is.a('function'); 1972 | 1973 | var initial = object[prop]; 1974 | fn(); 1975 | 1976 | this.assert( 1977 | object[prop] - initial > 0 1978 | , 'expected .' + prop + ' to increase' 1979 | , 'expected .' + prop + ' to not increase' 1980 | ); 1981 | } 1982 | 1983 | Assertion.addChainableMethod('increase', assertIncreases); 1984 | Assertion.addChainableMethod('increases', assertIncreases); 1985 | 1986 | /** 1987 | * ### .decrease(function) 1988 | * 1989 | * Asserts that a function decreases an object property 1990 | * 1991 | * var obj = { val: 10 }; 1992 | * var fn = function() { obj.val = 5 }; 1993 | * expect(fn).to.decrease(obj, 'val'); 1994 | * 1995 | * @name decrease 1996 | * @alias decreases 1997 | * @alias Decrease 1998 | * @param {String} object 1999 | * @param {String} property name 2000 | * @param {String} message _optional_ 2001 | * @namespace BDD 2002 | * @api public 2003 | */ 2004 | 2005 | function assertDecreases (object, prop, msg) { 2006 | if (msg) flag(this, 'message', msg); 2007 | var fn = flag(this, 'object'); 2008 | new Assertion(object, msg).to.have.property(prop); 2009 | new Assertion(fn).is.a('function'); 2010 | 2011 | var initial = object[prop]; 2012 | fn(); 2013 | 2014 | this.assert( 2015 | object[prop] - initial < 0 2016 | , 'expected .' + prop + ' to decrease' 2017 | , 'expected .' + prop + ' to not decrease' 2018 | ); 2019 | } 2020 | 2021 | Assertion.addChainableMethod('decrease', assertDecreases); 2022 | Assertion.addChainableMethod('decreases', assertDecreases); 2023 | 2024 | /** 2025 | * ### .extensible 2026 | * 2027 | * Asserts that the target is extensible (can have new properties added to 2028 | * it). 2029 | * 2030 | * var nonExtensibleObject = Object.preventExtensions({}); 2031 | * var sealedObject = Object.seal({}); 2032 | * var frozenObject = Object.freeze({}); 2033 | * 2034 | * expect({}).to.be.extensible; 2035 | * expect(nonExtensibleObject).to.not.be.extensible; 2036 | * expect(sealedObject).to.not.be.extensible; 2037 | * expect(frozenObject).to.not.be.extensible; 2038 | * 2039 | * @name extensible 2040 | * @namespace BDD 2041 | * @api public 2042 | */ 2043 | 2044 | Assertion.addProperty('extensible', function() { 2045 | var obj = flag(this, 'object'); 2046 | 2047 | // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. 2048 | // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. 2049 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible 2050 | // The following provides ES6 behavior when a TypeError is thrown under ES5. 2051 | 2052 | var isExtensible; 2053 | 2054 | try { 2055 | isExtensible = Object.isExtensible(obj); 2056 | } catch (err) { 2057 | if (err instanceof TypeError) isExtensible = false; 2058 | else throw err; 2059 | } 2060 | 2061 | this.assert( 2062 | isExtensible 2063 | , 'expected #{this} to be extensible' 2064 | , 'expected #{this} to not be extensible' 2065 | ); 2066 | }); 2067 | 2068 | /** 2069 | * ### .sealed 2070 | * 2071 | * Asserts that the target is sealed (cannot have new properties added to it 2072 | * and its existing properties cannot be removed). 2073 | * 2074 | * var sealedObject = Object.seal({}); 2075 | * var frozenObject = Object.freeze({}); 2076 | * 2077 | * expect(sealedObject).to.be.sealed; 2078 | * expect(frozenObject).to.be.sealed; 2079 | * expect({}).to.not.be.sealed; 2080 | * 2081 | * @name sealed 2082 | * @namespace BDD 2083 | * @api public 2084 | */ 2085 | 2086 | Assertion.addProperty('sealed', function() { 2087 | var obj = flag(this, 'object'); 2088 | 2089 | // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. 2090 | // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true. 2091 | // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed 2092 | // The following provides ES6 behavior when a TypeError is thrown under ES5. 2093 | 2094 | var isSealed; 2095 | 2096 | try { 2097 | isSealed = Object.isSealed(obj); 2098 | } catch (err) { 2099 | if (err instanceof TypeError) isSealed = true; 2100 | else throw err; 2101 | } 2102 | 2103 | this.assert( 2104 | isSealed 2105 | , 'expected #{this} to be sealed' 2106 | , 'expected #{this} to not be sealed' 2107 | ); 2108 | }); 2109 | 2110 | /** 2111 | * ### .frozen 2112 | * 2113 | * Asserts that the target is frozen (cannot have new properties added to it 2114 | * and its existing properties cannot be modified). 2115 | * 2116 | * var frozenObject = Object.freeze({}); 2117 | * 2118 | * expect(frozenObject).to.be.frozen; 2119 | * expect({}).to.not.be.frozen; 2120 | * 2121 | * @name frozen 2122 | * @namespace BDD 2123 | * @api public 2124 | */ 2125 | 2126 | Assertion.addProperty('frozen', function() { 2127 | var obj = flag(this, 'object'); 2128 | 2129 | // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. 2130 | // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true. 2131 | // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen 2132 | // The following provides ES6 behavior when a TypeError is thrown under ES5. 2133 | 2134 | var isFrozen; 2135 | 2136 | try { 2137 | isFrozen = Object.isFrozen(obj); 2138 | } catch (err) { 2139 | if (err instanceof TypeError) isFrozen = true; 2140 | else throw err; 2141 | } 2142 | 2143 | this.assert( 2144 | isFrozen 2145 | , 'expected #{this} to be frozen' 2146 | , 'expected #{this} to not be frozen' 2147 | ); 2148 | }); 2149 | }; 2150 | 2151 | },{}],6:[function(require,module,exports){ 2152 | /*! 2153 | * chai 2154 | * Copyright(c) 2011-2014 Jake Luer 2155 | * MIT Licensed 2156 | */ 2157 | 2158 | 2159 | module.exports = function (chai, util) { 2160 | 2161 | /*! 2162 | * Chai dependencies. 2163 | */ 2164 | 2165 | var Assertion = chai.Assertion 2166 | , flag = util.flag; 2167 | 2168 | /*! 2169 | * Module export. 2170 | */ 2171 | 2172 | /** 2173 | * ### assert(expression, message) 2174 | * 2175 | * Write your own test expressions. 2176 | * 2177 | * assert('foo' !== 'bar', 'foo is not bar'); 2178 | * assert(Array.isArray([]), 'empty arrays are arrays'); 2179 | * 2180 | * @param {Mixed} expression to test for truthiness 2181 | * @param {String} message to display on error 2182 | * @name assert 2183 | * @namespace Assert 2184 | * @api public 2185 | */ 2186 | 2187 | var assert = chai.assert = function (express, errmsg) { 2188 | var test = new Assertion(null, null, chai.assert); 2189 | test.assert( 2190 | express 2191 | , errmsg 2192 | , '[ negation message unavailable ]' 2193 | ); 2194 | }; 2195 | 2196 | /** 2197 | * ### .fail(actual, expected, [message], [operator]) 2198 | * 2199 | * Throw a failure. Node.js `assert` module-compatible. 2200 | * 2201 | * @name fail 2202 | * @param {Mixed} actual 2203 | * @param {Mixed} expected 2204 | * @param {String} message 2205 | * @param {String} operator 2206 | * @namespace Assert 2207 | * @api public 2208 | */ 2209 | 2210 | assert.fail = function (actual, expected, message, operator) { 2211 | message = message || 'assert.fail()'; 2212 | throw new chai.AssertionError(message, { 2213 | actual: actual 2214 | , expected: expected 2215 | , operator: operator 2216 | }, assert.fail); 2217 | }; 2218 | 2219 | /** 2220 | * ### .isOk(object, [message]) 2221 | * 2222 | * Asserts that `object` is truthy. 2223 | * 2224 | * assert.isOk('everything', 'everything is ok'); 2225 | * assert.isOk(false, 'this will fail'); 2226 | * 2227 | * @name isOk 2228 | * @alias ok 2229 | * @param {Mixed} object to test 2230 | * @param {String} message 2231 | * @namespace Assert 2232 | * @api public 2233 | */ 2234 | 2235 | assert.isOk = function (val, msg) { 2236 | new Assertion(val, msg).is.ok; 2237 | }; 2238 | 2239 | /** 2240 | * ### .isNotOk(object, [message]) 2241 | * 2242 | * Asserts that `object` is falsy. 2243 | * 2244 | * assert.isNotOk('everything', 'this will fail'); 2245 | * assert.isNotOk(false, 'this will pass'); 2246 | * 2247 | * @name isNotOk 2248 | * @alias notOk 2249 | * @param {Mixed} object to test 2250 | * @param {String} message 2251 | * @namespace Assert 2252 | * @api public 2253 | */ 2254 | 2255 | assert.isNotOk = function (val, msg) { 2256 | new Assertion(val, msg).is.not.ok; 2257 | }; 2258 | 2259 | /** 2260 | * ### .equal(actual, expected, [message]) 2261 | * 2262 | * Asserts non-strict equality (`==`) of `actual` and `expected`. 2263 | * 2264 | * assert.equal(3, '3', '== coerces values to strings'); 2265 | * 2266 | * @name equal 2267 | * @param {Mixed} actual 2268 | * @param {Mixed} expected 2269 | * @param {String} message 2270 | * @namespace Assert 2271 | * @api public 2272 | */ 2273 | 2274 | assert.equal = function (act, exp, msg) { 2275 | var test = new Assertion(act, msg, assert.equal); 2276 | 2277 | test.assert( 2278 | exp == flag(test, 'object') 2279 | , 'expected #{this} to equal #{exp}' 2280 | , 'expected #{this} to not equal #{act}' 2281 | , exp 2282 | , act 2283 | ); 2284 | }; 2285 | 2286 | /** 2287 | * ### .notEqual(actual, expected, [message]) 2288 | * 2289 | * Asserts non-strict inequality (`!=`) of `actual` and `expected`. 2290 | * 2291 | * assert.notEqual(3, 4, 'these numbers are not equal'); 2292 | * 2293 | * @name notEqual 2294 | * @param {Mixed} actual 2295 | * @param {Mixed} expected 2296 | * @param {String} message 2297 | * @namespace Assert 2298 | * @api public 2299 | */ 2300 | 2301 | assert.notEqual = function (act, exp, msg) { 2302 | var test = new Assertion(act, msg, assert.notEqual); 2303 | 2304 | test.assert( 2305 | exp != flag(test, 'object') 2306 | , 'expected #{this} to not equal #{exp}' 2307 | , 'expected #{this} to equal #{act}' 2308 | , exp 2309 | , act 2310 | ); 2311 | }; 2312 | 2313 | /** 2314 | * ### .strictEqual(actual, expected, [message]) 2315 | * 2316 | * Asserts strict equality (`===`) of `actual` and `expected`. 2317 | * 2318 | * assert.strictEqual(true, true, 'these booleans are strictly equal'); 2319 | * 2320 | * @name strictEqual 2321 | * @param {Mixed} actual 2322 | * @param {Mixed} expected 2323 | * @param {String} message 2324 | * @namespace Assert 2325 | * @api public 2326 | */ 2327 | 2328 | assert.strictEqual = function (act, exp, msg) { 2329 | new Assertion(act, msg).to.equal(exp); 2330 | }; 2331 | 2332 | /** 2333 | * ### .notStrictEqual(actual, expected, [message]) 2334 | * 2335 | * Asserts strict inequality (`!==`) of `actual` and `expected`. 2336 | * 2337 | * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); 2338 | * 2339 | * @name notStrictEqual 2340 | * @param {Mixed} actual 2341 | * @param {Mixed} expected 2342 | * @param {String} message 2343 | * @namespace Assert 2344 | * @api public 2345 | */ 2346 | 2347 | assert.notStrictEqual = function (act, exp, msg) { 2348 | new Assertion(act, msg).to.not.equal(exp); 2349 | }; 2350 | 2351 | /** 2352 | * ### .deepEqual(actual, expected, [message]) 2353 | * 2354 | * Asserts that `actual` is deeply equal to `expected`. 2355 | * 2356 | * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); 2357 | * 2358 | * @name deepEqual 2359 | * @param {Mixed} actual 2360 | * @param {Mixed} expected 2361 | * @param {String} message 2362 | * @namespace Assert 2363 | * @api public 2364 | */ 2365 | 2366 | assert.deepEqual = function (act, exp, msg) { 2367 | new Assertion(act, msg).to.eql(exp); 2368 | }; 2369 | 2370 | /** 2371 | * ### .notDeepEqual(actual, expected, [message]) 2372 | * 2373 | * Assert that `actual` is not deeply equal to `expected`. 2374 | * 2375 | * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); 2376 | * 2377 | * @name notDeepEqual 2378 | * @param {Mixed} actual 2379 | * @param {Mixed} expected 2380 | * @param {String} message 2381 | * @namespace Assert 2382 | * @api public 2383 | */ 2384 | 2385 | assert.notDeepEqual = function (act, exp, msg) { 2386 | new Assertion(act, msg).to.not.eql(exp); 2387 | }; 2388 | 2389 | /** 2390 | * ### .isAbove(valueToCheck, valueToBeAbove, [message]) 2391 | * 2392 | * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove` 2393 | * 2394 | * assert.isAbove(5, 2, '5 is strictly greater than 2'); 2395 | * 2396 | * @name isAbove 2397 | * @param {Mixed} valueToCheck 2398 | * @param {Mixed} valueToBeAbove 2399 | * @param {String} message 2400 | * @namespace Assert 2401 | * @api public 2402 | */ 2403 | 2404 | assert.isAbove = function (val, abv, msg) { 2405 | new Assertion(val, msg).to.be.above(abv); 2406 | }; 2407 | 2408 | /** 2409 | * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message]) 2410 | * 2411 | * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast` 2412 | * 2413 | * assert.isAtLeast(5, 2, '5 is greater or equal to 2'); 2414 | * assert.isAtLeast(3, 3, '3 is greater or equal to 3'); 2415 | * 2416 | * @name isAtLeast 2417 | * @param {Mixed} valueToCheck 2418 | * @param {Mixed} valueToBeAtLeast 2419 | * @param {String} message 2420 | * @namespace Assert 2421 | * @api public 2422 | */ 2423 | 2424 | assert.isAtLeast = function (val, atlst, msg) { 2425 | new Assertion(val, msg).to.be.least(atlst); 2426 | }; 2427 | 2428 | /** 2429 | * ### .isBelow(valueToCheck, valueToBeBelow, [message]) 2430 | * 2431 | * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow` 2432 | * 2433 | * assert.isBelow(3, 6, '3 is strictly less than 6'); 2434 | * 2435 | * @name isBelow 2436 | * @param {Mixed} valueToCheck 2437 | * @param {Mixed} valueToBeBelow 2438 | * @param {String} message 2439 | * @namespace Assert 2440 | * @api public 2441 | */ 2442 | 2443 | assert.isBelow = function (val, blw, msg) { 2444 | new Assertion(val, msg).to.be.below(blw); 2445 | }; 2446 | 2447 | /** 2448 | * ### .isAtMost(valueToCheck, valueToBeAtMost, [message]) 2449 | * 2450 | * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost` 2451 | * 2452 | * assert.isAtMost(3, 6, '3 is less than or equal to 6'); 2453 | * assert.isAtMost(4, 4, '4 is less than or equal to 4'); 2454 | * 2455 | * @name isAtMost 2456 | * @param {Mixed} valueToCheck 2457 | * @param {Mixed} valueToBeAtMost 2458 | * @param {String} message 2459 | * @namespace Assert 2460 | * @api public 2461 | */ 2462 | 2463 | assert.isAtMost = function (val, atmst, msg) { 2464 | new Assertion(val, msg).to.be.most(atmst); 2465 | }; 2466 | 2467 | /** 2468 | * ### .isTrue(value, [message]) 2469 | * 2470 | * Asserts that `value` is true. 2471 | * 2472 | * var teaServed = true; 2473 | * assert.isTrue(teaServed, 'the tea has been served'); 2474 | * 2475 | * @name isTrue 2476 | * @param {Mixed} value 2477 | * @param {String} message 2478 | * @namespace Assert 2479 | * @api public 2480 | */ 2481 | 2482 | assert.isTrue = function (val, msg) { 2483 | new Assertion(val, msg).is['true']; 2484 | }; 2485 | 2486 | /** 2487 | * ### .isNotTrue(value, [message]) 2488 | * 2489 | * Asserts that `value` is not true. 2490 | * 2491 | * var tea = 'tasty chai'; 2492 | * assert.isNotTrue(tea, 'great, time for tea!'); 2493 | * 2494 | * @name isNotTrue 2495 | * @param {Mixed} value 2496 | * @param {String} message 2497 | * @namespace Assert 2498 | * @api public 2499 | */ 2500 | 2501 | assert.isNotTrue = function (val, msg) { 2502 | new Assertion(val, msg).to.not.equal(true); 2503 | }; 2504 | 2505 | /** 2506 | * ### .isFalse(value, [message]) 2507 | * 2508 | * Asserts that `value` is false. 2509 | * 2510 | * var teaServed = false; 2511 | * assert.isFalse(teaServed, 'no tea yet? hmm...'); 2512 | * 2513 | * @name isFalse 2514 | * @param {Mixed} value 2515 | * @param {String} message 2516 | * @namespace Assert 2517 | * @api public 2518 | */ 2519 | 2520 | assert.isFalse = function (val, msg) { 2521 | new Assertion(val, msg).is['false']; 2522 | }; 2523 | 2524 | /** 2525 | * ### .isNotFalse(value, [message]) 2526 | * 2527 | * Asserts that `value` is not false. 2528 | * 2529 | * var tea = 'tasty chai'; 2530 | * assert.isNotFalse(tea, 'great, time for tea!'); 2531 | * 2532 | * @name isNotFalse 2533 | * @param {Mixed} value 2534 | * @param {String} message 2535 | * @namespace Assert 2536 | * @api public 2537 | */ 2538 | 2539 | assert.isNotFalse = function (val, msg) { 2540 | new Assertion(val, msg).to.not.equal(false); 2541 | }; 2542 | 2543 | /** 2544 | * ### .isNull(value, [message]) 2545 | * 2546 | * Asserts that `value` is null. 2547 | * 2548 | * assert.isNull(err, 'there was no error'); 2549 | * 2550 | * @name isNull 2551 | * @param {Mixed} value 2552 | * @param {String} message 2553 | * @namespace Assert 2554 | * @api public 2555 | */ 2556 | 2557 | assert.isNull = function (val, msg) { 2558 | new Assertion(val, msg).to.equal(null); 2559 | }; 2560 | 2561 | /** 2562 | * ### .isNotNull(value, [message]) 2563 | * 2564 | * Asserts that `value` is not null. 2565 | * 2566 | * var tea = 'tasty chai'; 2567 | * assert.isNotNull(tea, 'great, time for tea!'); 2568 | * 2569 | * @name isNotNull 2570 | * @param {Mixed} value 2571 | * @param {String} message 2572 | * @namespace Assert 2573 | * @api public 2574 | */ 2575 | 2576 | assert.isNotNull = function (val, msg) { 2577 | new Assertion(val, msg).to.not.equal(null); 2578 | }; 2579 | 2580 | /** 2581 | * ### .isNaN 2582 | * Asserts that value is NaN 2583 | * 2584 | * assert.isNaN('foo', 'foo is NaN'); 2585 | * 2586 | * @name isNaN 2587 | * @param {Mixed} value 2588 | * @param {String} message 2589 | * @namespace Assert 2590 | * @api public 2591 | */ 2592 | 2593 | assert.isNaN = function (val, msg) { 2594 | new Assertion(val, msg).to.be.NaN; 2595 | }; 2596 | 2597 | /** 2598 | * ### .isNotNaN 2599 | * Asserts that value is not NaN 2600 | * 2601 | * assert.isNotNaN(4, '4 is not NaN'); 2602 | * 2603 | * @name isNotNaN 2604 | * @param {Mixed} value 2605 | * @param {String} message 2606 | * @namespace Assert 2607 | * @api public 2608 | */ 2609 | assert.isNotNaN = function (val, msg) { 2610 | new Assertion(val, msg).not.to.be.NaN; 2611 | }; 2612 | 2613 | /** 2614 | * ### .isUndefined(value, [message]) 2615 | * 2616 | * Asserts that `value` is `undefined`. 2617 | * 2618 | * var tea; 2619 | * assert.isUndefined(tea, 'no tea defined'); 2620 | * 2621 | * @name isUndefined 2622 | * @param {Mixed} value 2623 | * @param {String} message 2624 | * @namespace Assert 2625 | * @api public 2626 | */ 2627 | 2628 | assert.isUndefined = function (val, msg) { 2629 | new Assertion(val, msg).to.equal(undefined); 2630 | }; 2631 | 2632 | /** 2633 | * ### .isDefined(value, [message]) 2634 | * 2635 | * Asserts that `value` is not `undefined`. 2636 | * 2637 | * var tea = 'cup of chai'; 2638 | * assert.isDefined(tea, 'tea has been defined'); 2639 | * 2640 | * @name isDefined 2641 | * @param {Mixed} value 2642 | * @param {String} message 2643 | * @namespace Assert 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 | * @namespace Assert 2663 | * @api public 2664 | */ 2665 | 2666 | assert.isFunction = function (val, msg) { 2667 | new Assertion(val, msg).to.be.a('function'); 2668 | }; 2669 | 2670 | /** 2671 | * ### .isNotFunction(value, [message]) 2672 | * 2673 | * Asserts that `value` is _not_ a function. 2674 | * 2675 | * var serveTea = [ 'heat', 'pour', 'sip' ]; 2676 | * assert.isNotFunction(serveTea, 'great, we have listed the steps'); 2677 | * 2678 | * @name isNotFunction 2679 | * @param {Mixed} value 2680 | * @param {String} message 2681 | * @namespace Assert 2682 | * @api public 2683 | */ 2684 | 2685 | assert.isNotFunction = function (val, msg) { 2686 | new Assertion(val, msg).to.not.be.a('function'); 2687 | }; 2688 | 2689 | /** 2690 | * ### .isObject(value, [message]) 2691 | * 2692 | * Asserts that `value` is an object of type 'Object' (as revealed by `Object.prototype.toString`). 2693 | * _The assertion does not match subclassed objects._ 2694 | * 2695 | * var selection = { name: 'Chai', serve: 'with spices' }; 2696 | * assert.isObject(selection, 'tea selection is an object'); 2697 | * 2698 | * @name isObject 2699 | * @param {Mixed} value 2700 | * @param {String} message 2701 | * @namespace Assert 2702 | * @api public 2703 | */ 2704 | 2705 | assert.isObject = function (val, msg) { 2706 | new Assertion(val, msg).to.be.a('object'); 2707 | }; 2708 | 2709 | /** 2710 | * ### .isNotObject(value, [message]) 2711 | * 2712 | * Asserts that `value` is _not_ an object of type 'Object' (as revealed by `Object.prototype.toString`). 2713 | * 2714 | * var selection = 'chai' 2715 | * assert.isNotObject(selection, 'tea selection is not an object'); 2716 | * assert.isNotObject(null, 'null is not an object'); 2717 | * 2718 | * @name isNotObject 2719 | * @param {Mixed} value 2720 | * @param {String} message 2721 | * @namespace Assert 2722 | * @api public 2723 | */ 2724 | 2725 | assert.isNotObject = function (val, msg) { 2726 | new Assertion(val, msg).to.not.be.a('object'); 2727 | }; 2728 | 2729 | /** 2730 | * ### .isArray(value, [message]) 2731 | * 2732 | * Asserts that `value` is an array. 2733 | * 2734 | * var menu = [ 'green', 'chai', 'oolong' ]; 2735 | * assert.isArray(menu, 'what kind of tea do we want?'); 2736 | * 2737 | * @name isArray 2738 | * @param {Mixed} value 2739 | * @param {String} message 2740 | * @namespace Assert 2741 | * @api public 2742 | */ 2743 | 2744 | assert.isArray = function (val, msg) { 2745 | new Assertion(val, msg).to.be.an('array'); 2746 | }; 2747 | 2748 | /** 2749 | * ### .isNotArray(value, [message]) 2750 | * 2751 | * Asserts that `value` is _not_ an array. 2752 | * 2753 | * var menu = 'green|chai|oolong'; 2754 | * assert.isNotArray(menu, 'what kind of tea do we want?'); 2755 | * 2756 | * @name isNotArray 2757 | * @param {Mixed} value 2758 | * @param {String} message 2759 | * @namespace Assert 2760 | * @api public 2761 | */ 2762 | 2763 | assert.isNotArray = function (val, msg) { 2764 | new Assertion(val, msg).to.not.be.an('array'); 2765 | }; 2766 | 2767 | /** 2768 | * ### .isString(value, [message]) 2769 | * 2770 | * Asserts that `value` is a string. 2771 | * 2772 | * var teaOrder = 'chai'; 2773 | * assert.isString(teaOrder, 'order placed'); 2774 | * 2775 | * @name isString 2776 | * @param {Mixed} value 2777 | * @param {String} message 2778 | * @namespace Assert 2779 | * @api public 2780 | */ 2781 | 2782 | assert.isString = function (val, msg) { 2783 | new Assertion(val, msg).to.be.a('string'); 2784 | }; 2785 | 2786 | /** 2787 | * ### .isNotString(value, [message]) 2788 | * 2789 | * Asserts that `value` is _not_ a string. 2790 | * 2791 | * var teaOrder = 4; 2792 | * assert.isNotString(teaOrder, 'order placed'); 2793 | * 2794 | * @name isNotString 2795 | * @param {Mixed} value 2796 | * @param {String} message 2797 | * @namespace Assert 2798 | * @api public 2799 | */ 2800 | 2801 | assert.isNotString = function (val, msg) { 2802 | new Assertion(val, msg).to.not.be.a('string'); 2803 | }; 2804 | 2805 | /** 2806 | * ### .isNumber(value, [message]) 2807 | * 2808 | * Asserts that `value` is a number. 2809 | * 2810 | * var cups = 2; 2811 | * assert.isNumber(cups, 'how many cups'); 2812 | * 2813 | * @name isNumber 2814 | * @param {Number} value 2815 | * @param {String} message 2816 | * @namespace Assert 2817 | * @api public 2818 | */ 2819 | 2820 | assert.isNumber = function (val, msg) { 2821 | new Assertion(val, msg).to.be.a('number'); 2822 | }; 2823 | 2824 | /** 2825 | * ### .isNotNumber(value, [message]) 2826 | * 2827 | * Asserts that `value` is _not_ a number. 2828 | * 2829 | * var cups = '2 cups please'; 2830 | * assert.isNotNumber(cups, 'how many cups'); 2831 | * 2832 | * @name isNotNumber 2833 | * @param {Mixed} value 2834 | * @param {String} message 2835 | * @namespace Assert 2836 | * @api public 2837 | */ 2838 | 2839 | assert.isNotNumber = function (val, msg) { 2840 | new Assertion(val, msg).to.not.be.a('number'); 2841 | }; 2842 | 2843 | /** 2844 | * ### .isBoolean(value, [message]) 2845 | * 2846 | * Asserts that `value` is a boolean. 2847 | * 2848 | * var teaReady = true 2849 | * , teaServed = false; 2850 | * 2851 | * assert.isBoolean(teaReady, 'is the tea ready'); 2852 | * assert.isBoolean(teaServed, 'has tea been served'); 2853 | * 2854 | * @name isBoolean 2855 | * @param {Mixed} value 2856 | * @param {String} message 2857 | * @namespace Assert 2858 | * @api public 2859 | */ 2860 | 2861 | assert.isBoolean = function (val, msg) { 2862 | new Assertion(val, msg).to.be.a('boolean'); 2863 | }; 2864 | 2865 | /** 2866 | * ### .isNotBoolean(value, [message]) 2867 | * 2868 | * Asserts that `value` is _not_ a boolean. 2869 | * 2870 | * var teaReady = 'yep' 2871 | * , teaServed = 'nope'; 2872 | * 2873 | * assert.isNotBoolean(teaReady, 'is the tea ready'); 2874 | * assert.isNotBoolean(teaServed, 'has tea been served'); 2875 | * 2876 | * @name isNotBoolean 2877 | * @param {Mixed} value 2878 | * @param {String} message 2879 | * @namespace Assert 2880 | * @api public 2881 | */ 2882 | 2883 | assert.isNotBoolean = function (val, msg) { 2884 | new Assertion(val, msg).to.not.be.a('boolean'); 2885 | }; 2886 | 2887 | /** 2888 | * ### .typeOf(value, name, [message]) 2889 | * 2890 | * Asserts that `value`'s type is `name`, as determined by 2891 | * `Object.prototype.toString`. 2892 | * 2893 | * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); 2894 | * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); 2895 | * assert.typeOf('tea', 'string', 'we have a string'); 2896 | * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); 2897 | * assert.typeOf(null, 'null', 'we have a null'); 2898 | * assert.typeOf(undefined, 'undefined', 'we have an undefined'); 2899 | * 2900 | * @name typeOf 2901 | * @param {Mixed} value 2902 | * @param {String} name 2903 | * @param {String} message 2904 | * @namespace Assert 2905 | * @api public 2906 | */ 2907 | 2908 | assert.typeOf = function (val, type, msg) { 2909 | new Assertion(val, msg).to.be.a(type); 2910 | }; 2911 | 2912 | /** 2913 | * ### .notTypeOf(value, name, [message]) 2914 | * 2915 | * Asserts that `value`'s type is _not_ `name`, as determined by 2916 | * `Object.prototype.toString`. 2917 | * 2918 | * assert.notTypeOf('tea', 'number', 'strings are not numbers'); 2919 | * 2920 | * @name notTypeOf 2921 | * @param {Mixed} value 2922 | * @param {String} typeof name 2923 | * @param {String} message 2924 | * @namespace Assert 2925 | * @api public 2926 | */ 2927 | 2928 | assert.notTypeOf = function (val, type, msg) { 2929 | new Assertion(val, msg).to.not.be.a(type); 2930 | }; 2931 | 2932 | /** 2933 | * ### .instanceOf(object, constructor, [message]) 2934 | * 2935 | * Asserts that `value` is an instance of `constructor`. 2936 | * 2937 | * var Tea = function (name) { this.name = name; } 2938 | * , chai = new Tea('chai'); 2939 | * 2940 | * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); 2941 | * 2942 | * @name instanceOf 2943 | * @param {Object} object 2944 | * @param {Constructor} constructor 2945 | * @param {String} message 2946 | * @namespace Assert 2947 | * @api public 2948 | */ 2949 | 2950 | assert.instanceOf = function (val, type, msg) { 2951 | new Assertion(val, msg).to.be.instanceOf(type); 2952 | }; 2953 | 2954 | /** 2955 | * ### .notInstanceOf(object, constructor, [message]) 2956 | * 2957 | * Asserts `value` is not an instance of `constructor`. 2958 | * 2959 | * var Tea = function (name) { this.name = name; } 2960 | * , chai = new String('chai'); 2961 | * 2962 | * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); 2963 | * 2964 | * @name notInstanceOf 2965 | * @param {Object} object 2966 | * @param {Constructor} constructor 2967 | * @param {String} message 2968 | * @namespace Assert 2969 | * @api public 2970 | */ 2971 | 2972 | assert.notInstanceOf = function (val, type, msg) { 2973 | new Assertion(val, msg).to.not.be.instanceOf(type); 2974 | }; 2975 | 2976 | /** 2977 | * ### .include(haystack, needle, [message]) 2978 | * 2979 | * Asserts that `haystack` includes `needle`. Works 2980 | * for strings and arrays. 2981 | * 2982 | * assert.include('foobar', 'bar', 'foobar contains string "bar"'); 2983 | * assert.include([ 1, 2, 3 ], 3, 'array contains value'); 2984 | * 2985 | * @name include 2986 | * @param {Array|String} haystack 2987 | * @param {Mixed} needle 2988 | * @param {String} message 2989 | * @namespace Assert 2990 | * @api public 2991 | */ 2992 | 2993 | assert.include = function (exp, inc, msg) { 2994 | new Assertion(exp, msg, assert.include).include(inc); 2995 | }; 2996 | 2997 | /** 2998 | * ### .notInclude(haystack, needle, [message]) 2999 | * 3000 | * Asserts that `haystack` does not include `needle`. Works 3001 | * for strings and arrays. 3002 | * 3003 | * assert.notInclude('foobar', 'baz', 'string not include substring'); 3004 | * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); 3005 | * 3006 | * @name notInclude 3007 | * @param {Array|String} haystack 3008 | * @param {Mixed} needle 3009 | * @param {String} message 3010 | * @namespace Assert 3011 | * @api public 3012 | */ 3013 | 3014 | assert.notInclude = function (exp, inc, msg) { 3015 | new Assertion(exp, msg, assert.notInclude).not.include(inc); 3016 | }; 3017 | 3018 | /** 3019 | * ### .match(value, regexp, [message]) 3020 | * 3021 | * Asserts that `value` matches the regular expression `regexp`. 3022 | * 3023 | * assert.match('foobar', /^foo/, 'regexp matches'); 3024 | * 3025 | * @name match 3026 | * @param {Mixed} value 3027 | * @param {RegExp} regexp 3028 | * @param {String} message 3029 | * @namespace Assert 3030 | * @api public 3031 | */ 3032 | 3033 | assert.match = function (exp, re, msg) { 3034 | new Assertion(exp, msg).to.match(re); 3035 | }; 3036 | 3037 | /** 3038 | * ### .notMatch(value, regexp, [message]) 3039 | * 3040 | * Asserts that `value` does not match the regular expression `regexp`. 3041 | * 3042 | * assert.notMatch('foobar', /^foo/, 'regexp does not match'); 3043 | * 3044 | * @name notMatch 3045 | * @param {Mixed} value 3046 | * @param {RegExp} regexp 3047 | * @param {String} message 3048 | * @namespace Assert 3049 | * @api public 3050 | */ 3051 | 3052 | assert.notMatch = function (exp, re, msg) { 3053 | new Assertion(exp, msg).to.not.match(re); 3054 | }; 3055 | 3056 | /** 3057 | * ### .property(object, property, [message]) 3058 | * 3059 | * Asserts that `object` has a property named by `property`. 3060 | * 3061 | * assert.property({ tea: { green: 'matcha' }}, 'tea'); 3062 | * 3063 | * @name property 3064 | * @param {Object} object 3065 | * @param {String} property 3066 | * @param {String} message 3067 | * @namespace Assert 3068 | * @api public 3069 | */ 3070 | 3071 | assert.property = function (obj, prop, msg) { 3072 | new Assertion(obj, msg).to.have.property(prop); 3073 | }; 3074 | 3075 | /** 3076 | * ### .notProperty(object, property, [message]) 3077 | * 3078 | * Asserts that `object` does _not_ have a property named by `property`. 3079 | * 3080 | * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); 3081 | * 3082 | * @name notProperty 3083 | * @param {Object} object 3084 | * @param {String} property 3085 | * @param {String} message 3086 | * @namespace Assert 3087 | * @api public 3088 | */ 3089 | 3090 | assert.notProperty = function (obj, prop, msg) { 3091 | new Assertion(obj, msg).to.not.have.property(prop); 3092 | }; 3093 | 3094 | /** 3095 | * ### .deepProperty(object, property, [message]) 3096 | * 3097 | * Asserts that `object` has a property named by `property`, which can be a 3098 | * string using dot- and bracket-notation for deep reference. 3099 | * 3100 | * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); 3101 | * 3102 | * @name deepProperty 3103 | * @param {Object} object 3104 | * @param {String} property 3105 | * @param {String} message 3106 | * @namespace Assert 3107 | * @api public 3108 | */ 3109 | 3110 | assert.deepProperty = function (obj, prop, msg) { 3111 | new Assertion(obj, msg).to.have.deep.property(prop); 3112 | }; 3113 | 3114 | /** 3115 | * ### .notDeepProperty(object, property, [message]) 3116 | * 3117 | * Asserts that `object` does _not_ have a property named by `property`, which 3118 | * can be a string using dot- and bracket-notation for deep reference. 3119 | * 3120 | * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); 3121 | * 3122 | * @name notDeepProperty 3123 | * @param {Object} object 3124 | * @param {String} property 3125 | * @param {String} message 3126 | * @namespace Assert 3127 | * @api public 3128 | */ 3129 | 3130 | assert.notDeepProperty = function (obj, prop, msg) { 3131 | new Assertion(obj, msg).to.not.have.deep.property(prop); 3132 | }; 3133 | 3134 | /** 3135 | * ### .propertyVal(object, property, value, [message]) 3136 | * 3137 | * Asserts that `object` has a property named by `property` with value given 3138 | * by `value`. 3139 | * 3140 | * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); 3141 | * 3142 | * @name propertyVal 3143 | * @param {Object} object 3144 | * @param {String} property 3145 | * @param {Mixed} value 3146 | * @param {String} message 3147 | * @namespace Assert 3148 | * @api public 3149 | */ 3150 | 3151 | assert.propertyVal = function (obj, prop, val, msg) { 3152 | new Assertion(obj, msg).to.have.property(prop, val); 3153 | }; 3154 | 3155 | /** 3156 | * ### .propertyNotVal(object, property, value, [message]) 3157 | * 3158 | * Asserts that `object` has a property named by `property`, but with a value 3159 | * different from that given by `value`. 3160 | * 3161 | * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); 3162 | * 3163 | * @name propertyNotVal 3164 | * @param {Object} object 3165 | * @param {String} property 3166 | * @param {Mixed} value 3167 | * @param {String} message 3168 | * @namespace Assert 3169 | * @api public 3170 | */ 3171 | 3172 | assert.propertyNotVal = function (obj, prop, val, msg) { 3173 | new Assertion(obj, msg).to.not.have.property(prop, val); 3174 | }; 3175 | 3176 | /** 3177 | * ### .deepPropertyVal(object, property, value, [message]) 3178 | * 3179 | * Asserts that `object` has a property named by `property` with value given 3180 | * by `value`. `property` can use dot- and bracket-notation for deep 3181 | * reference. 3182 | * 3183 | * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); 3184 | * 3185 | * @name deepPropertyVal 3186 | * @param {Object} object 3187 | * @param {String} property 3188 | * @param {Mixed} value 3189 | * @param {String} message 3190 | * @namespace Assert 3191 | * @api public 3192 | */ 3193 | 3194 | assert.deepPropertyVal = function (obj, prop, val, msg) { 3195 | new Assertion(obj, msg).to.have.deep.property(prop, val); 3196 | }; 3197 | 3198 | /** 3199 | * ### .deepPropertyNotVal(object, property, value, [message]) 3200 | * 3201 | * Asserts that `object` has a property named by `property`, but with a value 3202 | * different from that given by `value`. `property` can use dot- and 3203 | * bracket-notation for deep reference. 3204 | * 3205 | * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); 3206 | * 3207 | * @name deepPropertyNotVal 3208 | * @param {Object} object 3209 | * @param {String} property 3210 | * @param {Mixed} value 3211 | * @param {String} message 3212 | * @namespace Assert 3213 | * @api public 3214 | */ 3215 | 3216 | assert.deepPropertyNotVal = function (obj, prop, val, msg) { 3217 | new Assertion(obj, msg).to.not.have.deep.property(prop, val); 3218 | }; 3219 | 3220 | /** 3221 | * ### .lengthOf(object, length, [message]) 3222 | * 3223 | * Asserts that `object` has a `length` property with the expected value. 3224 | * 3225 | * assert.lengthOf([1,2,3], 3, 'array has length of 3'); 3226 | * assert.lengthOf('foobar', 6, 'string has length of 6'); 3227 | * 3228 | * @name lengthOf 3229 | * @param {Mixed} object 3230 | * @param {Number} length 3231 | * @param {String} message 3232 | * @namespace Assert 3233 | * @api public 3234 | */ 3235 | 3236 | assert.lengthOf = function (exp, len, msg) { 3237 | new Assertion(exp, msg).to.have.length(len); 3238 | }; 3239 | 3240 | /** 3241 | * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) 3242 | * 3243 | * Asserts that `function` will throw an error that is an instance of 3244 | * `constructor`, or alternately that it will throw an error with message 3245 | * matching `regexp`. 3246 | * 3247 | * assert.throws(fn, 'function throws a reference error'); 3248 | * assert.throws(fn, /function throws a reference error/); 3249 | * assert.throws(fn, ReferenceError); 3250 | * assert.throws(fn, ReferenceError, 'function throws a reference error'); 3251 | * assert.throws(fn, ReferenceError, /function throws a reference error/); 3252 | * 3253 | * @name throws 3254 | * @alias throw 3255 | * @alias Throw 3256 | * @param {Function} function 3257 | * @param {ErrorConstructor} constructor 3258 | * @param {RegExp} regexp 3259 | * @param {String} message 3260 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3261 | * @namespace Assert 3262 | * @api public 3263 | */ 3264 | 3265 | assert.throws = function (fn, errt, errs, msg) { 3266 | if ('string' === typeof errt || errt instanceof RegExp) { 3267 | errs = errt; 3268 | errt = null; 3269 | } 3270 | 3271 | var assertErr = new Assertion(fn, msg).to.throw(errt, errs); 3272 | return flag(assertErr, 'object'); 3273 | }; 3274 | 3275 | /** 3276 | * ### .doesNotThrow(function, [constructor/regexp], [message]) 3277 | * 3278 | * Asserts that `function` will _not_ throw an error that is an instance of 3279 | * `constructor`, or alternately that it will not throw an error with message 3280 | * matching `regexp`. 3281 | * 3282 | * assert.doesNotThrow(fn, Error, 'function does not throw'); 3283 | * 3284 | * @name doesNotThrow 3285 | * @param {Function} function 3286 | * @param {ErrorConstructor} constructor 3287 | * @param {RegExp} regexp 3288 | * @param {String} message 3289 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3290 | * @namespace Assert 3291 | * @api public 3292 | */ 3293 | 3294 | assert.doesNotThrow = function (fn, type, msg) { 3295 | if ('string' === typeof type) { 3296 | msg = type; 3297 | type = null; 3298 | } 3299 | 3300 | new Assertion(fn, msg).to.not.Throw(type); 3301 | }; 3302 | 3303 | /** 3304 | * ### .operator(val1, operator, val2, [message]) 3305 | * 3306 | * Compares two values using `operator`. 3307 | * 3308 | * assert.operator(1, '<', 2, 'everything is ok'); 3309 | * assert.operator(1, '>', 2, 'this will fail'); 3310 | * 3311 | * @name operator 3312 | * @param {Mixed} val1 3313 | * @param {String} operator 3314 | * @param {Mixed} val2 3315 | * @param {String} message 3316 | * @namespace Assert 3317 | * @api public 3318 | */ 3319 | 3320 | assert.operator = function (val, operator, val2, msg) { 3321 | var ok; 3322 | switch(operator) { 3323 | case '==': 3324 | ok = val == val2; 3325 | break; 3326 | case '===': 3327 | ok = val === val2; 3328 | break; 3329 | case '>': 3330 | ok = val > val2; 3331 | break; 3332 | case '>=': 3333 | ok = val >= val2; 3334 | break; 3335 | case '<': 3336 | ok = val < val2; 3337 | break; 3338 | case '<=': 3339 | ok = val <= val2; 3340 | break; 3341 | case '!=': 3342 | ok = val != val2; 3343 | break; 3344 | case '!==': 3345 | ok = val !== val2; 3346 | break; 3347 | default: 3348 | throw new Error('Invalid operator "' + operator + '"'); 3349 | } 3350 | var test = new Assertion(ok, msg); 3351 | test.assert( 3352 | true === flag(test, 'object') 3353 | , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) 3354 | , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); 3355 | }; 3356 | 3357 | /** 3358 | * ### .closeTo(actual, expected, delta, [message]) 3359 | * 3360 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 3361 | * 3362 | * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); 3363 | * 3364 | * @name closeTo 3365 | * @param {Number} actual 3366 | * @param {Number} expected 3367 | * @param {Number} delta 3368 | * @param {String} message 3369 | * @namespace Assert 3370 | * @api public 3371 | */ 3372 | 3373 | assert.closeTo = function (act, exp, delta, msg) { 3374 | new Assertion(act, msg).to.be.closeTo(exp, delta); 3375 | }; 3376 | 3377 | /** 3378 | * ### .approximately(actual, expected, delta, [message]) 3379 | * 3380 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 3381 | * 3382 | * assert.approximately(1.5, 1, 0.5, 'numbers are close'); 3383 | * 3384 | * @name approximately 3385 | * @param {Number} actual 3386 | * @param {Number} expected 3387 | * @param {Number} delta 3388 | * @param {String} message 3389 | * @namespace Assert 3390 | * @api public 3391 | */ 3392 | 3393 | assert.approximately = function (act, exp, delta, msg) { 3394 | new Assertion(act, msg).to.be.approximately(exp, delta); 3395 | }; 3396 | 3397 | /** 3398 | * ### .sameMembers(set1, set2, [message]) 3399 | * 3400 | * Asserts that `set1` and `set2` have the same members. 3401 | * Order is not taken into account. 3402 | * 3403 | * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); 3404 | * 3405 | * @name sameMembers 3406 | * @param {Array} set1 3407 | * @param {Array} set2 3408 | * @param {String} message 3409 | * @namespace Assert 3410 | * @api public 3411 | */ 3412 | 3413 | assert.sameMembers = function (set1, set2, msg) { 3414 | new Assertion(set1, msg).to.have.same.members(set2); 3415 | } 3416 | 3417 | /** 3418 | * ### .sameDeepMembers(set1, set2, [message]) 3419 | * 3420 | * Asserts that `set1` and `set2` have the same members - using a deep equality checking. 3421 | * Order is not taken into account. 3422 | * 3423 | * assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members'); 3424 | * 3425 | * @name sameDeepMembers 3426 | * @param {Array} set1 3427 | * @param {Array} set2 3428 | * @param {String} message 3429 | * @namespace Assert 3430 | * @api public 3431 | */ 3432 | 3433 | assert.sameDeepMembers = function (set1, set2, msg) { 3434 | new Assertion(set1, msg).to.have.same.deep.members(set2); 3435 | } 3436 | 3437 | /** 3438 | * ### .includeMembers(superset, subset, [message]) 3439 | * 3440 | * Asserts that `subset` is included in `superset`. 3441 | * Order is not taken into account. 3442 | * 3443 | * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); 3444 | * 3445 | * @name includeMembers 3446 | * @param {Array} superset 3447 | * @param {Array} subset 3448 | * @param {String} message 3449 | * @namespace Assert 3450 | * @api public 3451 | */ 3452 | 3453 | assert.includeMembers = function (superset, subset, msg) { 3454 | new Assertion(superset, msg).to.include.members(subset); 3455 | } 3456 | 3457 | /** 3458 | * ### .includeDeepMembers(superset, subset, [message]) 3459 | * 3460 | * Asserts that `subset` is included in `superset` - using deep equality checking. 3461 | * Order is not taken into account. 3462 | * Duplicates are ignored. 3463 | * 3464 | * assert.includeDeepMembers([ {a: 1}, {b: 2}, {c: 3} ], [ {b: 2}, {a: 1}, {b: 2} ], 'include deep members'); 3465 | * 3466 | * @name includeDeepMembers 3467 | * @param {Array} superset 3468 | * @param {Array} subset 3469 | * @param {String} message 3470 | * @namespace Assert 3471 | * @api public 3472 | */ 3473 | 3474 | assert.includeDeepMembers = function (superset, subset, msg) { 3475 | new Assertion(superset, msg).to.include.deep.members(subset); 3476 | } 3477 | 3478 | /** 3479 | * ### .oneOf(inList, list, [message]) 3480 | * 3481 | * Asserts that non-object, non-array value `inList` appears in the flat array `list`. 3482 | * 3483 | * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); 3484 | * 3485 | * @name oneOf 3486 | * @param {*} inList 3487 | * @param {Array<*>} list 3488 | * @param {String} message 3489 | * @namespace Assert 3490 | * @api public 3491 | */ 3492 | 3493 | assert.oneOf = function (inList, list, msg) { 3494 | new Assertion(inList, msg).to.be.oneOf(list); 3495 | } 3496 | 3497 | /** 3498 | * ### .changes(function, object, property) 3499 | * 3500 | * Asserts that a function changes the value of a property 3501 | * 3502 | * var obj = { val: 10 }; 3503 | * var fn = function() { obj.val = 22 }; 3504 | * assert.changes(fn, obj, 'val'); 3505 | * 3506 | * @name changes 3507 | * @param {Function} modifier function 3508 | * @param {Object} object 3509 | * @param {String} property name 3510 | * @param {String} message _optional_ 3511 | * @namespace Assert 3512 | * @api public 3513 | */ 3514 | 3515 | assert.changes = function (fn, obj, prop) { 3516 | new Assertion(fn).to.change(obj, prop); 3517 | } 3518 | 3519 | /** 3520 | * ### .doesNotChange(function, object, property) 3521 | * 3522 | * Asserts that a function does not changes the value of a property 3523 | * 3524 | * var obj = { val: 10 }; 3525 | * var fn = function() { console.log('foo'); }; 3526 | * assert.doesNotChange(fn, obj, 'val'); 3527 | * 3528 | * @name doesNotChange 3529 | * @param {Function} modifier function 3530 | * @param {Object} object 3531 | * @param {String} property name 3532 | * @param {String} message _optional_ 3533 | * @namespace Assert 3534 | * @api public 3535 | */ 3536 | 3537 | assert.doesNotChange = function (fn, obj, prop) { 3538 | new Assertion(fn).to.not.change(obj, prop); 3539 | } 3540 | 3541 | /** 3542 | * ### .increases(function, object, property) 3543 | * 3544 | * Asserts that a function increases an object property 3545 | * 3546 | * var obj = { val: 10 }; 3547 | * var fn = function() { obj.val = 13 }; 3548 | * assert.increases(fn, obj, 'val'); 3549 | * 3550 | * @name increases 3551 | * @param {Function} modifier function 3552 | * @param {Object} object 3553 | * @param {String} property name 3554 | * @param {String} message _optional_ 3555 | * @namespace Assert 3556 | * @api public 3557 | */ 3558 | 3559 | assert.increases = function (fn, obj, prop) { 3560 | new Assertion(fn).to.increase(obj, prop); 3561 | } 3562 | 3563 | /** 3564 | * ### .doesNotIncrease(function, object, property) 3565 | * 3566 | * Asserts that a function does not increase object property 3567 | * 3568 | * var obj = { val: 10 }; 3569 | * var fn = function() { obj.val = 8 }; 3570 | * assert.doesNotIncrease(fn, obj, 'val'); 3571 | * 3572 | * @name doesNotIncrease 3573 | * @param {Function} modifier function 3574 | * @param {Object} object 3575 | * @param {String} property name 3576 | * @param {String} message _optional_ 3577 | * @namespace Assert 3578 | * @api public 3579 | */ 3580 | 3581 | assert.doesNotIncrease = function (fn, obj, prop) { 3582 | new Assertion(fn).to.not.increase(obj, prop); 3583 | } 3584 | 3585 | /** 3586 | * ### .decreases(function, object, property) 3587 | * 3588 | * Asserts that a function decreases an object property 3589 | * 3590 | * var obj = { val: 10 }; 3591 | * var fn = function() { obj.val = 5 }; 3592 | * assert.decreases(fn, obj, 'val'); 3593 | * 3594 | * @name decreases 3595 | * @param {Function} modifier function 3596 | * @param {Object} object 3597 | * @param {String} property name 3598 | * @param {String} message _optional_ 3599 | * @namespace Assert 3600 | * @api public 3601 | */ 3602 | 3603 | assert.decreases = function (fn, obj, prop) { 3604 | new Assertion(fn).to.decrease(obj, prop); 3605 | } 3606 | 3607 | /** 3608 | * ### .doesNotDecrease(function, object, property) 3609 | * 3610 | * Asserts that a function does not decreases an object property 3611 | * 3612 | * var obj = { val: 10 }; 3613 | * var fn = function() { obj.val = 15 }; 3614 | * assert.doesNotDecrease(fn, obj, 'val'); 3615 | * 3616 | * @name doesNotDecrease 3617 | * @param {Function} modifier function 3618 | * @param {Object} object 3619 | * @param {String} property name 3620 | * @param {String} message _optional_ 3621 | * @namespace Assert 3622 | * @api public 3623 | */ 3624 | 3625 | assert.doesNotDecrease = function (fn, obj, prop) { 3626 | new Assertion(fn).to.not.decrease(obj, prop); 3627 | } 3628 | 3629 | /*! 3630 | * ### .ifError(object) 3631 | * 3632 | * Asserts if value is not a false value, and throws if it is a true value. 3633 | * This is added to allow for chai to be a drop-in replacement for Node's 3634 | * assert class. 3635 | * 3636 | * var err = new Error('I am a custom error'); 3637 | * assert.ifError(err); // Rethrows err! 3638 | * 3639 | * @name ifError 3640 | * @param {Object} object 3641 | * @namespace Assert 3642 | * @api public 3643 | */ 3644 | 3645 | assert.ifError = function (val) { 3646 | if (val) { 3647 | throw(val); 3648 | } 3649 | }; 3650 | 3651 | /** 3652 | * ### .isExtensible(object) 3653 | * 3654 | * Asserts that `object` is extensible (can have new properties added to it). 3655 | * 3656 | * assert.isExtensible({}); 3657 | * 3658 | * @name isExtensible 3659 | * @alias extensible 3660 | * @param {Object} object 3661 | * @param {String} message _optional_ 3662 | * @namespace Assert 3663 | * @api public 3664 | */ 3665 | 3666 | assert.isExtensible = function (obj, msg) { 3667 | new Assertion(obj, msg).to.be.extensible; 3668 | }; 3669 | 3670 | /** 3671 | * ### .isNotExtensible(object) 3672 | * 3673 | * Asserts that `object` is _not_ extensible. 3674 | * 3675 | * var nonExtensibleObject = Object.preventExtensions({}); 3676 | * var sealedObject = Object.seal({}); 3677 | * var frozenObject = Object.freese({}); 3678 | * 3679 | * assert.isNotExtensible(nonExtensibleObject); 3680 | * assert.isNotExtensible(sealedObject); 3681 | * assert.isNotExtensible(frozenObject); 3682 | * 3683 | * @name isNotExtensible 3684 | * @alias notExtensible 3685 | * @param {Object} object 3686 | * @param {String} message _optional_ 3687 | * @namespace Assert 3688 | * @api public 3689 | */ 3690 | 3691 | assert.isNotExtensible = function (obj, msg) { 3692 | new Assertion(obj, msg).to.not.be.extensible; 3693 | }; 3694 | 3695 | /** 3696 | * ### .isSealed(object) 3697 | * 3698 | * Asserts that `object` is sealed (cannot have new properties added to it 3699 | * and its existing properties cannot be removed). 3700 | * 3701 | * var sealedObject = Object.seal({}); 3702 | * var frozenObject = Object.seal({}); 3703 | * 3704 | * assert.isSealed(sealedObject); 3705 | * assert.isSealed(frozenObject); 3706 | * 3707 | * @name isSealed 3708 | * @alias sealed 3709 | * @param {Object} object 3710 | * @param {String} message _optional_ 3711 | * @namespace Assert 3712 | * @api public 3713 | */ 3714 | 3715 | assert.isSealed = function (obj, msg) { 3716 | new Assertion(obj, msg).to.be.sealed; 3717 | }; 3718 | 3719 | /** 3720 | * ### .isNotSealed(object) 3721 | * 3722 | * Asserts that `object` is _not_ sealed. 3723 | * 3724 | * assert.isNotSealed({}); 3725 | * 3726 | * @name isNotSealed 3727 | * @alias notSealed 3728 | * @param {Object} object 3729 | * @param {String} message _optional_ 3730 | * @namespace Assert 3731 | * @api public 3732 | */ 3733 | 3734 | assert.isNotSealed = function (obj, msg) { 3735 | new Assertion(obj, msg).to.not.be.sealed; 3736 | }; 3737 | 3738 | /** 3739 | * ### .isFrozen(object) 3740 | * 3741 | * Asserts that `object` is frozen (cannot have new properties added to it 3742 | * and its existing properties cannot be modified). 3743 | * 3744 | * var frozenObject = Object.freeze({}); 3745 | * assert.frozen(frozenObject); 3746 | * 3747 | * @name isFrozen 3748 | * @alias frozen 3749 | * @param {Object} object 3750 | * @param {String} message _optional_ 3751 | * @namespace Assert 3752 | * @api public 3753 | */ 3754 | 3755 | assert.isFrozen = function (obj, msg) { 3756 | new Assertion(obj, msg).to.be.frozen; 3757 | }; 3758 | 3759 | /** 3760 | * ### .isNotFrozen(object) 3761 | * 3762 | * Asserts that `object` is _not_ frozen. 3763 | * 3764 | * assert.isNotFrozen({}); 3765 | * 3766 | * @name isNotFrozen 3767 | * @alias notFrozen 3768 | * @param {Object} object 3769 | * @param {String} message _optional_ 3770 | * @namespace Assert 3771 | * @api public 3772 | */ 3773 | 3774 | assert.isNotFrozen = function (obj, msg) { 3775 | new Assertion(obj, msg).to.not.be.frozen; 3776 | }; 3777 | 3778 | /*! 3779 | * Aliases. 3780 | */ 3781 | 3782 | (function alias(name, as){ 3783 | assert[as] = assert[name]; 3784 | return alias; 3785 | }) 3786 | ('isOk', 'ok') 3787 | ('isNotOk', 'notOk') 3788 | ('throws', 'throw') 3789 | ('throws', 'Throw') 3790 | ('isExtensible', 'extensible') 3791 | ('isNotExtensible', 'notExtensible') 3792 | ('isSealed', 'sealed') 3793 | ('isNotSealed', 'notSealed') 3794 | ('isFrozen', 'frozen') 3795 | ('isNotFrozen', 'notFrozen'); 3796 | }; 3797 | 3798 | },{}],7:[function(require,module,exports){ 3799 | /*! 3800 | * chai 3801 | * Copyright(c) 2011-2014 Jake Luer 3802 | * MIT Licensed 3803 | */ 3804 | 3805 | module.exports = function (chai, util) { 3806 | chai.expect = function (val, message) { 3807 | return new chai.Assertion(val, message); 3808 | }; 3809 | 3810 | /** 3811 | * ### .fail(actual, expected, [message], [operator]) 3812 | * 3813 | * Throw a failure. 3814 | * 3815 | * @name fail 3816 | * @param {Mixed} actual 3817 | * @param {Mixed} expected 3818 | * @param {String} message 3819 | * @param {String} operator 3820 | * @namespace Expect 3821 | * @api public 3822 | */ 3823 | 3824 | chai.expect.fail = function (actual, expected, message, operator) { 3825 | message = message || 'expect.fail()'; 3826 | throw new chai.AssertionError(message, { 3827 | actual: actual 3828 | , expected: expected 3829 | , operator: operator 3830 | }, chai.expect.fail); 3831 | }; 3832 | }; 3833 | 3834 | },{}],8:[function(require,module,exports){ 3835 | /*! 3836 | * chai 3837 | * Copyright(c) 2011-2014 Jake Luer 3838 | * MIT Licensed 3839 | */ 3840 | 3841 | module.exports = function (chai, util) { 3842 | var Assertion = chai.Assertion; 3843 | 3844 | function loadShould () { 3845 | // explicitly define this method as function as to have it's name to include as `ssfi` 3846 | function shouldGetter() { 3847 | if (this instanceof String || this instanceof Number || this instanceof Boolean ) { 3848 | return new Assertion(this.valueOf(), null, shouldGetter); 3849 | } 3850 | return new Assertion(this, null, shouldGetter); 3851 | } 3852 | function shouldSetter(value) { 3853 | // See https://github.com/chaijs/chai/issues/86: this makes 3854 | // `whatever.should = someValue` actually set `someValue`, which is 3855 | // especially useful for `global.should = require('chai').should()`. 3856 | // 3857 | // Note that we have to use [[DefineProperty]] instead of [[Put]] 3858 | // since otherwise we would trigger this very setter! 3859 | Object.defineProperty(this, 'should', { 3860 | value: value, 3861 | enumerable: true, 3862 | configurable: true, 3863 | writable: true 3864 | }); 3865 | } 3866 | // modify Object.prototype to have `should` 3867 | Object.defineProperty(Object.prototype, 'should', { 3868 | set: shouldSetter 3869 | , get: shouldGetter 3870 | , configurable: true 3871 | }); 3872 | 3873 | var should = {}; 3874 | 3875 | /** 3876 | * ### .fail(actual, expected, [message], [operator]) 3877 | * 3878 | * Throw a failure. 3879 | * 3880 | * @name fail 3881 | * @param {Mixed} actual 3882 | * @param {Mixed} expected 3883 | * @param {String} message 3884 | * @param {String} operator 3885 | * @namespace Should 3886 | * @api public 3887 | */ 3888 | 3889 | should.fail = function (actual, expected, message, operator) { 3890 | message = message || 'should.fail()'; 3891 | throw new chai.AssertionError(message, { 3892 | actual: actual 3893 | , expected: expected 3894 | , operator: operator 3895 | }, should.fail); 3896 | }; 3897 | 3898 | /** 3899 | * ### .equal(actual, expected, [message]) 3900 | * 3901 | * Asserts non-strict equality (`==`) of `actual` and `expected`. 3902 | * 3903 | * should.equal(3, '3', '== coerces values to strings'); 3904 | * 3905 | * @name equal 3906 | * @param {Mixed} actual 3907 | * @param {Mixed} expected 3908 | * @param {String} message 3909 | * @namespace Should 3910 | * @api public 3911 | */ 3912 | 3913 | should.equal = function (val1, val2, msg) { 3914 | new Assertion(val1, msg).to.equal(val2); 3915 | }; 3916 | 3917 | /** 3918 | * ### .throw(function, [constructor/string/regexp], [string/regexp], [message]) 3919 | * 3920 | * Asserts that `function` will throw an error that is an instance of 3921 | * `constructor`, or alternately that it will throw an error with message 3922 | * matching `regexp`. 3923 | * 3924 | * should.throw(fn, 'function throws a reference error'); 3925 | * should.throw(fn, /function throws a reference error/); 3926 | * should.throw(fn, ReferenceError); 3927 | * should.throw(fn, ReferenceError, 'function throws a reference error'); 3928 | * should.throw(fn, ReferenceError, /function throws a reference error/); 3929 | * 3930 | * @name throw 3931 | * @alias Throw 3932 | * @param {Function} function 3933 | * @param {ErrorConstructor} constructor 3934 | * @param {RegExp} regexp 3935 | * @param {String} message 3936 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3937 | * @namespace Should 3938 | * @api public 3939 | */ 3940 | 3941 | should.Throw = function (fn, errt, errs, msg) { 3942 | new Assertion(fn, msg).to.Throw(errt, errs); 3943 | }; 3944 | 3945 | /** 3946 | * ### .exist 3947 | * 3948 | * Asserts that the target is neither `null` nor `undefined`. 3949 | * 3950 | * var foo = 'hi'; 3951 | * 3952 | * should.exist(foo, 'foo exists'); 3953 | * 3954 | * @name exist 3955 | * @namespace Should 3956 | * @api public 3957 | */ 3958 | 3959 | should.exist = function (val, msg) { 3960 | new Assertion(val, msg).to.exist; 3961 | } 3962 | 3963 | // negation 3964 | should.not = {} 3965 | 3966 | /** 3967 | * ### .not.equal(actual, expected, [message]) 3968 | * 3969 | * Asserts non-strict inequality (`!=`) of `actual` and `expected`. 3970 | * 3971 | * should.not.equal(3, 4, 'these numbers are not equal'); 3972 | * 3973 | * @name not.equal 3974 | * @param {Mixed} actual 3975 | * @param {Mixed} expected 3976 | * @param {String} message 3977 | * @namespace Should 3978 | * @api public 3979 | */ 3980 | 3981 | should.not.equal = function (val1, val2, msg) { 3982 | new Assertion(val1, msg).to.not.equal(val2); 3983 | }; 3984 | 3985 | /** 3986 | * ### .throw(function, [constructor/regexp], [message]) 3987 | * 3988 | * Asserts that `function` will _not_ throw an error that is an instance of 3989 | * `constructor`, or alternately that it will not throw an error with message 3990 | * matching `regexp`. 3991 | * 3992 | * should.not.throw(fn, Error, 'function does not throw'); 3993 | * 3994 | * @name not.throw 3995 | * @alias not.Throw 3996 | * @param {Function} function 3997 | * @param {ErrorConstructor} constructor 3998 | * @param {RegExp} regexp 3999 | * @param {String} message 4000 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 4001 | * @namespace Should 4002 | * @api public 4003 | */ 4004 | 4005 | should.not.Throw = function (fn, errt, errs, msg) { 4006 | new Assertion(fn, msg).to.not.Throw(errt, errs); 4007 | }; 4008 | 4009 | /** 4010 | * ### .not.exist 4011 | * 4012 | * Asserts that the target is neither `null` nor `undefined`. 4013 | * 4014 | * var bar = null; 4015 | * 4016 | * should.not.exist(bar, 'bar does not exist'); 4017 | * 4018 | * @name not.exist 4019 | * @namespace Should 4020 | * @api public 4021 | */ 4022 | 4023 | should.not.exist = function (val, msg) { 4024 | new Assertion(val, msg).to.not.exist; 4025 | } 4026 | 4027 | should['throw'] = should['Throw']; 4028 | should.not['throw'] = should.not['Throw']; 4029 | 4030 | return should; 4031 | }; 4032 | 4033 | chai.should = loadShould; 4034 | chai.Should = loadShould; 4035 | }; 4036 | 4037 | },{}],9:[function(require,module,exports){ 4038 | /*! 4039 | * Chai - addChainingMethod utility 4040 | * Copyright(c) 2012-2014 Jake Luer 4041 | * MIT Licensed 4042 | */ 4043 | 4044 | /*! 4045 | * Module dependencies 4046 | */ 4047 | 4048 | var transferFlags = require('./transferFlags'); 4049 | var flag = require('./flag'); 4050 | var config = require('../config'); 4051 | 4052 | /*! 4053 | * Module variables 4054 | */ 4055 | 4056 | // Check whether `__proto__` is supported 4057 | var hasProtoSupport = '__proto__' in Object; 4058 | 4059 | // Without `__proto__` support, this module will need to add properties to a function. 4060 | // However, some Function.prototype methods cannot be overwritten, 4061 | // and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). 4062 | var excludeNames = /^(?:length|name|arguments|caller)$/; 4063 | 4064 | // Cache `Function` properties 4065 | var call = Function.prototype.call, 4066 | apply = Function.prototype.apply; 4067 | 4068 | /** 4069 | * ### addChainableMethod (ctx, name, method, chainingBehavior) 4070 | * 4071 | * Adds a method to an object, such that the method can also be chained. 4072 | * 4073 | * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { 4074 | * var obj = utils.flag(this, 'object'); 4075 | * new chai.Assertion(obj).to.be.equal(str); 4076 | * }); 4077 | * 4078 | * Can also be accessed directly from `chai.Assertion`. 4079 | * 4080 | * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); 4081 | * 4082 | * The result can then be used as both a method assertion, executing both `method` and 4083 | * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. 4084 | * 4085 | * expect(fooStr).to.be.foo('bar'); 4086 | * expect(fooStr).to.be.foo.equal('foo'); 4087 | * 4088 | * @param {Object} ctx object to which the method is added 4089 | * @param {String} name of method to add 4090 | * @param {Function} method function to be used for `name`, when called 4091 | * @param {Function} chainingBehavior function to be called every time the property is accessed 4092 | * @namespace Utils 4093 | * @name addChainableMethod 4094 | * @api public 4095 | */ 4096 | 4097 | module.exports = function (ctx, name, method, chainingBehavior) { 4098 | if (typeof chainingBehavior !== 'function') { 4099 | chainingBehavior = function () { }; 4100 | } 4101 | 4102 | var chainableBehavior = { 4103 | method: method 4104 | , chainingBehavior: chainingBehavior 4105 | }; 4106 | 4107 | // save the methods so we can overwrite them later, if we need to. 4108 | if (!ctx.__methods) { 4109 | ctx.__methods = {}; 4110 | } 4111 | ctx.__methods[name] = chainableBehavior; 4112 | 4113 | Object.defineProperty(ctx, name, 4114 | { get: function () { 4115 | chainableBehavior.chainingBehavior.call(this); 4116 | 4117 | var assert = function assert() { 4118 | var old_ssfi = flag(this, 'ssfi'); 4119 | if (old_ssfi && config.includeStack === false) 4120 | flag(this, 'ssfi', assert); 4121 | var result = chainableBehavior.method.apply(this, arguments); 4122 | return result === undefined ? this : result; 4123 | }; 4124 | 4125 | // Use `__proto__` if available 4126 | if (hasProtoSupport) { 4127 | // Inherit all properties from the object by replacing the `Function` prototype 4128 | var prototype = assert.__proto__ = Object.create(this); 4129 | // Restore the `call` and `apply` methods from `Function` 4130 | prototype.call = call; 4131 | prototype.apply = apply; 4132 | } 4133 | // Otherwise, redefine all properties (slow!) 4134 | else { 4135 | var asserterNames = Object.getOwnPropertyNames(ctx); 4136 | asserterNames.forEach(function (asserterName) { 4137 | if (!excludeNames.test(asserterName)) { 4138 | var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); 4139 | Object.defineProperty(assert, asserterName, pd); 4140 | } 4141 | }); 4142 | } 4143 | 4144 | transferFlags(this, assert); 4145 | return assert; 4146 | } 4147 | , configurable: true 4148 | }); 4149 | }; 4150 | 4151 | },{"../config":4,"./flag":13,"./transferFlags":29}],10:[function(require,module,exports){ 4152 | /*! 4153 | * Chai - addMethod utility 4154 | * Copyright(c) 2012-2014 Jake Luer 4155 | * MIT Licensed 4156 | */ 4157 | 4158 | var config = require('../config'); 4159 | 4160 | /** 4161 | * ### .addMethod (ctx, name, method) 4162 | * 4163 | * Adds a method to the prototype of an object. 4164 | * 4165 | * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { 4166 | * var obj = utils.flag(this, 'object'); 4167 | * new chai.Assertion(obj).to.be.equal(str); 4168 | * }); 4169 | * 4170 | * Can also be accessed directly from `chai.Assertion`. 4171 | * 4172 | * chai.Assertion.addMethod('foo', fn); 4173 | * 4174 | * Then can be used as any other assertion. 4175 | * 4176 | * expect(fooStr).to.be.foo('bar'); 4177 | * 4178 | * @param {Object} ctx object to which the method is added 4179 | * @param {String} name of method to add 4180 | * @param {Function} method function to be used for name 4181 | * @namespace Utils 4182 | * @name addMethod 4183 | * @api public 4184 | */ 4185 | var flag = require('./flag'); 4186 | 4187 | module.exports = function (ctx, name, method) { 4188 | ctx[name] = function () { 4189 | var old_ssfi = flag(this, 'ssfi'); 4190 | if (old_ssfi && config.includeStack === false) 4191 | flag(this, 'ssfi', ctx[name]); 4192 | var result = method.apply(this, arguments); 4193 | return result === undefined ? this : result; 4194 | }; 4195 | }; 4196 | 4197 | },{"../config":4,"./flag":13}],11:[function(require,module,exports){ 4198 | /*! 4199 | * Chai - addProperty utility 4200 | * Copyright(c) 2012-2014 Jake Luer 4201 | * MIT Licensed 4202 | */ 4203 | 4204 | var config = require('../config'); 4205 | var flag = require('./flag'); 4206 | 4207 | /** 4208 | * ### addProperty (ctx, name, getter) 4209 | * 4210 | * Adds a property to the prototype of an object. 4211 | * 4212 | * utils.addProperty(chai.Assertion.prototype, 'foo', function () { 4213 | * var obj = utils.flag(this, 'object'); 4214 | * new chai.Assertion(obj).to.be.instanceof(Foo); 4215 | * }); 4216 | * 4217 | * Can also be accessed directly from `chai.Assertion`. 4218 | * 4219 | * chai.Assertion.addProperty('foo', fn); 4220 | * 4221 | * Then can be used as any other assertion. 4222 | * 4223 | * expect(myFoo).to.be.foo; 4224 | * 4225 | * @param {Object} ctx object to which the property is added 4226 | * @param {String} name of property to add 4227 | * @param {Function} getter function to be used for name 4228 | * @namespace Utils 4229 | * @name addProperty 4230 | * @api public 4231 | */ 4232 | 4233 | module.exports = function (ctx, name, getter) { 4234 | Object.defineProperty(ctx, name, 4235 | { get: function addProperty() { 4236 | var old_ssfi = flag(this, 'ssfi'); 4237 | if (old_ssfi && config.includeStack === false) 4238 | flag(this, 'ssfi', addProperty); 4239 | 4240 | var result = getter.call(this); 4241 | return result === undefined ? this : result; 4242 | } 4243 | , configurable: true 4244 | }); 4245 | }; 4246 | 4247 | },{"../config":4,"./flag":13}],12:[function(require,module,exports){ 4248 | /*! 4249 | * Chai - expectTypes utility 4250 | * Copyright(c) 2012-2014 Jake Luer 4251 | * MIT Licensed 4252 | */ 4253 | 4254 | /** 4255 | * ### expectTypes(obj, types) 4256 | * 4257 | * Ensures that the object being tested against is of a valid type. 4258 | * 4259 | * utils.expectTypes(this, ['array', 'object', 'string']); 4260 | * 4261 | * @param {Mixed} obj constructed Assertion 4262 | * @param {Array} type A list of allowed types for this assertion 4263 | * @namespace Utils 4264 | * @name expectTypes 4265 | * @api public 4266 | */ 4267 | 4268 | var AssertionError = require('assertion-error'); 4269 | var flag = require('./flag'); 4270 | var type = require('type-detect'); 4271 | 4272 | module.exports = function (obj, types) { 4273 | var obj = flag(obj, 'object'); 4274 | types = types.map(function (t) { return t.toLowerCase(); }); 4275 | types.sort(); 4276 | 4277 | // Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum' 4278 | var str = types.map(function (t, index) { 4279 | var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a'; 4280 | var or = types.length > 1 && index === types.length - 1 ? 'or ' : ''; 4281 | return or + art + ' ' + t; 4282 | }).join(', '); 4283 | 4284 | if (!types.some(function (expected) { return type(obj) === expected; })) { 4285 | throw new AssertionError( 4286 | 'object tested must be ' + str + ', but ' + type(obj) + ' given' 4287 | ); 4288 | } 4289 | }; 4290 | 4291 | },{"./flag":13,"assertion-error":30,"type-detect":35}],13:[function(require,module,exports){ 4292 | /*! 4293 | * Chai - flag utility 4294 | * Copyright(c) 2012-2014 Jake Luer 4295 | * MIT Licensed 4296 | */ 4297 | 4298 | /** 4299 | * ### flag(object, key, [value]) 4300 | * 4301 | * Get or set a flag value on an object. If a 4302 | * value is provided it will be set, else it will 4303 | * return the currently set value or `undefined` if 4304 | * the value is not set. 4305 | * 4306 | * utils.flag(this, 'foo', 'bar'); // setter 4307 | * utils.flag(this, 'foo'); // getter, returns `bar` 4308 | * 4309 | * @param {Object} object constructed Assertion 4310 | * @param {String} key 4311 | * @param {Mixed} value (optional) 4312 | * @namespace Utils 4313 | * @name flag 4314 | * @api private 4315 | */ 4316 | 4317 | module.exports = function (obj, key, value) { 4318 | var flags = obj.__flags || (obj.__flags = Object.create(null)); 4319 | if (arguments.length === 3) { 4320 | flags[key] = value; 4321 | } else { 4322 | return flags[key]; 4323 | } 4324 | }; 4325 | 4326 | },{}],14:[function(require,module,exports){ 4327 | /*! 4328 | * Chai - getActual utility 4329 | * Copyright(c) 2012-2014 Jake Luer 4330 | * MIT Licensed 4331 | */ 4332 | 4333 | /** 4334 | * # getActual(object, [actual]) 4335 | * 4336 | * Returns the `actual` value for an Assertion 4337 | * 4338 | * @param {Object} object (constructed Assertion) 4339 | * @param {Arguments} chai.Assertion.prototype.assert arguments 4340 | * @namespace Utils 4341 | * @name getActual 4342 | */ 4343 | 4344 | module.exports = function (obj, args) { 4345 | return args.length > 4 ? args[4] : obj._obj; 4346 | }; 4347 | 4348 | },{}],15:[function(require,module,exports){ 4349 | /*! 4350 | * Chai - getEnumerableProperties utility 4351 | * Copyright(c) 2012-2014 Jake Luer 4352 | * MIT Licensed 4353 | */ 4354 | 4355 | /** 4356 | * ### .getEnumerableProperties(object) 4357 | * 4358 | * This allows the retrieval of enumerable property names of an object, 4359 | * inherited or not. 4360 | * 4361 | * @param {Object} object 4362 | * @returns {Array} 4363 | * @namespace Utils 4364 | * @name getEnumerableProperties 4365 | * @api public 4366 | */ 4367 | 4368 | module.exports = function getEnumerableProperties(object) { 4369 | var result = []; 4370 | for (var name in object) { 4371 | result.push(name); 4372 | } 4373 | return result; 4374 | }; 4375 | 4376 | },{}],16:[function(require,module,exports){ 4377 | /*! 4378 | * Chai - message composition utility 4379 | * Copyright(c) 2012-2014 Jake Luer 4380 | * MIT Licensed 4381 | */ 4382 | 4383 | /*! 4384 | * Module dependancies 4385 | */ 4386 | 4387 | var flag = require('./flag') 4388 | , getActual = require('./getActual') 4389 | , inspect = require('./inspect') 4390 | , objDisplay = require('./objDisplay'); 4391 | 4392 | /** 4393 | * ### .getMessage(object, message, negateMessage) 4394 | * 4395 | * Construct the error message based on flags 4396 | * and template tags. Template tags will return 4397 | * a stringified inspection of the object referenced. 4398 | * 4399 | * Message template tags: 4400 | * - `#{this}` current asserted object 4401 | * - `#{act}` actual value 4402 | * - `#{exp}` expected value 4403 | * 4404 | * @param {Object} object (constructed Assertion) 4405 | * @param {Arguments} chai.Assertion.prototype.assert arguments 4406 | * @namespace Utils 4407 | * @name getMessage 4408 | * @api public 4409 | */ 4410 | 4411 | module.exports = function (obj, args) { 4412 | var negate = flag(obj, 'negate') 4413 | , val = flag(obj, 'object') 4414 | , expected = args[3] 4415 | , actual = getActual(obj, args) 4416 | , msg = negate ? args[2] : args[1] 4417 | , flagMsg = flag(obj, 'message'); 4418 | 4419 | if(typeof msg === "function") msg = msg(); 4420 | msg = msg || ''; 4421 | msg = msg 4422 | .replace(/#\{this\}/g, function () { return objDisplay(val); }) 4423 | .replace(/#\{act\}/g, function () { return objDisplay(actual); }) 4424 | .replace(/#\{exp\}/g, function () { return objDisplay(expected); }); 4425 | 4426 | return flagMsg ? flagMsg + ': ' + msg : msg; 4427 | }; 4428 | 4429 | },{"./flag":13,"./getActual":14,"./inspect":23,"./objDisplay":24}],17:[function(require,module,exports){ 4430 | /*! 4431 | * Chai - getName utility 4432 | * Copyright(c) 2012-2014 Jake Luer 4433 | * MIT Licensed 4434 | */ 4435 | 4436 | /** 4437 | * # getName(func) 4438 | * 4439 | * Gets the name of a function, in a cross-browser way. 4440 | * 4441 | * @param {Function} a function (usually a constructor) 4442 | * @namespace Utils 4443 | * @name getName 4444 | */ 4445 | 4446 | module.exports = function (func) { 4447 | if (func.name) return func.name; 4448 | 4449 | var match = /^\s?function ([^(]*)\(/.exec(func); 4450 | return match && match[1] ? match[1] : ""; 4451 | }; 4452 | 4453 | },{}],18:[function(require,module,exports){ 4454 | /*! 4455 | * Chai - getPathInfo utility 4456 | * Copyright(c) 2012-2014 Jake Luer 4457 | * MIT Licensed 4458 | */ 4459 | 4460 | var hasProperty = require('./hasProperty'); 4461 | 4462 | /** 4463 | * ### .getPathInfo(path, object) 4464 | * 4465 | * This allows the retrieval of property info in an 4466 | * object given a string path. 4467 | * 4468 | * The path info consists of an object with the 4469 | * following properties: 4470 | * 4471 | * * parent - The parent object of the property referenced by `path` 4472 | * * name - The name of the final property, a number if it was an array indexer 4473 | * * value - The value of the property, if it exists, otherwise `undefined` 4474 | * * exists - Whether the property exists or not 4475 | * 4476 | * @param {String} path 4477 | * @param {Object} object 4478 | * @returns {Object} info 4479 | * @namespace Utils 4480 | * @name getPathInfo 4481 | * @api public 4482 | */ 4483 | 4484 | module.exports = function getPathInfo(path, obj) { 4485 | var parsed = parsePath(path), 4486 | last = parsed[parsed.length - 1]; 4487 | 4488 | var info = { 4489 | parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj, 4490 | name: last.p || last.i, 4491 | value: _getPathValue(parsed, obj) 4492 | }; 4493 | info.exists = hasProperty(info.name, info.parent); 4494 | 4495 | return info; 4496 | }; 4497 | 4498 | 4499 | /*! 4500 | * ## parsePath(path) 4501 | * 4502 | * Helper function used to parse string object 4503 | * paths. Use in conjunction with `_getPathValue`. 4504 | * 4505 | * var parsed = parsePath('myobject.property.subprop'); 4506 | * 4507 | * ### Paths: 4508 | * 4509 | * * Can be as near infinitely deep and nested 4510 | * * Arrays are also valid using the formal `myobject.document[3].property`. 4511 | * * Literal dots and brackets (not delimiter) must be backslash-escaped. 4512 | * 4513 | * @param {String} path 4514 | * @returns {Object} parsed 4515 | * @api private 4516 | */ 4517 | 4518 | function parsePath (path) { 4519 | var str = path.replace(/([^\\])\[/g, '$1.[') 4520 | , parts = str.match(/(\\\.|[^.]+?)+/g); 4521 | return parts.map(function (value) { 4522 | var re = /^\[(\d+)\]$/ 4523 | , mArr = re.exec(value); 4524 | if (mArr) return { i: parseFloat(mArr[1]) }; 4525 | else return { p: value.replace(/\\([.\[\]])/g, '$1') }; 4526 | }); 4527 | } 4528 | 4529 | 4530 | /*! 4531 | * ## _getPathValue(parsed, obj) 4532 | * 4533 | * Helper companion function for `.parsePath` that returns 4534 | * the value located at the parsed address. 4535 | * 4536 | * var value = getPathValue(parsed, obj); 4537 | * 4538 | * @param {Object} parsed definition from `parsePath`. 4539 | * @param {Object} object to search against 4540 | * @param {Number} object to search against 4541 | * @returns {Object|Undefined} value 4542 | * @api private 4543 | */ 4544 | 4545 | function _getPathValue (parsed, obj, index) { 4546 | var tmp = obj 4547 | , res; 4548 | 4549 | index = (index === undefined ? parsed.length : index); 4550 | 4551 | for (var i = 0, l = index; i < l; i++) { 4552 | var part = parsed[i]; 4553 | if (tmp) { 4554 | if ('undefined' !== typeof part.p) 4555 | tmp = tmp[part.p]; 4556 | else if ('undefined' !== typeof part.i) 4557 | tmp = tmp[part.i]; 4558 | if (i == (l - 1)) res = tmp; 4559 | } else { 4560 | res = undefined; 4561 | } 4562 | } 4563 | return res; 4564 | } 4565 | 4566 | },{"./hasProperty":21}],19:[function(require,module,exports){ 4567 | /*! 4568 | * Chai - getPathValue utility 4569 | * Copyright(c) 2012-2014 Jake Luer 4570 | * @see https://github.com/logicalparadox/filtr 4571 | * MIT Licensed 4572 | */ 4573 | 4574 | var getPathInfo = require('./getPathInfo'); 4575 | 4576 | /** 4577 | * ### .getPathValue(path, object) 4578 | * 4579 | * This allows the retrieval of values in an 4580 | * object given a string path. 4581 | * 4582 | * var obj = { 4583 | * prop1: { 4584 | * arr: ['a', 'b', 'c'] 4585 | * , str: 'Hello' 4586 | * } 4587 | * , prop2: { 4588 | * arr: [ { nested: 'Universe' } ] 4589 | * , str: 'Hello again!' 4590 | * } 4591 | * } 4592 | * 4593 | * The following would be the results. 4594 | * 4595 | * getPathValue('prop1.str', obj); // Hello 4596 | * getPathValue('prop1.att[2]', obj); // b 4597 | * getPathValue('prop2.arr[0].nested', obj); // Universe 4598 | * 4599 | * @param {String} path 4600 | * @param {Object} object 4601 | * @returns {Object} value or `undefined` 4602 | * @namespace Utils 4603 | * @name getPathValue 4604 | * @api public 4605 | */ 4606 | module.exports = function(path, obj) { 4607 | var info = getPathInfo(path, obj); 4608 | return info.value; 4609 | }; 4610 | 4611 | },{"./getPathInfo":18}],20:[function(require,module,exports){ 4612 | /*! 4613 | * Chai - getProperties utility 4614 | * Copyright(c) 2012-2014 Jake Luer 4615 | * MIT Licensed 4616 | */ 4617 | 4618 | /** 4619 | * ### .getProperties(object) 4620 | * 4621 | * This allows the retrieval of property names of an object, enumerable or not, 4622 | * inherited or not. 4623 | * 4624 | * @param {Object} object 4625 | * @returns {Array} 4626 | * @namespace Utils 4627 | * @name getProperties 4628 | * @api public 4629 | */ 4630 | 4631 | module.exports = function getProperties(object) { 4632 | var result = Object.getOwnPropertyNames(object); 4633 | 4634 | function addProperty(property) { 4635 | if (result.indexOf(property) === -1) { 4636 | result.push(property); 4637 | } 4638 | } 4639 | 4640 | var proto = Object.getPrototypeOf(object); 4641 | while (proto !== null) { 4642 | Object.getOwnPropertyNames(proto).forEach(addProperty); 4643 | proto = Object.getPrototypeOf(proto); 4644 | } 4645 | 4646 | return result; 4647 | }; 4648 | 4649 | },{}],21:[function(require,module,exports){ 4650 | /*! 4651 | * Chai - hasProperty utility 4652 | * Copyright(c) 2012-2014 Jake Luer 4653 | * MIT Licensed 4654 | */ 4655 | 4656 | var type = require('type-detect'); 4657 | 4658 | /** 4659 | * ### .hasProperty(object, name) 4660 | * 4661 | * This allows checking whether an object has 4662 | * named property or numeric array index. 4663 | * 4664 | * Basically does the same thing as the `in` 4665 | * operator but works properly with natives 4666 | * and null/undefined values. 4667 | * 4668 | * var obj = { 4669 | * arr: ['a', 'b', 'c'] 4670 | * , str: 'Hello' 4671 | * } 4672 | * 4673 | * The following would be the results. 4674 | * 4675 | * hasProperty('str', obj); // true 4676 | * hasProperty('constructor', obj); // true 4677 | * hasProperty('bar', obj); // false 4678 | * 4679 | * hasProperty('length', obj.str); // true 4680 | * hasProperty(1, obj.str); // true 4681 | * hasProperty(5, obj.str); // false 4682 | * 4683 | * hasProperty('length', obj.arr); // true 4684 | * hasProperty(2, obj.arr); // true 4685 | * hasProperty(3, obj.arr); // false 4686 | * 4687 | * @param {Objuect} object 4688 | * @param {String|Number} name 4689 | * @returns {Boolean} whether it exists 4690 | * @namespace Utils 4691 | * @name getPathInfo 4692 | * @api public 4693 | */ 4694 | 4695 | var literals = { 4696 | 'number': Number 4697 | , 'string': String 4698 | }; 4699 | 4700 | module.exports = function hasProperty(name, obj) { 4701 | var ot = type(obj); 4702 | 4703 | // Bad Object, obviously no props at all 4704 | if(ot === 'null' || ot === 'undefined') 4705 | return false; 4706 | 4707 | // The `in` operator does not work with certain literals 4708 | // box these before the check 4709 | if(literals[ot] && typeof obj !== 'object') 4710 | obj = new literals[ot](obj); 4711 | 4712 | return name in obj; 4713 | }; 4714 | 4715 | },{"type-detect":35}],22:[function(require,module,exports){ 4716 | /*! 4717 | * chai 4718 | * Copyright(c) 2011 Jake Luer 4719 | * MIT Licensed 4720 | */ 4721 | 4722 | /*! 4723 | * Main exports 4724 | */ 4725 | 4726 | var exports = module.exports = {}; 4727 | 4728 | /*! 4729 | * test utility 4730 | */ 4731 | 4732 | exports.test = require('./test'); 4733 | 4734 | /*! 4735 | * type utility 4736 | */ 4737 | 4738 | exports.type = require('type-detect'); 4739 | 4740 | /*! 4741 | * expectTypes utility 4742 | */ 4743 | exports.expectTypes = require('./expectTypes'); 4744 | 4745 | /*! 4746 | * message utility 4747 | */ 4748 | 4749 | exports.getMessage = require('./getMessage'); 4750 | 4751 | /*! 4752 | * actual utility 4753 | */ 4754 | 4755 | exports.getActual = require('./getActual'); 4756 | 4757 | /*! 4758 | * Inspect util 4759 | */ 4760 | 4761 | exports.inspect = require('./inspect'); 4762 | 4763 | /*! 4764 | * Object Display util 4765 | */ 4766 | 4767 | exports.objDisplay = require('./objDisplay'); 4768 | 4769 | /*! 4770 | * Flag utility 4771 | */ 4772 | 4773 | exports.flag = require('./flag'); 4774 | 4775 | /*! 4776 | * Flag transferring utility 4777 | */ 4778 | 4779 | exports.transferFlags = require('./transferFlags'); 4780 | 4781 | /*! 4782 | * Deep equal utility 4783 | */ 4784 | 4785 | exports.eql = require('deep-eql'); 4786 | 4787 | /*! 4788 | * Deep path value 4789 | */ 4790 | 4791 | exports.getPathValue = require('./getPathValue'); 4792 | 4793 | /*! 4794 | * Deep path info 4795 | */ 4796 | 4797 | exports.getPathInfo = require('./getPathInfo'); 4798 | 4799 | /*! 4800 | * Check if a property exists 4801 | */ 4802 | 4803 | exports.hasProperty = require('./hasProperty'); 4804 | 4805 | /*! 4806 | * Function name 4807 | */ 4808 | 4809 | exports.getName = require('./getName'); 4810 | 4811 | /*! 4812 | * add Property 4813 | */ 4814 | 4815 | exports.addProperty = require('./addProperty'); 4816 | 4817 | /*! 4818 | * add Method 4819 | */ 4820 | 4821 | exports.addMethod = require('./addMethod'); 4822 | 4823 | /*! 4824 | * overwrite Property 4825 | */ 4826 | 4827 | exports.overwriteProperty = require('./overwriteProperty'); 4828 | 4829 | /*! 4830 | * overwrite Method 4831 | */ 4832 | 4833 | exports.overwriteMethod = require('./overwriteMethod'); 4834 | 4835 | /*! 4836 | * Add a chainable method 4837 | */ 4838 | 4839 | exports.addChainableMethod = require('./addChainableMethod'); 4840 | 4841 | /*! 4842 | * Overwrite chainable method 4843 | */ 4844 | 4845 | exports.overwriteChainableMethod = require('./overwriteChainableMethod'); 4846 | 4847 | },{"./addChainableMethod":9,"./addMethod":10,"./addProperty":11,"./expectTypes":12,"./flag":13,"./getActual":14,"./getMessage":16,"./getName":17,"./getPathInfo":18,"./getPathValue":19,"./hasProperty":21,"./inspect":23,"./objDisplay":24,"./overwriteChainableMethod":25,"./overwriteMethod":26,"./overwriteProperty":27,"./test":28,"./transferFlags":29,"deep-eql":31,"type-detect":35}],23:[function(require,module,exports){ 4848 | // This is (almost) directly from Node.js utils 4849 | // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js 4850 | 4851 | var getName = require('./getName'); 4852 | var getProperties = require('./getProperties'); 4853 | var getEnumerableProperties = require('./getEnumerableProperties'); 4854 | 4855 | module.exports = inspect; 4856 | 4857 | /** 4858 | * Echos the value of a value. Trys to print the value out 4859 | * in the best way possible given the different types. 4860 | * 4861 | * @param {Object} obj The object to print out. 4862 | * @param {Boolean} showHidden Flag that shows hidden (not enumerable) 4863 | * properties of objects. 4864 | * @param {Number} depth Depth in which to descend in object. Default is 2. 4865 | * @param {Boolean} colors Flag to turn on ANSI escape codes to color the 4866 | * output. Default is false (no coloring). 4867 | * @namespace Utils 4868 | * @name inspect 4869 | */ 4870 | function inspect(obj, showHidden, depth, colors) { 4871 | var ctx = { 4872 | showHidden: showHidden, 4873 | seen: [], 4874 | stylize: function (str) { return str; } 4875 | }; 4876 | return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); 4877 | } 4878 | 4879 | // Returns true if object is a DOM element. 4880 | var isDOMElement = function (object) { 4881 | if (typeof HTMLElement === 'object') { 4882 | return object instanceof HTMLElement; 4883 | } else { 4884 | return object && 4885 | typeof object === 'object' && 4886 | object.nodeType === 1 && 4887 | typeof object.nodeName === 'string'; 4888 | } 4889 | }; 4890 | 4891 | function formatValue(ctx, value, recurseTimes) { 4892 | // Provide a hook for user-specified inspect functions. 4893 | // Check that value is an object with an inspect function on it 4894 | if (value && typeof value.inspect === 'function' && 4895 | // Filter out the util module, it's inspect function is special 4896 | value.inspect !== exports.inspect && 4897 | // Also filter out any prototype objects using the circular check. 4898 | !(value.constructor && value.constructor.prototype === value)) { 4899 | var ret = value.inspect(recurseTimes); 4900 | if (typeof ret !== 'string') { 4901 | ret = formatValue(ctx, ret, recurseTimes); 4902 | } 4903 | return ret; 4904 | } 4905 | 4906 | // Primitive types cannot have properties 4907 | var primitive = formatPrimitive(ctx, value); 4908 | if (primitive) { 4909 | return primitive; 4910 | } 4911 | 4912 | // If this is a DOM element, try to get the outer HTML. 4913 | if (isDOMElement(value)) { 4914 | if ('outerHTML' in value) { 4915 | return value.outerHTML; 4916 | // This value does not have an outerHTML attribute, 4917 | // it could still be an XML element 4918 | } else { 4919 | // Attempt to serialize it 4920 | try { 4921 | if (document.xmlVersion) { 4922 | var xmlSerializer = new XMLSerializer(); 4923 | return xmlSerializer.serializeToString(value); 4924 | } else { 4925 | // Firefox 11- do not support outerHTML 4926 | // It does, however, support innerHTML 4927 | // Use the following to render the element 4928 | var ns = "http://www.w3.org/1999/xhtml"; 4929 | var container = document.createElementNS(ns, '_'); 4930 | 4931 | container.appendChild(value.cloneNode(false)); 4932 | html = container.innerHTML 4933 | .replace('><', '>' + value.innerHTML + '<'); 4934 | container.innerHTML = ''; 4935 | return html; 4936 | } 4937 | } catch (err) { 4938 | // This could be a non-native DOM implementation, 4939 | // continue with the normal flow: 4940 | // printing the element as if it is an object. 4941 | } 4942 | } 4943 | } 4944 | 4945 | // Look up the keys of the object. 4946 | var visibleKeys = getEnumerableProperties(value); 4947 | var keys = ctx.showHidden ? getProperties(value) : visibleKeys; 4948 | 4949 | // Some type of object without properties can be shortcutted. 4950 | // In IE, errors have a single `stack` property, or if they are vanilla `Error`, 4951 | // a `stack` plus `description` property; ignore those for consistency. 4952 | if (keys.length === 0 || (isError(value) && ( 4953 | (keys.length === 1 && keys[0] === 'stack') || 4954 | (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') 4955 | ))) { 4956 | if (typeof value === 'function') { 4957 | var name = getName(value); 4958 | var nameSuffix = name ? ': ' + name : ''; 4959 | return ctx.stylize('[Function' + nameSuffix + ']', 'special'); 4960 | } 4961 | if (isRegExp(value)) { 4962 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 4963 | } 4964 | if (isDate(value)) { 4965 | return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); 4966 | } 4967 | if (isError(value)) { 4968 | return formatError(value); 4969 | } 4970 | } 4971 | 4972 | var base = '', array = false, braces = ['{', '}']; 4973 | 4974 | // Make Array say that they are Array 4975 | if (isArray(value)) { 4976 | array = true; 4977 | braces = ['[', ']']; 4978 | } 4979 | 4980 | // Make functions say that they are functions 4981 | if (typeof value === 'function') { 4982 | var name = getName(value); 4983 | var nameSuffix = name ? ': ' + name : ''; 4984 | base = ' [Function' + nameSuffix + ']'; 4985 | } 4986 | 4987 | // Make RegExps say that they are RegExps 4988 | if (isRegExp(value)) { 4989 | base = ' ' + RegExp.prototype.toString.call(value); 4990 | } 4991 | 4992 | // Make dates with properties first say the date 4993 | if (isDate(value)) { 4994 | base = ' ' + Date.prototype.toUTCString.call(value); 4995 | } 4996 | 4997 | // Make error with message first say the error 4998 | if (isError(value)) { 4999 | return formatError(value); 5000 | } 5001 | 5002 | if (keys.length === 0 && (!array || value.length == 0)) { 5003 | return braces[0] + base + braces[1]; 5004 | } 5005 | 5006 | if (recurseTimes < 0) { 5007 | if (isRegExp(value)) { 5008 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 5009 | } else { 5010 | return ctx.stylize('[Object]', 'special'); 5011 | } 5012 | } 5013 | 5014 | ctx.seen.push(value); 5015 | 5016 | var output; 5017 | if (array) { 5018 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 5019 | } else { 5020 | output = keys.map(function(key) { 5021 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 5022 | }); 5023 | } 5024 | 5025 | ctx.seen.pop(); 5026 | 5027 | return reduceToSingleString(output, base, braces); 5028 | } 5029 | 5030 | 5031 | function formatPrimitive(ctx, value) { 5032 | switch (typeof value) { 5033 | case 'undefined': 5034 | return ctx.stylize('undefined', 'undefined'); 5035 | 5036 | case 'string': 5037 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 5038 | .replace(/'/g, "\\'") 5039 | .replace(/\\"/g, '"') + '\''; 5040 | return ctx.stylize(simple, 'string'); 5041 | 5042 | case 'number': 5043 | if (value === 0 && (1/value) === -Infinity) { 5044 | return ctx.stylize('-0', 'number'); 5045 | } 5046 | return ctx.stylize('' + value, 'number'); 5047 | 5048 | case 'boolean': 5049 | return ctx.stylize('' + value, 'boolean'); 5050 | } 5051 | // For some reason typeof null is "object", so special case here. 5052 | if (value === null) { 5053 | return ctx.stylize('null', 'null'); 5054 | } 5055 | } 5056 | 5057 | 5058 | function formatError(value) { 5059 | return '[' + Error.prototype.toString.call(value) + ']'; 5060 | } 5061 | 5062 | 5063 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 5064 | var output = []; 5065 | for (var i = 0, l = value.length; i < l; ++i) { 5066 | if (Object.prototype.hasOwnProperty.call(value, String(i))) { 5067 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 5068 | String(i), true)); 5069 | } else { 5070 | output.push(''); 5071 | } 5072 | } 5073 | keys.forEach(function(key) { 5074 | if (!key.match(/^\d+$/)) { 5075 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 5076 | key, true)); 5077 | } 5078 | }); 5079 | return output; 5080 | } 5081 | 5082 | 5083 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 5084 | var name, str; 5085 | if (value.__lookupGetter__) { 5086 | if (value.__lookupGetter__(key)) { 5087 | if (value.__lookupSetter__(key)) { 5088 | str = ctx.stylize('[Getter/Setter]', 'special'); 5089 | } else { 5090 | str = ctx.stylize('[Getter]', 'special'); 5091 | } 5092 | } else { 5093 | if (value.__lookupSetter__(key)) { 5094 | str = ctx.stylize('[Setter]', 'special'); 5095 | } 5096 | } 5097 | } 5098 | if (visibleKeys.indexOf(key) < 0) { 5099 | name = '[' + key + ']'; 5100 | } 5101 | if (!str) { 5102 | if (ctx.seen.indexOf(value[key]) < 0) { 5103 | if (recurseTimes === null) { 5104 | str = formatValue(ctx, value[key], null); 5105 | } else { 5106 | str = formatValue(ctx, value[key], recurseTimes - 1); 5107 | } 5108 | if (str.indexOf('\n') > -1) { 5109 | if (array) { 5110 | str = str.split('\n').map(function(line) { 5111 | return ' ' + line; 5112 | }).join('\n').substr(2); 5113 | } else { 5114 | str = '\n' + str.split('\n').map(function(line) { 5115 | return ' ' + line; 5116 | }).join('\n'); 5117 | } 5118 | } 5119 | } else { 5120 | str = ctx.stylize('[Circular]', 'special'); 5121 | } 5122 | } 5123 | if (typeof name === 'undefined') { 5124 | if (array && key.match(/^\d+$/)) { 5125 | return str; 5126 | } 5127 | name = JSON.stringify('' + key); 5128 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 5129 | name = name.substr(1, name.length - 2); 5130 | name = ctx.stylize(name, 'name'); 5131 | } else { 5132 | name = name.replace(/'/g, "\\'") 5133 | .replace(/\\"/g, '"') 5134 | .replace(/(^"|"$)/g, "'"); 5135 | name = ctx.stylize(name, 'string'); 5136 | } 5137 | } 5138 | 5139 | return name + ': ' + str; 5140 | } 5141 | 5142 | 5143 | function reduceToSingleString(output, base, braces) { 5144 | var numLinesEst = 0; 5145 | var length = output.reduce(function(prev, cur) { 5146 | numLinesEst++; 5147 | if (cur.indexOf('\n') >= 0) numLinesEst++; 5148 | return prev + cur.length + 1; 5149 | }, 0); 5150 | 5151 | if (length > 60) { 5152 | return braces[0] + 5153 | (base === '' ? '' : base + '\n ') + 5154 | ' ' + 5155 | output.join(',\n ') + 5156 | ' ' + 5157 | braces[1]; 5158 | } 5159 | 5160 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 5161 | } 5162 | 5163 | function isArray(ar) { 5164 | return Array.isArray(ar) || 5165 | (typeof ar === 'object' && objectToString(ar) === '[object Array]'); 5166 | } 5167 | 5168 | function isRegExp(re) { 5169 | return typeof re === 'object' && objectToString(re) === '[object RegExp]'; 5170 | } 5171 | 5172 | function isDate(d) { 5173 | return typeof d === 'object' && objectToString(d) === '[object Date]'; 5174 | } 5175 | 5176 | function isError(e) { 5177 | return typeof e === 'object' && objectToString(e) === '[object Error]'; 5178 | } 5179 | 5180 | function objectToString(o) { 5181 | return Object.prototype.toString.call(o); 5182 | } 5183 | 5184 | },{"./getEnumerableProperties":15,"./getName":17,"./getProperties":20}],24:[function(require,module,exports){ 5185 | /*! 5186 | * Chai - flag utility 5187 | * Copyright(c) 2012-2014 Jake Luer 5188 | * MIT Licensed 5189 | */ 5190 | 5191 | /*! 5192 | * Module dependancies 5193 | */ 5194 | 5195 | var inspect = require('./inspect'); 5196 | var config = require('../config'); 5197 | 5198 | /** 5199 | * ### .objDisplay (object) 5200 | * 5201 | * Determines if an object or an array matches 5202 | * criteria to be inspected in-line for error 5203 | * messages or should be truncated. 5204 | * 5205 | * @param {Mixed} javascript object to inspect 5206 | * @name objDisplay 5207 | * @namespace Utils 5208 | * @api public 5209 | */ 5210 | 5211 | module.exports = function (obj) { 5212 | var str = inspect(obj) 5213 | , type = Object.prototype.toString.call(obj); 5214 | 5215 | if (config.truncateThreshold && str.length >= config.truncateThreshold) { 5216 | if (type === '[object Function]') { 5217 | return !obj.name || obj.name === '' 5218 | ? '[Function]' 5219 | : '[Function: ' + obj.name + ']'; 5220 | } else if (type === '[object Array]') { 5221 | return '[ Array(' + obj.length + ') ]'; 5222 | } else if (type === '[object Object]') { 5223 | var keys = Object.keys(obj) 5224 | , kstr = keys.length > 2 5225 | ? keys.splice(0, 2).join(', ') + ', ...' 5226 | : keys.join(', '); 5227 | return '{ Object (' + kstr + ') }'; 5228 | } else { 5229 | return str; 5230 | } 5231 | } else { 5232 | return str; 5233 | } 5234 | }; 5235 | 5236 | },{"../config":4,"./inspect":23}],25:[function(require,module,exports){ 5237 | /*! 5238 | * Chai - overwriteChainableMethod utility 5239 | * Copyright(c) 2012-2014 Jake Luer 5240 | * MIT Licensed 5241 | */ 5242 | 5243 | /** 5244 | * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) 5245 | * 5246 | * Overwites an already existing chainable method 5247 | * and provides access to the previous function or 5248 | * property. Must return functions to be used for 5249 | * name. 5250 | * 5251 | * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', 5252 | * function (_super) { 5253 | * } 5254 | * , function (_super) { 5255 | * } 5256 | * ); 5257 | * 5258 | * Can also be accessed directly from `chai.Assertion`. 5259 | * 5260 | * chai.Assertion.overwriteChainableMethod('foo', fn, fn); 5261 | * 5262 | * Then can be used as any other assertion. 5263 | * 5264 | * expect(myFoo).to.have.length(3); 5265 | * expect(myFoo).to.have.length.above(3); 5266 | * 5267 | * @param {Object} ctx object whose method / property is to be overwritten 5268 | * @param {String} name of method / property to overwrite 5269 | * @param {Function} method function that returns a function to be used for name 5270 | * @param {Function} chainingBehavior function that returns a function to be used for property 5271 | * @namespace Utils 5272 | * @name overwriteChainableMethod 5273 | * @api public 5274 | */ 5275 | 5276 | module.exports = function (ctx, name, method, chainingBehavior) { 5277 | var chainableBehavior = ctx.__methods[name]; 5278 | 5279 | var _chainingBehavior = chainableBehavior.chainingBehavior; 5280 | chainableBehavior.chainingBehavior = function () { 5281 | var result = chainingBehavior(_chainingBehavior).call(this); 5282 | return result === undefined ? this : result; 5283 | }; 5284 | 5285 | var _method = chainableBehavior.method; 5286 | chainableBehavior.method = function () { 5287 | var result = method(_method).apply(this, arguments); 5288 | return result === undefined ? this : result; 5289 | }; 5290 | }; 5291 | 5292 | },{}],26:[function(require,module,exports){ 5293 | /*! 5294 | * Chai - overwriteMethod utility 5295 | * Copyright(c) 2012-2014 Jake Luer 5296 | * MIT Licensed 5297 | */ 5298 | 5299 | /** 5300 | * ### overwriteMethod (ctx, name, fn) 5301 | * 5302 | * Overwites an already existing method and provides 5303 | * access to previous function. Must return function 5304 | * to be used for name. 5305 | * 5306 | * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { 5307 | * return function (str) { 5308 | * var obj = utils.flag(this, 'object'); 5309 | * if (obj instanceof Foo) { 5310 | * new chai.Assertion(obj.value).to.equal(str); 5311 | * } else { 5312 | * _super.apply(this, arguments); 5313 | * } 5314 | * } 5315 | * }); 5316 | * 5317 | * Can also be accessed directly from `chai.Assertion`. 5318 | * 5319 | * chai.Assertion.overwriteMethod('foo', fn); 5320 | * 5321 | * Then can be used as any other assertion. 5322 | * 5323 | * expect(myFoo).to.equal('bar'); 5324 | * 5325 | * @param {Object} ctx object whose method is to be overwritten 5326 | * @param {String} name of method to overwrite 5327 | * @param {Function} method function that returns a function to be used for name 5328 | * @namespace Utils 5329 | * @name overwriteMethod 5330 | * @api public 5331 | */ 5332 | 5333 | module.exports = function (ctx, name, method) { 5334 | var _method = ctx[name] 5335 | , _super = function () { return this; }; 5336 | 5337 | if (_method && 'function' === typeof _method) 5338 | _super = _method; 5339 | 5340 | ctx[name] = function () { 5341 | var result = method(_super).apply(this, arguments); 5342 | return result === undefined ? this : result; 5343 | } 5344 | }; 5345 | 5346 | },{}],27:[function(require,module,exports){ 5347 | /*! 5348 | * Chai - overwriteProperty utility 5349 | * Copyright(c) 2012-2014 Jake Luer 5350 | * MIT Licensed 5351 | */ 5352 | 5353 | /** 5354 | * ### overwriteProperty (ctx, name, fn) 5355 | * 5356 | * Overwites an already existing property getter and provides 5357 | * access to previous value. Must return function to use as getter. 5358 | * 5359 | * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { 5360 | * return function () { 5361 | * var obj = utils.flag(this, 'object'); 5362 | * if (obj instanceof Foo) { 5363 | * new chai.Assertion(obj.name).to.equal('bar'); 5364 | * } else { 5365 | * _super.call(this); 5366 | * } 5367 | * } 5368 | * }); 5369 | * 5370 | * 5371 | * Can also be accessed directly from `chai.Assertion`. 5372 | * 5373 | * chai.Assertion.overwriteProperty('foo', fn); 5374 | * 5375 | * Then can be used as any other assertion. 5376 | * 5377 | * expect(myFoo).to.be.ok; 5378 | * 5379 | * @param {Object} ctx object whose property is to be overwritten 5380 | * @param {String} name of property to overwrite 5381 | * @param {Function} getter function that returns a getter function to be used for name 5382 | * @namespace Utils 5383 | * @name overwriteProperty 5384 | * @api public 5385 | */ 5386 | 5387 | module.exports = function (ctx, name, getter) { 5388 | var _get = Object.getOwnPropertyDescriptor(ctx, name) 5389 | , _super = function () {}; 5390 | 5391 | if (_get && 'function' === typeof _get.get) 5392 | _super = _get.get 5393 | 5394 | Object.defineProperty(ctx, name, 5395 | { get: function () { 5396 | var result = getter(_super).call(this); 5397 | return result === undefined ? this : result; 5398 | } 5399 | , configurable: true 5400 | }); 5401 | }; 5402 | 5403 | },{}],28:[function(require,module,exports){ 5404 | /*! 5405 | * Chai - test utility 5406 | * Copyright(c) 2012-2014 Jake Luer 5407 | * MIT Licensed 5408 | */ 5409 | 5410 | /*! 5411 | * Module dependancies 5412 | */ 5413 | 5414 | var flag = require('./flag'); 5415 | 5416 | /** 5417 | * # test(object, expression) 5418 | * 5419 | * Test and object for expression. 5420 | * 5421 | * @param {Object} object (constructed Assertion) 5422 | * @param {Arguments} chai.Assertion.prototype.assert arguments 5423 | * @namespace Utils 5424 | * @name test 5425 | */ 5426 | 5427 | module.exports = function (obj, args) { 5428 | var negate = flag(obj, 'negate') 5429 | , expr = args[0]; 5430 | return negate ? !expr : expr; 5431 | }; 5432 | 5433 | },{"./flag":13}],29:[function(require,module,exports){ 5434 | /*! 5435 | * Chai - transferFlags utility 5436 | * Copyright(c) 2012-2014 Jake Luer 5437 | * MIT Licensed 5438 | */ 5439 | 5440 | /** 5441 | * ### transferFlags(assertion, object, includeAll = true) 5442 | * 5443 | * Transfer all the flags for `assertion` to `object`. If 5444 | * `includeAll` is set to `false`, then the base Chai 5445 | * assertion flags (namely `object`, `ssfi`, and `message`) 5446 | * will not be transferred. 5447 | * 5448 | * 5449 | * var newAssertion = new Assertion(); 5450 | * utils.transferFlags(assertion, newAssertion); 5451 | * 5452 | * var anotherAsseriton = new Assertion(myObj); 5453 | * utils.transferFlags(assertion, anotherAssertion, false); 5454 | * 5455 | * @param {Assertion} assertion the assertion to transfer the flags from 5456 | * @param {Object} object the object to transfer the flags to; usually a new assertion 5457 | * @param {Boolean} includeAll 5458 | * @namespace Utils 5459 | * @name transferFlags 5460 | * @api private 5461 | */ 5462 | 5463 | module.exports = function (assertion, object, includeAll) { 5464 | var flags = assertion.__flags || (assertion.__flags = Object.create(null)); 5465 | 5466 | if (!object.__flags) { 5467 | object.__flags = Object.create(null); 5468 | } 5469 | 5470 | includeAll = arguments.length === 3 ? includeAll : true; 5471 | 5472 | for (var flag in flags) { 5473 | if (includeAll || 5474 | (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { 5475 | object.__flags[flag] = flags[flag]; 5476 | } 5477 | } 5478 | }; 5479 | 5480 | },{}],30:[function(require,module,exports){ 5481 | /*! 5482 | * assertion-error 5483 | * Copyright(c) 2013 Jake Luer 5484 | * MIT Licensed 5485 | */ 5486 | 5487 | /*! 5488 | * Return a function that will copy properties from 5489 | * one object to another excluding any originally 5490 | * listed. Returned function will create a new `{}`. 5491 | * 5492 | * @param {String} excluded properties ... 5493 | * @return {Function} 5494 | */ 5495 | 5496 | function exclude () { 5497 | var excludes = [].slice.call(arguments); 5498 | 5499 | function excludeProps (res, obj) { 5500 | Object.keys(obj).forEach(function (key) { 5501 | if (!~excludes.indexOf(key)) res[key] = obj[key]; 5502 | }); 5503 | } 5504 | 5505 | return function extendExclude () { 5506 | var args = [].slice.call(arguments) 5507 | , i = 0 5508 | , res = {}; 5509 | 5510 | for (; i < args.length; i++) { 5511 | excludeProps(res, args[i]); 5512 | } 5513 | 5514 | return res; 5515 | }; 5516 | }; 5517 | 5518 | /*! 5519 | * Primary Exports 5520 | */ 5521 | 5522 | module.exports = AssertionError; 5523 | 5524 | /** 5525 | * ### AssertionError 5526 | * 5527 | * An extension of the JavaScript `Error` constructor for 5528 | * assertion and validation scenarios. 5529 | * 5530 | * @param {String} message 5531 | * @param {Object} properties to include (optional) 5532 | * @param {callee} start stack function (optional) 5533 | */ 5534 | 5535 | function AssertionError (message, _props, ssf) { 5536 | var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') 5537 | , props = extend(_props || {}); 5538 | 5539 | // default values 5540 | this.message = message || 'Unspecified AssertionError'; 5541 | this.showDiff = false; 5542 | 5543 | // copy from properties 5544 | for (var key in props) { 5545 | this[key] = props[key]; 5546 | } 5547 | 5548 | // capture stack trace 5549 | ssf = ssf || arguments.callee; 5550 | if (ssf && Error.captureStackTrace) { 5551 | Error.captureStackTrace(this, ssf); 5552 | } else { 5553 | this.stack = new Error().stack; 5554 | } 5555 | } 5556 | 5557 | /*! 5558 | * Inherit from Error.prototype 5559 | */ 5560 | 5561 | AssertionError.prototype = Object.create(Error.prototype); 5562 | 5563 | /*! 5564 | * Statically set name 5565 | */ 5566 | 5567 | AssertionError.prototype.name = 'AssertionError'; 5568 | 5569 | /*! 5570 | * Ensure correct constructor 5571 | */ 5572 | 5573 | AssertionError.prototype.constructor = AssertionError; 5574 | 5575 | /** 5576 | * Allow errors to be converted to JSON for static transfer. 5577 | * 5578 | * @param {Boolean} include stack (default: `true`) 5579 | * @return {Object} object that can be `JSON.stringify` 5580 | */ 5581 | 5582 | AssertionError.prototype.toJSON = function (stack) { 5583 | var extend = exclude('constructor', 'toJSON', 'stack') 5584 | , props = extend({ name: this.name }, this); 5585 | 5586 | // include stack if exists and not turned off 5587 | if (false !== stack && this.stack) { 5588 | props.stack = this.stack; 5589 | } 5590 | 5591 | return props; 5592 | }; 5593 | 5594 | },{}],31:[function(require,module,exports){ 5595 | module.exports = require('./lib/eql'); 5596 | 5597 | },{"./lib/eql":32}],32:[function(require,module,exports){ 5598 | /*! 5599 | * deep-eql 5600 | * Copyright(c) 2013 Jake Luer 5601 | * MIT Licensed 5602 | */ 5603 | 5604 | /*! 5605 | * Module dependencies 5606 | */ 5607 | 5608 | var type = require('type-detect'); 5609 | 5610 | /*! 5611 | * Buffer.isBuffer browser shim 5612 | */ 5613 | 5614 | var Buffer; 5615 | try { Buffer = require('buffer').Buffer; } 5616 | catch(ex) { 5617 | Buffer = {}; 5618 | Buffer.isBuffer = function() { return false; } 5619 | } 5620 | 5621 | /*! 5622 | * Primary Export 5623 | */ 5624 | 5625 | module.exports = deepEqual; 5626 | 5627 | /** 5628 | * Assert super-strict (egal) equality between 5629 | * two objects of any type. 5630 | * 5631 | * @param {Mixed} a 5632 | * @param {Mixed} b 5633 | * @param {Array} memoised (optional) 5634 | * @return {Boolean} equal match 5635 | */ 5636 | 5637 | function deepEqual(a, b, m) { 5638 | if (sameValue(a, b)) { 5639 | return true; 5640 | } else if ('date' === type(a)) { 5641 | return dateEqual(a, b); 5642 | } else if ('regexp' === type(a)) { 5643 | return regexpEqual(a, b); 5644 | } else if (Buffer.isBuffer(a)) { 5645 | return bufferEqual(a, b); 5646 | } else if ('arguments' === type(a)) { 5647 | return argumentsEqual(a, b, m); 5648 | } else if (!typeEqual(a, b)) { 5649 | return false; 5650 | } else if (('object' !== type(a) && 'object' !== type(b)) 5651 | && ('array' !== type(a) && 'array' !== type(b))) { 5652 | return sameValue(a, b); 5653 | } else { 5654 | return objectEqual(a, b, m); 5655 | } 5656 | } 5657 | 5658 | /*! 5659 | * Strict (egal) equality test. Ensures that NaN always 5660 | * equals NaN and `-0` does not equal `+0`. 5661 | * 5662 | * @param {Mixed} a 5663 | * @param {Mixed} b 5664 | * @return {Boolean} equal match 5665 | */ 5666 | 5667 | function sameValue(a, b) { 5668 | if (a === b) return a !== 0 || 1 / a === 1 / b; 5669 | return a !== a && b !== b; 5670 | } 5671 | 5672 | /*! 5673 | * Compare the types of two given objects and 5674 | * return if they are equal. Note that an Array 5675 | * has a type of `array` (not `object`) and arguments 5676 | * have a type of `arguments` (not `array`/`object`). 5677 | * 5678 | * @param {Mixed} a 5679 | * @param {Mixed} b 5680 | * @return {Boolean} result 5681 | */ 5682 | 5683 | function typeEqual(a, b) { 5684 | return type(a) === type(b); 5685 | } 5686 | 5687 | /*! 5688 | * Compare two Date objects by asserting that 5689 | * the time values are equal using `saveValue`. 5690 | * 5691 | * @param {Date} a 5692 | * @param {Date} b 5693 | * @return {Boolean} result 5694 | */ 5695 | 5696 | function dateEqual(a, b) { 5697 | if ('date' !== type(b)) return false; 5698 | return sameValue(a.getTime(), b.getTime()); 5699 | } 5700 | 5701 | /*! 5702 | * Compare two regular expressions by converting them 5703 | * to string and checking for `sameValue`. 5704 | * 5705 | * @param {RegExp} a 5706 | * @param {RegExp} b 5707 | * @return {Boolean} result 5708 | */ 5709 | 5710 | function regexpEqual(a, b) { 5711 | if ('regexp' !== type(b)) return false; 5712 | return sameValue(a.toString(), b.toString()); 5713 | } 5714 | 5715 | /*! 5716 | * Assert deep equality of two `arguments` objects. 5717 | * Unfortunately, these must be sliced to arrays 5718 | * prior to test to ensure no bad behavior. 5719 | * 5720 | * @param {Arguments} a 5721 | * @param {Arguments} b 5722 | * @param {Array} memoize (optional) 5723 | * @return {Boolean} result 5724 | */ 5725 | 5726 | function argumentsEqual(a, b, m) { 5727 | if ('arguments' !== type(b)) return false; 5728 | a = [].slice.call(a); 5729 | b = [].slice.call(b); 5730 | return deepEqual(a, b, m); 5731 | } 5732 | 5733 | /*! 5734 | * Get enumerable properties of a given object. 5735 | * 5736 | * @param {Object} a 5737 | * @return {Array} property names 5738 | */ 5739 | 5740 | function enumerable(a) { 5741 | var res = []; 5742 | for (var key in a) res.push(key); 5743 | return res; 5744 | } 5745 | 5746 | /*! 5747 | * Simple equality for flat iterable objects 5748 | * such as Arrays or Node.js buffers. 5749 | * 5750 | * @param {Iterable} a 5751 | * @param {Iterable} b 5752 | * @return {Boolean} result 5753 | */ 5754 | 5755 | function iterableEqual(a, b) { 5756 | if (a.length !== b.length) return false; 5757 | 5758 | var i = 0; 5759 | var match = true; 5760 | 5761 | for (; i < a.length; i++) { 5762 | if (a[i] !== b[i]) { 5763 | match = false; 5764 | break; 5765 | } 5766 | } 5767 | 5768 | return match; 5769 | } 5770 | 5771 | /*! 5772 | * Extension to `iterableEqual` specifically 5773 | * for Node.js Buffers. 5774 | * 5775 | * @param {Buffer} a 5776 | * @param {Mixed} b 5777 | * @return {Boolean} result 5778 | */ 5779 | 5780 | function bufferEqual(a, b) { 5781 | if (!Buffer.isBuffer(b)) return false; 5782 | return iterableEqual(a, b); 5783 | } 5784 | 5785 | /*! 5786 | * Block for `objectEqual` ensuring non-existing 5787 | * values don't get in. 5788 | * 5789 | * @param {Mixed} object 5790 | * @return {Boolean} result 5791 | */ 5792 | 5793 | function isValue(a) { 5794 | return a !== null && a !== undefined; 5795 | } 5796 | 5797 | /*! 5798 | * Recursively check the equality of two objects. 5799 | * Once basic sameness has been established it will 5800 | * defer to `deepEqual` for each enumerable key 5801 | * in the object. 5802 | * 5803 | * @param {Mixed} a 5804 | * @param {Mixed} b 5805 | * @return {Boolean} result 5806 | */ 5807 | 5808 | function objectEqual(a, b, m) { 5809 | if (!isValue(a) || !isValue(b)) { 5810 | return false; 5811 | } 5812 | 5813 | if (a.prototype !== b.prototype) { 5814 | return false; 5815 | } 5816 | 5817 | var i; 5818 | if (m) { 5819 | for (i = 0; i < m.length; i++) { 5820 | if ((m[i][0] === a && m[i][1] === b) 5821 | || (m[i][0] === b && m[i][1] === a)) { 5822 | return true; 5823 | } 5824 | } 5825 | } else { 5826 | m = []; 5827 | } 5828 | 5829 | try { 5830 | var ka = enumerable(a); 5831 | var kb = enumerable(b); 5832 | } catch (ex) { 5833 | return false; 5834 | } 5835 | 5836 | ka.sort(); 5837 | kb.sort(); 5838 | 5839 | if (!iterableEqual(ka, kb)) { 5840 | return false; 5841 | } 5842 | 5843 | m.push([ a, b ]); 5844 | 5845 | var key; 5846 | for (i = ka.length - 1; i >= 0; i--) { 5847 | key = ka[i]; 5848 | if (!deepEqual(a[key], b[key], m)) { 5849 | return false; 5850 | } 5851 | } 5852 | 5853 | return true; 5854 | } 5855 | 5856 | },{"buffer":undefined,"type-detect":33}],33:[function(require,module,exports){ 5857 | module.exports = require('./lib/type'); 5858 | 5859 | },{"./lib/type":34}],34:[function(require,module,exports){ 5860 | /*! 5861 | * type-detect 5862 | * Copyright(c) 2013 jake luer 5863 | * MIT Licensed 5864 | */ 5865 | 5866 | /*! 5867 | * Primary Exports 5868 | */ 5869 | 5870 | var exports = module.exports = getType; 5871 | 5872 | /*! 5873 | * Detectable javascript natives 5874 | */ 5875 | 5876 | var natives = { 5877 | '[object Array]': 'array' 5878 | , '[object RegExp]': 'regexp' 5879 | , '[object Function]': 'function' 5880 | , '[object Arguments]': 'arguments' 5881 | , '[object Date]': 'date' 5882 | }; 5883 | 5884 | /** 5885 | * ### typeOf (obj) 5886 | * 5887 | * Use several different techniques to determine 5888 | * the type of object being tested. 5889 | * 5890 | * 5891 | * @param {Mixed} object 5892 | * @return {String} object type 5893 | * @api public 5894 | */ 5895 | 5896 | function getType (obj) { 5897 | var str = Object.prototype.toString.call(obj); 5898 | if (natives[str]) return natives[str]; 5899 | if (obj === null) return 'null'; 5900 | if (obj === undefined) return 'undefined'; 5901 | if (obj === Object(obj)) return 'object'; 5902 | return typeof obj; 5903 | } 5904 | 5905 | exports.Library = Library; 5906 | 5907 | /** 5908 | * ### Library 5909 | * 5910 | * Create a repository for custom type detection. 5911 | * 5912 | * ```js 5913 | * var lib = new type.Library; 5914 | * ``` 5915 | * 5916 | */ 5917 | 5918 | function Library () { 5919 | this.tests = {}; 5920 | } 5921 | 5922 | /** 5923 | * #### .of (obj) 5924 | * 5925 | * Expose replacement `typeof` detection to the library. 5926 | * 5927 | * ```js 5928 | * if ('string' === lib.of('hello world')) { 5929 | * // ... 5930 | * } 5931 | * ``` 5932 | * 5933 | * @param {Mixed} object to test 5934 | * @return {String} type 5935 | */ 5936 | 5937 | Library.prototype.of = getType; 5938 | 5939 | /** 5940 | * #### .define (type, test) 5941 | * 5942 | * Add a test to for the `.test()` assertion. 5943 | * 5944 | * Can be defined as a regular expression: 5945 | * 5946 | * ```js 5947 | * lib.define('int', /^[0-9]+$/); 5948 | * ``` 5949 | * 5950 | * ... or as a function: 5951 | * 5952 | * ```js 5953 | * lib.define('bln', function (obj) { 5954 | * if ('boolean' === lib.of(obj)) return true; 5955 | * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; 5956 | * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); 5957 | * return !! ~blns.indexOf(obj); 5958 | * }); 5959 | * ``` 5960 | * 5961 | * @param {String} type 5962 | * @param {RegExp|Function} test 5963 | * @api public 5964 | */ 5965 | 5966 | Library.prototype.define = function (type, test) { 5967 | if (arguments.length === 1) return this.tests[type]; 5968 | this.tests[type] = test; 5969 | return this; 5970 | }; 5971 | 5972 | /** 5973 | * #### .test (obj, test) 5974 | * 5975 | * Assert that an object is of type. Will first 5976 | * check natives, and if that does not pass it will 5977 | * use the user defined custom tests. 5978 | * 5979 | * ```js 5980 | * assert(lib.test('1', 'int')); 5981 | * assert(lib.test('yes', 'bln')); 5982 | * ``` 5983 | * 5984 | * @param {Mixed} object 5985 | * @param {String} type 5986 | * @return {Boolean} result 5987 | * @api public 5988 | */ 5989 | 5990 | Library.prototype.test = function (obj, type) { 5991 | if (type === getType(obj)) return true; 5992 | var test = this.tests[type]; 5993 | 5994 | if (test && 'regexp' === getType(test)) { 5995 | return test.test(obj); 5996 | } else if (test && 'function' === getType(test)) { 5997 | return test(obj); 5998 | } else { 5999 | throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); 6000 | } 6001 | }; 6002 | 6003 | },{}],35:[function(require,module,exports){ 6004 | arguments[4][33][0].apply(exports,arguments) 6005 | },{"./lib/type":36,"dup":33}],36:[function(require,module,exports){ 6006 | /*! 6007 | * type-detect 6008 | * Copyright(c) 2013 jake luer 6009 | * MIT Licensed 6010 | */ 6011 | 6012 | /*! 6013 | * Primary Exports 6014 | */ 6015 | 6016 | var exports = module.exports = getType; 6017 | 6018 | /** 6019 | * ### typeOf (obj) 6020 | * 6021 | * Use several different techniques to determine 6022 | * the type of object being tested. 6023 | * 6024 | * 6025 | * @param {Mixed} object 6026 | * @return {String} object type 6027 | * @api public 6028 | */ 6029 | var objectTypeRegexp = /^\[object (.*)\]$/; 6030 | 6031 | function getType(obj) { 6032 | var type = Object.prototype.toString.call(obj).match(objectTypeRegexp)[1].toLowerCase(); 6033 | // Let "new String('')" return 'object' 6034 | if (typeof Promise === 'function' && obj instanceof Promise) return 'promise'; 6035 | // PhantomJS has type "DOMWindow" for null 6036 | if (obj === null) return 'null'; 6037 | // PhantomJS has type "DOMWindow" for undefined 6038 | if (obj === undefined) return 'undefined'; 6039 | return type; 6040 | } 6041 | 6042 | exports.Library = Library; 6043 | 6044 | /** 6045 | * ### Library 6046 | * 6047 | * Create a repository for custom type detection. 6048 | * 6049 | * ```js 6050 | * var lib = new type.Library; 6051 | * ``` 6052 | * 6053 | */ 6054 | 6055 | function Library() { 6056 | if (!(this instanceof Library)) return new Library(); 6057 | this.tests = {}; 6058 | } 6059 | 6060 | /** 6061 | * #### .of (obj) 6062 | * 6063 | * Expose replacement `typeof` detection to the library. 6064 | * 6065 | * ```js 6066 | * if ('string' === lib.of('hello world')) { 6067 | * // ... 6068 | * } 6069 | * ``` 6070 | * 6071 | * @param {Mixed} object to test 6072 | * @return {String} type 6073 | */ 6074 | 6075 | Library.prototype.of = getType; 6076 | 6077 | /** 6078 | * #### .define (type, test) 6079 | * 6080 | * Add a test to for the `.test()` assertion. 6081 | * 6082 | * Can be defined as a regular expression: 6083 | * 6084 | * ```js 6085 | * lib.define('int', /^[0-9]+$/); 6086 | * ``` 6087 | * 6088 | * ... or as a function: 6089 | * 6090 | * ```js 6091 | * lib.define('bln', function (obj) { 6092 | * if ('boolean' === lib.of(obj)) return true; 6093 | * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; 6094 | * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); 6095 | * return !! ~blns.indexOf(obj); 6096 | * }); 6097 | * ``` 6098 | * 6099 | * @param {String} type 6100 | * @param {RegExp|Function} test 6101 | * @api public 6102 | */ 6103 | 6104 | Library.prototype.define = function(type, test) { 6105 | if (arguments.length === 1) return this.tests[type]; 6106 | this.tests[type] = test; 6107 | return this; 6108 | }; 6109 | 6110 | /** 6111 | * #### .test (obj, test) 6112 | * 6113 | * Assert that an object is of type. Will first 6114 | * check natives, and if that does not pass it will 6115 | * use the user defined custom tests. 6116 | * 6117 | * ```js 6118 | * assert(lib.test('1', 'int')); 6119 | * assert(lib.test('yes', 'bln')); 6120 | * ``` 6121 | * 6122 | * @param {Mixed} object 6123 | * @param {String} type 6124 | * @return {Boolean} result 6125 | * @api public 6126 | */ 6127 | 6128 | Library.prototype.test = function(obj, type) { 6129 | if (type === getType(obj)) return true; 6130 | var test = this.tests[type]; 6131 | 6132 | if (test && 'regexp' === getType(test)) { 6133 | return test.test(obj); 6134 | } else if (test && 'function' === getType(test)) { 6135 | return test(obj); 6136 | } else { 6137 | throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); 6138 | } 6139 | }; 6140 | 6141 | },{}]},{},[1])(1) 6142 | }); --------------------------------------------------------------------------------