├── index.js ├── makefile ├── .jshintrc ├── package.json ├── .gitignore ├── LICENSE ├── lib └── x-error.js ├── README.md └── test └── basic.js /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/x-error') -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | test: 2 | ./node_modules/.bin/mocha --reporter spec 3 | 4 | jshint: 5 | ./node_modules/.bin/jshint lib 6 | 7 | .PHONY: test -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise":false, 3 | "boss":true, 4 | "expr":true, 5 | "camelcase":false, 6 | "curly":false, 7 | "eqeqeq":true, 8 | "freeze":true, 9 | "immed":true, 10 | "indent":2, 11 | "latedef":"nofunc", 12 | "laxbreak":true, 13 | "laxcomma":true, 14 | "newcap":true, 15 | "noarg":true, 16 | "node":true, 17 | "strict":true, 18 | "trailing":true, 19 | "undef":true, 20 | "esnext":false, 21 | "sub":true, 22 | 23 | /* questionable */ 24 | "loopfunc":true, 25 | 26 | "predef": [ 27 | "alert", 28 | "describe", 29 | "it", 30 | "before", 31 | "beforeEach", 32 | "after", 33 | "afterEach" 34 | ] 35 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "x-error", 3 | "version": "0.0.10", 4 | "description": "Utility for creating and extending error objects", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "make" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/yzarubin/x-error.git" 12 | }, 13 | "devDependencies": { 14 | "chai": "~1.9.0", 15 | "mocha": "~1.17.0", 16 | "jshint": ">=2.4.2" 17 | }, 18 | "keywords": [ 19 | "error" 20 | ], 21 | "author": "Yuri Zarubin", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/yzarubin/x-error/issues" 25 | }, 26 | "homepage": "https://github.com/yzarubin/x-error" 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yuri Zarubin 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 | 23 | -------------------------------------------------------------------------------- /lib/x-error.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (function() { 4 | 5 | var isArrayOrIsNotObject = function(x) { 6 | return x instanceof Array || !(typeof x === 'object' && x instanceof Object) || false; 7 | }; 8 | 9 | var XError = function XError() { 10 | 11 | // called without new 12 | if (this === undefined) { 13 | return new XError(arguments[0], arguments[1], arguments[2]); 14 | } 15 | 16 | var code = (typeof arguments[0] === 'number') ? arguments[0] : undefined; 17 | 18 | var message = ((typeof arguments[0] !== 'undefined' && typeof code === 'undefined') 19 | && isArrayOrIsNotObject(arguments[0]) && String(arguments[0]) || undefined) 20 | || (typeof arguments[1] !== 'undefined' && isArrayOrIsNotObject(arguments[1]) 21 | && String(arguments[1]) || undefined); 22 | 23 | var data = arguments[0] !== 'undefined' 24 | && (!isArrayOrIsNotObject(arguments[0]) && arguments[0] 25 | || !isArrayOrIsNotObject(arguments[1]) && arguments[1] 26 | || !isArrayOrIsNotObject(arguments[2]) && arguments[2]) 27 | || {}; 28 | 29 | this.setCode(code); 30 | this.setMessage(message); 31 | 32 | // avoid polluting the stack 33 | Error.captureStackTrace(this, XError); 34 | 35 | // modify stack's getter and setter methods to make the property enumerable by JSON.stringify() 36 | // activate the getter 37 | var _stack = this.stack; 38 | this.__defineGetter__('stack', function() { return _stack; }); 39 | this.__defineSetter__('stack', function(stack) { _stack = stack; }); 40 | 41 | this.extend(data); 42 | 43 | return this; 44 | }; 45 | 46 | // inherit Error 47 | XError.prototype = new Error(); 48 | 49 | XError.prototype.setCode = XError.prototype.c = function(code) { 50 | if (typeof code !== 'undefined') { this.code = code; } 51 | return this; 52 | }; 53 | 54 | XError.prototype.setMessage = XError.prototype.m = function(message) { 55 | if (typeof message !== 'undefined') { this.message = String(message); } 56 | return this; 57 | }; 58 | 59 | XError.prototype.setSeverity = XError.prototype.s = function(severity) { 60 | if (typeof severity !== 'undefined') { this.severity = severity; } 61 | return this; 62 | }; 63 | 64 | XError.prototype.setHttpCode = XError.prototype.hc = function(httpCode) { 65 | if (typeof httpCode === 'number') { this.httpCode = httpCode; } 66 | return this; 67 | }; 68 | 69 | XError.prototype.setHttpResponse = XError.prototype.hr = function(httpResponse) { 70 | if (typeof httpResponse !== 'undefined') { this.httpResponse = httpResponse; } 71 | return this; 72 | }; 73 | 74 | XError.prototype.extend = XError.prototype.ex = function(source) { 75 | if (source instanceof Error) { 76 | // hidden methods will not be enumerated, so check for them manually 77 | source.message && (this.message = source.message); 78 | source.stack && (this.stack = source.stack); 79 | } 80 | 81 | source = source || {}; 82 | for (var key in source) { 83 | this[key] = source[key]; 84 | } 85 | return this; 86 | }; 87 | 88 | XError.prototype.debug = XError.prototype.d = function(){ 89 | var args = Array.prototype.slice.call(arguments) 90 | , self = this; 91 | 92 | if (this._debug == undefined) this._debug = []; 93 | 94 | args.forEach(function(data){ 95 | if (self._debug instanceof Array === true) self._debug.push(data); 96 | }); 97 | 98 | return this; 99 | }; 100 | 101 | return XError; 102 | })(); 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | X-Error 2 | ======= 3 | Better JavaScript errors 4 | 5 | X-Error expands the error handling capabilities of server-side applications by inhereting and extending the vanilla Error object. 6 | 7 | # Installation 8 | 9 | ``` 10 | npm install x-error 11 | ``` 12 | 13 | Then: 14 | 15 | ```js 16 | var XError = require('x-error'); 17 | ``` 18 | # Usage 19 | 20 | ## XError([code], [message], [data]) 21 | X-Error behaves the same way an Error would, `new XError('foo')` is identical to `new Error('foo')`. The key difference is that XError provides additional constructor parameters and convenience methods. 22 | 23 | You can instantiate X-Error with or without the new keyword, it returns an instance of XError in either case. 24 | 25 | Call the constructor with an object to extend its properties: 26 | 27 | ```js 28 | new XError('hello world', { foo: 'bar', a: 'b' }); 29 | ``` 30 | Resulting in: 31 | ``` 32 | { 33 | message: 'hello world', 34 | foo: 'bar', 35 | a: 'b', 36 | stack: '...' 37 | } 38 | ``` 39 | 40 | Which is equivalent to calling extend directly: 41 | 42 | ```js 43 | new XError('hello world').extend({ foo: 'bar', a: 'b' }); 44 | ``` 45 | 46 | And: 47 | 48 | ```js 49 | new XError().setMessage('hello world').extend({ foo: 'bar', a: 'b' }); 50 | ``` 51 | 52 | Extend instances of Error/XError: 53 | 54 | ```js 55 | var vanillaError = new Error('hello'); 56 | var e = new XError(vanillaError).extend({ to: 'world' }); 57 | 58 | e.message === vanillaError.message; // true 59 | e.stack === vanillaError.stack; // true 60 | e.to === 'world'; // true 61 | 62 | var e2 = new XError(e).extend({ message: 'hi' }); 63 | 64 | e2.message === vanillaError.message; // false 65 | e2.stack === vanillaError.stack; // true 66 | e2.to === 'world'; // true 67 | ``` 68 | 69 | ### Enumeration 70 | 71 | Enumerate errors with a code by passing a number as the first argument. 72 | ```js 73 | new XError(3000, 'hello world', { foo: 'bar' }); 74 | /* 75 | { 76 | code: 3000, 77 | message: 'hello world', 78 | foo: 'bar', 79 | stack: 'Error: hello world ...' 80 | } 81 | */ 82 | ``` 83 | 84 | ### HTTP status code & response 85 | 86 | One of the most important X-Error features is being able to describe how to handle Errors within the context of HTTP responses. 87 | 88 | e.g. using callbacks 89 | 90 | ```js 91 | User.find(function(err, user) { 92 | if (err) { 93 | return callback(XError(err) 94 | .setHttpCode(400) 95 | .setHttpResponse('Internal error')); 96 | } 97 | if (!user) { 98 | return callback(XError('Unable to find user') 99 | .setHttpCode(400) 100 | .setHttpResponse('Invalid input')); 101 | } 102 | }); 103 | ``` 104 | 105 | Then in your app's route controller/handler: 106 | 107 | ```js 108 | FooService.doStuff(function(err, result) { 109 | if (err) return res.json(err.httpCode, err.httpResponse); 110 | res.json(200, result); 111 | }); 112 | ``` 113 | 114 | Use shorthands for more terse API calls: 115 | 116 | ```js 117 | new XError('Server blew up').hc(500).hr('Internal error'); 118 | ``` 119 | 120 | See API for the complete list. 121 | 122 | ### X-Error with Promises 123 | 124 | Combine X-Error with promises to create powerful error handlers. 125 | 126 | Take a function that returns a promise: 127 | 128 | ```js 129 | function createFoo() { 130 | return User.find(userId) 131 | .then(function(user){ 132 | if (!user) throw XError().hc(400).hr('Invalid input'); 133 | return Foo.create({ user: user._id }); 134 | }) 135 | .catch(function(e) { 136 | // wrap and re-throw 137 | throw XError(e).setSeverity('critical'); 138 | }); 139 | } 140 | ``` 141 | 142 | Create an error handler as a function of the ```res``` object: 143 | 144 | ```js 145 | function createErrHandler(res){ 146 | return function(e) { 147 | // do some logging depending on severity 148 | e.severity === 'critical' && logError(e); 149 | 150 | res.status(e.httpCode || 500) 151 | .send(e.httpResponse || 'Internal error'); 152 | 153 | }; 154 | } 155 | ``` 156 | 157 | Call createErrHandler at the end of the promise chain inside your API's route handler 158 | 159 | ```js 160 | // Foo API 161 | function create(req, res, next) { 162 | createFoo.then(function(foo) { 163 | res.status(200).json(foo); 164 | }) 165 | .catch(createErrHandler(req, res)); 166 | } 167 | ``` 168 | 169 | ### Better JSON support 170 | 171 | X-Error is co-operates with `JSON.stringify()` by properly enumerating over stack and message properties. This is in contrast with the vanilla Error object which serializes into ```"{}"```. 172 | 173 | ### Better debugging 174 | 175 | Use the built-in ```debug()``` method to better diagnose your applications: 176 | 177 | ```js 178 | function getStuff(id) { 179 | Stuff.find({ id: id }) 180 | .then(function(stuff){ 181 | if (!stuff) throw XError().debug(id).hr('oops').hc(400); 182 | return stuff; 183 | }); 184 | } 185 | 186 | function doThings(req, res) { 187 | getStuff(req.id) 188 | .then(function(stuff){ 189 | res.status(200).json(stuff); 190 | }) 191 | .catch(function(err){ 192 | err.debug(req.body); 193 | 194 | // err._debug is now an array containing two items 195 | // which you can log, or do whatever else 196 | logErr(err._debug); 197 | 198 | res.status(err.httpCode || 500) 199 | .send(err.httpResponse || 'Internal error'); 200 | }); 201 | } 202 | ``` 203 | 204 | # API 205 | 206 | ### Convenience methods 207 | 208 | | Method | Short Name | 209 | | ------------------------ | -------------- | 210 | | `XError.setCode` | `XError.c` | 211 | | `XError.setMessage` | `XError.m` | 212 | | `XError.setSeverity` | `XError.s` | 213 | | `XError.setHttpCode` | `XError.hc` | 214 | | `XError.setHttpResponse` | `XError.hr` | 215 | | `XError.extend` | `XError.ex` | 216 | | `XError.debug` | `XError.d` | 217 | 218 | # Extensible 219 | 220 | Since X-Error is a plain JavaScript constructor you can easily extend its prototype to add custom methods for your application: 221 | 222 | ```js 223 | var XError = require('x-error'); 224 | 225 | XError.prototype.setPriority = function(priority) { 226 | this.priority = priority; 227 | return this; 228 | }; 229 | 230 | var e = XError('Update failed') 231 | .setPriority('high') 232 | .debug({ accountId: '123' }); 233 | 234 | ``` 235 | 236 | # License 237 | Standard MIT License 238 | -------------------------------------------------------------------------------- /test/basic.js: -------------------------------------------------------------------------------- 1 | var XError = require('./../lib/x-error') 2 | , chai = require('chai') 3 | , expect = chai.expect 4 | , should = chai.should(); 5 | 6 | describe('XError tests', function () { 7 | it('should be an instance of Error', function () { 8 | var e = new XError(); 9 | expect(e).to.be.an.instanceof(Error); 10 | }); 11 | 12 | it('should be an instance of XError', function () { 13 | var e = new XError(); 14 | expect(e).to.be.an.instanceof(XError); 15 | }); 16 | 17 | it('should generate the stack correctly', function () { 18 | var e = new XError(); 19 | expect(typeof e.stack === 'string').to.be.true; 20 | }); 21 | 22 | it('should instantiate with arguments correctly #1', function () { 23 | var e = new XError(5); 24 | expect(typeof e.stack === 'string').to.be.true; 25 | expect(e.code).to.equal(5); 26 | }); 27 | 28 | it('should instantiate with arguments correctly #2', function () { 29 | var e = new XError(5, 'hello'); 30 | expect(typeof e.stack === 'string').to.be.true; 31 | expect(e.code).to.equal(5); 32 | expect(e.message).to.equal('hello'); 33 | }); 34 | 35 | it('should instantiate with arguments correctly #3', function () { 36 | var e = new XError(5, 'hello', {test: 123}); 37 | expect(typeof e.stack === 'string').to.be.true; 38 | expect(e.code).to.equal(5); 39 | expect(e.message).to.equal('hello'); 40 | expect(e.test).to.equal(123); 41 | }); 42 | 43 | it('should instantiate with arguments correctly #4', function () { 44 | var e = new XError(5, 'hello').extend({test:123}); 45 | expect(typeof e.stack === 'string').to.be.true; 46 | expect(e.code).to.equal(5); 47 | expect(e.message).to.equal('hello'); 48 | expect(e.test).to.equal(123); 49 | }); 50 | 51 | it('should instantiate with arguments correctly #5', function () { 52 | var e = new XError('hello', {test: 123}); 53 | expect(typeof e.stack === 'string').to.be.true; 54 | expect(e.message).to.equal('hello'); 55 | expect(e.test).to.equal(123); 56 | }); 57 | 58 | it('should instantiate with arguments correctly #6', function () { 59 | var e = new XError({test: 123}); 60 | expect(typeof e.stack === 'string').to.be.true; 61 | expect(e.test).to.equal(123); 62 | }); 63 | 64 | it('should instantiate with arguments correctly #7', function () { 65 | var e = new XError(99); 66 | expect(typeof e.stack === 'string').to.be.true; 67 | expect(e.code).to.equal(99); 68 | }); 69 | 70 | it('should instantiate with arguments correctly #8', function () { 71 | var e = new XError(5,99); 72 | expect(typeof e.stack === 'string').to.be.true; 73 | expect(e.code).to.equal(5); 74 | expect(e.message).to.equal("99"); 75 | }); 76 | 77 | it('should instantiate with arguments correctly #9', function () { 78 | var e = new XError(5,'hello'); 79 | expect(typeof e.stack === 'string').to.be.true; 80 | expect(e.code).to.equal(5); 81 | expect(e.message).to.equal('hello'); 82 | }); 83 | 84 | it('should instantiate with arguments correctly #10', function () { 85 | var e = new XError(5,{test: 123}); 86 | expect(typeof e.stack === 'string').to.be.true; 87 | expect(e.code).to.equal(5); 88 | expect(e.test).to.equal(123); 89 | }); 90 | 91 | it('should instantiate with arguments correctly #11', function () { 92 | var e = new XError(1, 2, 3); 93 | expect(typeof e.stack === 'string').to.be.true; 94 | expect(e.code).to.equal(1); 95 | expect(e.message).to.equal('2'); 96 | }); 97 | 98 | it('should instantiate with null correctly #1', function () { 99 | var e = new XError(1, null, 3); 100 | expect(typeof e.stack === 'string').to.be.true; 101 | expect(e.code).to.equal(1); 102 | expect(e.message).to.equal('null'); 103 | }); 104 | 105 | it('should instantiate with null correctly #2', function () { 106 | var e = new XError(null, 'foo', {foo: 'bar'}); 107 | expect(typeof e.stack === 'string').to.be.true; 108 | expect(e.code).to.equal(undefined); 109 | expect(e.message).to.equal('null'); 110 | expect(e.foo).to.equal('bar'); 111 | }); 112 | 113 | it('should instantiate with null correctly #3', function () { 114 | var e = new XError(null, 'foo', {foo: 'bar'}); 115 | expect(typeof e.stack === 'string').to.be.true; 116 | expect(e.code).to.equal(undefined); 117 | expect(e.message).to.equal('null'); 118 | expect(e.foo).to.equal('bar'); 119 | }); 120 | 121 | it('should instantiate with arrays correctly #1', function () { 122 | var e = new XError([1,2]); 123 | expect(typeof e.stack === 'string').to.be.true; 124 | expect(e.message).to.equal('1,2'); 125 | }); 126 | 127 | it('should instantiate with arrays correctly #2', function () { 128 | var e = new XError([1,2], [2,3], {foo: 'bar'}); 129 | expect(typeof e.stack === 'string').to.be.true; 130 | expect(e.message).to.equal('1,2'); 131 | expect(e.foo).to.equal('bar'); 132 | }); 133 | 134 | it('should instantiate with arrays correctly #3', function () { 135 | var e = new XError( {foo: 'bar'}, [1,2], [2,3]); 136 | expect(typeof e.stack === 'string').to.be.true; 137 | expect(e.message).to.equal('1,2'); 138 | expect(e.foo).to.equal('bar'); 139 | }); 140 | 141 | it('should instantiate with arrays correctly #4', function () { 142 | var e = new XError("1", {foo: 'bar'}, {foo: 'baz'}); 143 | expect(typeof e.stack === 'string').to.be.true; 144 | expect(e.message).to.equal('1'); 145 | expect(e.foo).to.equal('bar'); 146 | }); 147 | 148 | it('should instantiate with a function correctly #1', function () { 149 | var e = new Error(function(){ 1+1=2; }); 150 | var ex = new XError(function(){ 1+1=2; }); 151 | expect(typeof e.stack === 'string').to.be.true; 152 | expect(e.message).to.equal(ex.message); 153 | }); 154 | 155 | it('should instantiate with a function correctly #2', function () { 156 | var e = new Error(function(){ 1+1=2; }); 157 | var ex = new XError(function(){ 1+1=2; }, { foo: 'bar' }); 158 | expect(typeof e.stack === 'string').to.be.true; 159 | expect(e.message).to.equal(ex.message); 160 | expect(ex.foo).to.equal('bar'); 161 | }); 162 | 163 | it('should instantiate with out of order arguments', function () { 164 | var e = new XError({foo: 'bar'}, 'foobar'); 165 | expect(typeof e.stack === 'string').to.be.true; 166 | expect(e.message).to.equal('foobar'); 167 | expect(e.foo).to.equal('bar'); 168 | }); 169 | 170 | it('should extend error with new properties', function () { 171 | var e = new XError(); 172 | expect(typeof e.stack === 'string').to.be.true; 173 | expect(e.data).to.equal(undefined); 174 | e.extend({test:123}); 175 | expect(e.test).to.equal(123); 176 | }); 177 | it('should set httpCode', function () { 178 | var e = new XError(); 179 | expect(typeof e.stack === 'string').to.be.true; 180 | e.setHttpCode(500); 181 | expect(e.httpCode).to.equal(500); 182 | }); 183 | 184 | it('should not set httpCode', function () { 185 | var e = new XError(); 186 | expect(typeof e.stack === 'string').to.be.true; 187 | e.setHttpCode('500'); 188 | expect(e.httpCode).to.equal(undefined); 189 | }); 190 | 191 | it('should set httpResponse', function () { 192 | var e = new XError(); 193 | expect(typeof e.stack === 'string').to.be.true; 194 | e.setHttpResponse('an error has occured'); 195 | expect(e.httpResponse).to.equal('an error has occured'); 196 | }); 197 | 198 | it('should be extended by the Error object', function () { 199 | var e = new Error('message'); 200 | var ex = new XError(); 201 | ex.extend(e).extend({test:123}); 202 | 203 | expect(typeof e.stack === 'string').to.be.true; 204 | expect(ex.message).to.equal('message'); 205 | expect(ex.stack).to.equal(e.stack); 206 | expect(ex.test).to.equal(123); 207 | }); 208 | 209 | it('stack should be included in JSON.stringify()', function () { 210 | var e = new Error('message'); 211 | var ex = new XError().extend(e); 212 | 213 | expect(JSON.parse(JSON.stringify(ex)).stack.length).to.be.gt(10); 214 | expect(JSON.parse(JSON.stringify(ex)).message).to.equal('message'); 215 | expect(JSON.parse(JSON.stringify(e)).stack).to.equal(undefined); 216 | }); 217 | 218 | it('stacks should be equal', function () { 219 | var e = new Error('message'); 220 | var ex = new XError('message'); 221 | 222 | expect(e.stack.substring(0,30)).to.equal(ex.stack.substring(0,30)); 223 | }); 224 | 225 | it('should chain correctly #1', function () { 226 | var ex = new XError().c(500).m('error').extend({a:'b'}).s(10).hc(500).hr('error has occured'); 227 | var ex2 = new XError(500, 'error', {a:'b'}).s(10).hc(500).hr('error has occured'); 228 | 229 | expect(ex.code).to.equal(500); 230 | expect(ex.message).to.equal('error'); 231 | expect(ex.a).to.equal('b'); 232 | expect(ex.severity).to.equal(10); 233 | expect(ex.httpCode).to.equal(500); 234 | expect(ex.httpResponse).to.equal('error has occured'); 235 | 236 | expect(ex2.code).to.equal(500); 237 | expect(ex2.message).to.equal('error'); 238 | expect(ex2.a).to.equal('b'); 239 | expect(ex2.severity).to.equal(10); 240 | expect(ex2.httpCode).to.equal(500); 241 | expect(ex2.httpResponse).to.equal('error has occured'); 242 | }); 243 | 244 | it('should populate the debug array', function(){ 245 | var e = new XError('message').debug('foo').debug(['bar']).debug({foo:'bar'}); 246 | expect(typeof e.stack === 'string').to.be.true; 247 | expect(e.message).to.equal('message'); 248 | expect(e._debug[0]).to.equal('foo'); 249 | expect(e._debug[1][0]).to.equal('bar'); 250 | expect(e._debug[2].foo).to.equal('bar'); 251 | }); 252 | 253 | it('should populate the debug array with multiple arguments', function(){ 254 | var e = new XError('message').debug('foo', ['bar'], {foo:'bar'}); 255 | expect(typeof e.stack === 'string').to.be.true; 256 | expect(e.message).to.equal('message'); 257 | expect(e._debug[0]).to.equal('foo'); 258 | expect(e._debug[1][0]).to.equal('bar'); 259 | expect(e._debug[2].foo).to.equal('bar'); 260 | }); 261 | 262 | it('should instantiate correctly with Error instance as the parameter #1', function(){ 263 | var e = new Error('foobar'); 264 | var ex = new XError(e); 265 | expect(ex.message).to.equal('foobar'); 266 | expect(e.stack).to.equal(ex.stack); 267 | 268 | }); 269 | 270 | it('should instantiate correctly with Error instance as the parameter #2', function(){ 271 | var e = new Error('foobar'); 272 | var ex = new XError(1, 'hello', e); 273 | expect(ex.message).to.equal('foobar'); 274 | expect(e.stack).to.equal(ex.stack); 275 | expect(ex.code).to.equal(1); 276 | 277 | }); 278 | 279 | it('should instantiate correctly with XError instance as the parameter', function(){ 280 | var ex = new XError('foobar').setHttpCode(200).setHttpResponse('baz').debug('test').debug('test2'); 281 | var ex2 = new XError(ex); 282 | expect(ex.message).to.equal('foobar'); 283 | expect(ex2.stack).to.equal(ex.stack); 284 | expect(ex2.httpResponse).to.equal('baz'); 285 | expect(ex2.httpCode).to.equal(200); 286 | expect(ex2._debug[0]).to.equal('test'); 287 | expect(ex2._debug[1]).to.equal('test2'); 288 | }); 289 | 290 | it('should instantiate correctly without calling new', function(){ 291 | var ex = XError(1,'foo', {foo: 'bar'}); 292 | expect(ex.message).to.equal('foo'); 293 | expect(ex.code).to.equal(1); 294 | expect(ex.foo).to.equal('bar'); 295 | }); 296 | 297 | it('should extend prototype correctly', function(){ 298 | XError.prototype.setPriority = function(priority) { 299 | this.priority = priority; 300 | return this; 301 | }; 302 | 303 | var ex = new XError(1, 'foo', {foo: 'bar'}).setPriority('top').debug('test'); 304 | expect(ex.message).to.equal('foo'); 305 | expect(ex.code).to.equal(1); 306 | expect(ex.foo).to.equal('bar'); 307 | expect(ex._debug[0]).to.equal('test'); 308 | expect(ex.priority).to.equal('top'); 309 | }); 310 | }); --------------------------------------------------------------------------------