Comparing version 7.2.1 to 10.0.0
## Migration | ||
## Version 10 | ||
The 10th version is a complete rewrite. Check out the `v7.x` | ||
branch for the older implementation. | ||
## Version 7 | ||
@@ -4,0 +9,0 @@ |
{ | ||
"name": "error", | ||
"version": "7.2.1", | ||
"version": "10.0.0", | ||
"description": "Custom errors", | ||
@@ -19,7 +19,6 @@ "keywords": [], | ||
}, | ||
"dependencies": { | ||
"string-template": "~0.2.1" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"istanbul": "0.3.13", | ||
"multidep": "2.0.2", | ||
"tape": "^3.5.0", | ||
@@ -35,3 +34,4 @@ "uber-standard": "3.6.4" | ||
"scripts": { | ||
"lint": "standard -v .", | ||
"multidep": "multidep benchmarks/multidep.json", | ||
"lint": "standard -v", | ||
"test": "npm run lint && node test/index.js", | ||
@@ -38,0 +38,0 @@ "travis-test": "istanbul cover ./test/index.js && ((cat coverage/lcov.info | coveralls) || exit 0)", |
371
README.md
# error | ||
<!-- | ||
[![build status][1]][2] | ||
[![NPM version][3]][4] | ||
[![Coverage Status][5]][6] | ||
[![gemnasium Dependency Status][7]][8] | ||
[![Davis Dependency status][9]][10] | ||
--> | ||
Wrap errors with more context. | ||
<!-- [![browser support][11]][12] --> | ||
## Inspiration | ||
Custom errors | ||
This module is inspired by the go error libraries that have simple | ||
functions for creating & wrapping errors. | ||
## Typed Error | ||
This is based on libraries like [eris][eris] & [pkg/errors][pkg-errors] | ||
## Older version of `error` | ||
If you are looking for the older v7 version of error you should | ||
check [v7.x][7.x] branch | ||
## Motivation | ||
Wrapping errors when bubbling up instead of just doing | ||
`if (err) return cb(err)` allows you to pass more context | ||
up the stack. | ||
Common example include passing along parameters from the DB | ||
read related to the failure or passing along any context | ||
from the user in a HTTP request when doing a failure. | ||
This can give you nice to read messages that include more | ||
information about the failure as it bubbles up. | ||
There is more information about how to handle errors in this | ||
article [Don't just check errors, handle them gracefully][dave] | ||
examples: | ||
```js | ||
var TypedError = require("error/typed") | ||
const { wrapf } = require('error') | ||
var ServerError = TypedError({ | ||
type: 'server.5xx', | ||
message: '{title} server error, status={statusCode}', | ||
title: null, | ||
statusCode: null | ||
}); | ||
var ClientError = TypedError({ | ||
type: 'client.4xx', | ||
message: '{title} client error, status={statusCode}', | ||
title: null, | ||
statusCode: null | ||
}); | ||
function authenticatRequest(req) { | ||
authenticate(req.user, (err) => { | ||
if (err) { | ||
return cb(wrapf('authenticate failed', err)) | ||
} | ||
cb(null) | ||
}) | ||
} | ||
``` | ||
var error = ServerError({ | ||
title:'some title', | ||
or | ||
```js | ||
const { wrapf } = require('error') | ||
function readFile(path, cb) { | ||
fs.open(path, 'r', (err, fd) => { | ||
if (err) { | ||
return cb(wrapf('open failed', err, { path })) | ||
} | ||
const buf = Buffer.alloc(64 * 1024) | ||
fs.read(fd, buf, 0, buf.length, 0, (err) => { | ||
if (err) { | ||
return cb(wrapf('read failed', err, { path })) | ||
} | ||
fs.close(fd, (err) => { | ||
if (err) { | ||
return cb(wrapf('close failed', err, { path })) | ||
} | ||
cb(null, buf) | ||
}) | ||
}) | ||
}) | ||
} | ||
``` | ||
## Structured errors | ||
```js | ||
const { Serror } = require('error') | ||
class ServerError extends Serror {} | ||
class ClientError extends SError {} | ||
const err = ServerError.create( | ||
'{title} server error, status={statusCode}', { | ||
title: 'some title', | ||
statusCode: 500 | ||
}); | ||
var error2 = ClientError({ | ||
} | ||
) | ||
const err2 = ClientError.create( | ||
'{title} client error, status={statusCode}', { | ||
title: 'some title', | ||
statusCode: 404 | ||
}); | ||
} | ||
) | ||
``` | ||
@@ -46,11 +102,6 @@ | ||
```js | ||
var net = require('net'); | ||
var WrappedError = require('error/wrapped'); | ||
const net = require('net'); | ||
const { WError } = require('error') | ||
var ServerListenError = WrappedError({ | ||
message: 'server: {origMessage}', | ||
type: 'server.listen-failed', | ||
requestedPort: null, | ||
host: null | ||
}); | ||
class ServerListenError extends WError {} | ||
@@ -60,10 +111,12 @@ var server = net.createServer(); | ||
server.on('error', function onError(err) { | ||
if (err.code === 'EADDRINUSE') { | ||
throw ServerListenError(err, { | ||
requestedPort: 3000, | ||
host: null | ||
}); | ||
} else { | ||
throw err; | ||
} | ||
if (err.code === 'EADDRINUSE') { | ||
throw ServerListenFailedError.wrap( | ||
'error in server, on port={requestPort}', err, { | ||
requestPort: 3000, | ||
host: null | ||
} | ||
) | ||
} else { | ||
throw err; | ||
} | ||
}); | ||
@@ -74,2 +127,214 @@ | ||
## Comparison to Alternatives. | ||
There are alternative existing libraries for creating typed | ||
and wrapped errors on npm. Here's a quick comparison to some | ||
alternatives. | ||
### [`verror`][verror] | ||
This module takes inspiration from `verror` and adds improvements. | ||
- You can pass extra fields as meta data on the error | ||
- The templating forces dynamic strings to be extra fields. | ||
- Uses ES6 classes for inheritance. This gives your errors unique | ||
class names and makes them show up in heapdumps. | ||
- Has JSON.stringify support | ||
### [`error@7.x`][7.x] | ||
This package used to have a completely different API on the | ||
[7.x][7.x] branch. | ||
- New `error` module uses actual classes instead of dynamically | ||
monkey patching fields onto `new Error()` | ||
- Implementation is more static, previous code was very dynamic | ||
- Simpler API, see the message & properties in one place. | ||
- `wrapf` & `errorf` helpers for less boilerplate. | ||
### Hand writing `Error` sub classes. | ||
You can create your own Error classes by hand. This tends to lead | ||
to 10-20 lines of boilerplate per error which is replace with | ||
one line by using the `error` module; aka | ||
```js | ||
class AccountsServerFailureError extends SError {} | ||
class ConnectionResetError extends WError {} | ||
``` | ||
### [`ono`][ono] | ||
The `ono` package has similar functionality with a different API | ||
- `ono` encourages plain errors instead of custom errors by default | ||
- `error` has zero dependencies | ||
- `error` is only one simple file. `ono` is 10. | ||
- `error` implementation is more static, ono is very dynamic. | ||
## Documentation | ||
This package implements three classes, `WError`; `SError` & | ||
`MultiError` | ||
You are expected to subclass either `WError` or `SError`; | ||
- `SError` stands for `Structured Error`; it's an error base | ||
class for adding informational fields to your error beyond | ||
just having a message. | ||
- `WError` stands for `Wrapped Error`; it's an error base | ||
class for when you are wrapping an existing error with more | ||
information. | ||
The `MultiError` class exists to store an array of errors but | ||
still return a single `Error`; This is useful if your doing | ||
a parallel operation and you want to wait for them all to finish | ||
and do something with all of the failures. | ||
Some utility functions are also exported: | ||
- `findCauseByName`; See if error or any of it's causes is of | ||
the type name. | ||
- `fullStack`; Take a wrapped error and compute a full stack. | ||
- `wrapf`; Utility function to quickly wrap | ||
- `errorf`; Utility function to quickly create an error | ||
### `WError` | ||
Example: | ||
```js | ||
class ServerListenError extends WError {} | ||
ServerListenError.wrap('error in server', err, { | ||
port: 3000 | ||
}) | ||
``` | ||
When using the `WError` class it's recommended to always call | ||
the static `wrap()` method instead of calling the constructor | ||
directly. | ||
### `const werr = new WError(message, cause, info)` | ||
Internal constructor, should pass a `message` string, a `cause` | ||
error and a `info` object (or `null`). | ||
### `WError.wrap(msgTmpl, cause, info)` | ||
`wrap()` method to create error instances. This applies the | ||
[`string-template`][string-template] templating to `msgTmpl` | ||
with `info` as a parameter. | ||
The `cause` parameter must be an `error` | ||
The `info` parameter is an object or `null`. | ||
### `werr.type` | ||
The `type` field is the machine readable type for this error. | ||
Always use `err.type` and never `err.message` when trying to | ||
determine what kind of error it is. | ||
The `type` field is unlikely to change but the `message` field | ||
can change. | ||
### `werr.fullType()` | ||
Calling `fullType` will compute a full type for this error and | ||
any causes that it wraps. This gives you a long `type` string | ||
that's a concat for every wrapped cause. | ||
### `werr.cause()` | ||
Returns the `cause` error. | ||
### `werr.info()` | ||
Returns the `info` object passed on. This is merged with the | ||
info of all `cause` errors up the chain. | ||
### `werr.toJSON()` | ||
The `WError` class implements `toJSON()` so that the JSON | ||
serialization makes sense. | ||
### `WError.fullStack(err)` | ||
This returns a full stack; which is a concatenation of this | ||
stack trace and the stack trace of all causes in the cause chain | ||
### `WError.findCauseByName(err, name)` | ||
Given an err and a name will find if the err or any causes | ||
implement the type of that name. | ||
This allows you to check if a wrapped `ApplicationError` has | ||
for example a `LevelReadError` or `LevelWriteError` in it's cause | ||
chain and handle database errors differently from all other app | ||
errors. | ||
### `SError` | ||
Example: | ||
```js | ||
class LevelReadError extends SError {} | ||
LevelReadError.create('Could not read key: {key}', { | ||
key: '/some/key' | ||
}) | ||
``` | ||
When using the `SError` class it's recommended to always call | ||
the static `create()` method instead of calling the constructor | ||
directly. | ||
### `const serr = new SError(message, info)` | ||
Internal constructor that takes a message string & an info object. | ||
### `SError.create(messageTmpl, info)` | ||
The main way to create error objects, takes a message template | ||
and an info object. | ||
It will use [string-template][string-template] to apply the | ||
template with the `info` object as a parameter. | ||
### `serr.type` | ||
Returns the type field. The `err.type` field is machine readable. | ||
Always use `err.type` & not `err.message` when trying to compare | ||
errors or do any introspection. | ||
The `type` field is unlikely to change but the `message` field | ||
can change. | ||
### `serr.info()` | ||
Returns the info object for this error. | ||
### `serr.toJSON()` | ||
This class can JSON serialize cleanly. | ||
### `MultiError` | ||
Example: | ||
```js | ||
class FanoutError extends MultiError {} | ||
function doStuff (filePath, cb) { | ||
fanoutDiskReads(filePath, (errors, fileContents) => { | ||
if (errors && errors.length > 0) { | ||
const err = FanoutError.errorFromList(errors) | ||
return cb(err) | ||
} | ||
// do stuff with files. | ||
}) | ||
} | ||
``` | ||
When using the `MultiError` class it's recommended to always | ||
call the static `errorFromList` method instead of calling the | ||
constructor directly. | ||
## Installation | ||
@@ -85,13 +350,7 @@ | ||
[1]: https://secure.travis-ci.org/Raynos/error.png | ||
[2]: https://travis-ci.org/Raynos/error | ||
[3]: https://badge.fury.io/js/error.png | ||
[4]: https://badge.fury.io/js/error | ||
[5]: https://coveralls.io/repos/Raynos/error/badge.png | ||
[6]: https://coveralls.io/r/Raynos/error | ||
[7]: https://gemnasium.com/Raynos/error.png | ||
[8]: https://gemnasium.com/Raynos/error | ||
[9]: https://david-dm.org/Raynos/error.png | ||
[10]: https://david-dm.org/Raynos/error | ||
[11]: https://ci.testling.com/Raynos/error.png | ||
[12]: https://ci.testling.com/Raynos/error | ||
[eris]: https://github.com/rotisserie/eris/tree/v0.1.0 | ||
[pkg-errors]: https://github.com/pkg/errors | ||
[7.x]: https://github.com/Raynos/error/tree/v7.x | ||
[string-template]: https://github.com/Matt-Esch/string-template | ||
[verror]: https://github.com/joyent/node-verror | ||
[ono]: https://github.com/JS-DevTools/ono |
@@ -1,4 +0,5 @@ | ||
'use strict'; | ||
'use strict' | ||
require('./typed.js'); | ||
require('./wrapped.js'); | ||
require('./multi.js') | ||
require('./typed.js') | ||
require('./wrapped.js') |
@@ -1,66 +0,85 @@ | ||
'use strict'; | ||
'use strict' | ||
var test = require('tape'); | ||
const test = require('tape') | ||
var TypedError = require('../typed.js'); | ||
const { SError } = require('../index.js') | ||
test('a server error', function t(assert) { | ||
var ServerError = TypedError({ | ||
type: 'server.5xx.error', | ||
message: '{title} server error, status={statusCode}' | ||
}); | ||
test('a server error', function t (assert) { | ||
class Server5XXError extends SError {} | ||
const error = Server5XXError.create( | ||
'{title} server error, status={statusCode}', { | ||
title: 'some title', | ||
statusCode: 500 | ||
} | ||
) | ||
var error = ServerError({ | ||
title: 'some title', | ||
statusCode: 500 | ||
}); | ||
assert.equal(Server5XXError.type, 'server.5xx.error') | ||
assert.equal(ServerError.type, 'server.5xx.error'); | ||
assert.equal(error.type, 'server.5xx.error') | ||
assert.equal(error.info().statusCode, 500) | ||
assert.equal(error.message, 'some title server error, status=500') | ||
assert.equal(error.toString(), | ||
'Server5XXError: some title server error, status=500') | ||
assert.equal(error.type, 'server.5xx.error'); | ||
assert.equal(error.fullType, 'server.5xx.error'); | ||
assert.equal(error.statusCode, 500); | ||
assert.equal(error.message, 'some title server error, status=500'); | ||
assert.equal(error.toString(), | ||
'Server5xxErrorError: some title server error, status=500') | ||
assert.deepEqual(error.info(), { | ||
title: 'some title', | ||
statusCode: 500 | ||
}) | ||
assert.deepEqual(error.toJSON(), { | ||
message: error.message, | ||
name: error.name, | ||
stack: error.stack, | ||
title: 'some title', | ||
statusCode: 500, | ||
type: error.type | ||
}) | ||
assert.end(); | ||
}); | ||
assert.end() | ||
}) | ||
test('null fields', function t(assert) { | ||
var NullError = TypedError({ | ||
type: 'myError', | ||
message: 'myError', | ||
length: null, | ||
buffer: null, | ||
state: null, | ||
expecting: null | ||
}) | ||
test('null fields', function t (assert) { | ||
class NullError extends SError {} | ||
var e = NullError() | ||
assert.equal(e.type, 'myError') | ||
assert.equal(NullError.type, 'myError') | ||
const e = NullError.create('myError', { | ||
length: null, | ||
buffer: null, | ||
state: null, | ||
expecting: null | ||
}) | ||
assert.equal(e.type, 'null.error') | ||
assert.equal(NullError.type, 'null.error') | ||
assert.end() | ||
assert.end() | ||
}) | ||
test('a client error', function t(assert) { | ||
var ClientError = TypedError({ | ||
type: 'client.4xx.error', | ||
message: '{title} client error, status={statusCode}' | ||
}); | ||
test('a client error', function t (assert) { | ||
class Client4XXError extends SError {} | ||
var error2 = ClientError({ | ||
title: 'some title', | ||
statusCode: 404 | ||
}); | ||
const error2 = Client4XXError.create( | ||
'{title} client error, status={statusCode}', { | ||
title: 'some title', | ||
statusCode: 404 | ||
} | ||
) | ||
assert.equal(error2.type, 'client.4xx.error'); | ||
assert.equal(error2.fullType, 'client.4xx.error'); | ||
assert.equal(error2.statusCode, 404); | ||
assert.equal(error2.message, 'some title client error, status=404'); | ||
assert.equal(error2.toString(), | ||
'Client4xxErrorError: some title client error, status=404') | ||
assert.equal(error2.type, 'client.4xx.error') | ||
assert.equal(error2.info().statusCode, 404) | ||
assert.equal(error2.message, 'some title client error, status=404') | ||
assert.equal(error2.toString(), | ||
'Client4XXError: some title client error, status=404') | ||
assert.end(); | ||
}); | ||
assert.deepEqual(error2.info(), { | ||
title: 'some title', | ||
statusCode: 404 | ||
}) | ||
assert.deepEqual(error2.toJSON(), { | ||
message: error2.message, | ||
name: error2.name, | ||
stack: error2.stack, | ||
title: 'some title', | ||
statusCode: 404, | ||
type: error2.type | ||
}) | ||
assert.end() | ||
}) |
@@ -1,206 +0,252 @@ | ||
'use strict'; | ||
'use strict' | ||
var test = require('tape'); | ||
var net = require('net'); | ||
const test = require('tape') | ||
const net = require('net') | ||
var WrappedError = require('../wrapped.js'); | ||
const { WError } = require('../index.js') | ||
test('can create a wrapped error', function t(assert) { | ||
var ServerListenError = WrappedError({ | ||
name: 'SomeError', | ||
message: 'server: {causeMessage}', | ||
type: 'server.listen-failed', | ||
requestedPort: null, | ||
host: null | ||
}); | ||
test('can create a wrapped error', function t (assert) { | ||
class ServerListenFailedError extends WError {} | ||
var err = new Error('listen EADDRINUSE'); | ||
err.code = 'EADDRINUSE'; | ||
var err = new Error('listen EADDRINUSE') | ||
err.code = 'EADDRINUSE' | ||
var err2 = ServerListenError(err, { | ||
requestedPort: 3426, | ||
host: 'localhost' | ||
}); | ||
var err2 = ServerListenFailedError.wrap( | ||
'server failed', err, { | ||
requestedPort: 3426, | ||
host: 'localhost' | ||
} | ||
) | ||
assert.equal(ServerListenError.type, 'server.listen-failed'); | ||
assert.equal( | ||
ServerListenFailedError.type, | ||
'server.listen.failed.error' | ||
) | ||
assert.equal(err2.message, 'server: listen EADDRINUSE'); | ||
assert.equal(err2.requestedPort, 3426); | ||
assert.equal(err2.host, 'localhost'); | ||
assert.equal(err2.code, 'EADDRINUSE'); | ||
assert.equal(err2.message, 'server failed: listen EADDRINUSE') | ||
assert.equal(err2.info().requestedPort, 3426) | ||
assert.equal(err2.info().host, 'localhost') | ||
assert.equal(err2.info().code, 'EADDRINUSE') | ||
assert.equal(err2.cause, err); | ||
assert.equal(err2.cause(), err) | ||
assert.equal(err2.toString(), | ||
'ServerListenFailedError: server: listen EADDRINUSE'); | ||
assert.equal(err2.toString(), | ||
'ServerListenFailedError: server failed: listen EADDRINUSE') | ||
assert.equal(JSON.stringify(err2), JSON.stringify({ | ||
type: 'server.listen-failed', | ||
name: 'ServerListenFailedError', | ||
message: 'server: listen EADDRINUSE', | ||
requestedPort: 3426, | ||
host: 'localhost', | ||
causeMessage: 'listen EADDRINUSE', | ||
origMessage: 'listen EADDRINUSE', | ||
code: 'EADDRINUSE', | ||
fullType: 'server.listen-failed~!~error.wrapped-unknown' | ||
})); | ||
assert.equal(JSON.stringify(err2), JSON.stringify({ | ||
code: 'EADDRINUSE', | ||
requestedPort: 3426, | ||
host: 'localhost', | ||
message: 'server failed: listen EADDRINUSE', | ||
stack: err2.stack, | ||
type: 'server.listen.failed.error', | ||
fullType: 'server.listen.failed.error~!~' + | ||
'error.wrapped-unknown', | ||
name: 'ServerListenFailedError', | ||
cause: { | ||
code: err.code, | ||
message: err.message, | ||
name: err.name | ||
} | ||
})) | ||
assert.end(); | ||
}); | ||
assert.end() | ||
}) | ||
test('can create wrapped error with syscall', function t(assert) { | ||
var SysCallError = WrappedError({ | ||
'message': 'tchannel socket error ({code} from ' + | ||
'{syscall}): {origMessage}', | ||
type: 'syscall.error' | ||
}); | ||
test('can create wrapped error with syscall', function t (assert) { | ||
class SyscallError extends WError {} | ||
var err = new Error('listen EADDRINUSE'); | ||
err.code = 'EADDRINUSE'; | ||
err.syscall = 'listen'; | ||
const err = new Error('listen EADDRINUSE') | ||
err.code = 'EADDRINUSE' | ||
err.syscall = 'listen' | ||
var err2 = SysCallError(err); | ||
const err2 = SyscallError.wrap( | ||
'tchannel socket error ({code} from {syscall})', err | ||
) | ||
assert.equal(err2.message, 'tchannel socket error ' + | ||
'(EADDRINUSE from listen): listen EADDRINUSE'); | ||
assert.equal(err2.syscall, 'listen'); | ||
assert.equal(err2.code, 'EADDRINUSE'); | ||
assert.equal(err2.type, 'syscall.error'); | ||
assert.equal(err2.message, 'tchannel socket error ' + | ||
'(EADDRINUSE from listen): listen EADDRINUSE') | ||
assert.equal(err2.info().syscall, 'listen') | ||
assert.equal(err2.info().code, 'EADDRINUSE') | ||
assert.equal(err2.type, 'syscall.error') | ||
assert.end(); | ||
}); | ||
assert.end() | ||
}) | ||
test('wrapping twice', function t(assert) { | ||
var ReadError = WrappedError({ | ||
type: 'my.read-error', | ||
message: 'read: {causeMessage}' | ||
}); | ||
test('wrapping twice', function t (assert) { | ||
class ReadError extends WError {} | ||
class DatabaseError extends WError {} | ||
class BusinessError extends WError {} | ||
var DatabaseError = WrappedError({ | ||
type: 'my.database-error', | ||
message: 'db: {causeMessage}' | ||
}); | ||
const err = BusinessError.wrap( | ||
'business', DatabaseError.wrap( | ||
'db', ReadError.wrap('read', new Error('oops')) | ||
) | ||
) | ||
assert.ok(err) | ||
var BusinessError = WrappedError({ | ||
type: 'my.business-error', | ||
message: 'business: {causeMessage}' | ||
}); | ||
assert.equal(err.message, 'business: db: read: oops') | ||
assert.equal(err.type, 'business.error') | ||
assert.equal(err.fullType(), 'business.error~!~' + | ||
'database.error~!~' + | ||
'read.error~!~' + | ||
'error.wrapped-unknown') | ||
var err = BusinessError( | ||
DatabaseError( | ||
ReadError( | ||
new Error('oops') | ||
) | ||
) | ||
); | ||
assert.ok(err); | ||
assert.equal(JSON.stringify(err), JSON.stringify({ | ||
message: 'business: db: read: oops', | ||
stack: err.stack, | ||
type: 'business.error', | ||
fullType: 'business.error~!~database.error~!~' + | ||
'read.error~!~error.wrapped-unknown', | ||
name: 'BusinessError', | ||
cause: { | ||
message: 'db: read: oops', | ||
type: 'database.error', | ||
fullType: 'database.error~!~' + | ||
'read.error~!~error.wrapped-unknown', | ||
name: 'DatabaseError', | ||
cause: { | ||
message: 'read: oops', | ||
type: 'read.error', | ||
fullType: 'read.error~!~error.wrapped-unknown', | ||
name: 'ReadError', | ||
cause: { | ||
message: 'oops', | ||
name: 'Error' | ||
} | ||
} | ||
} | ||
})) | ||
assert.equal(err.message, 'business: db: read: oops'); | ||
assert.equal(err.type, 'my.business-error'); | ||
assert.equal(err.fullType, 'my.business-error~!~' + | ||
'my.database-error~!~' + | ||
'my.read-error~!~' + | ||
'error.wrapped-unknown'); | ||
assert.end() | ||
}) | ||
assert.end(); | ||
}); | ||
test('handles bad recursive strings', function t (assert) { | ||
class ReadError extends WError {} | ||
test('handles bad recursive strings', function t(assert) { | ||
var ReadError = WrappedError({ | ||
type: 'wat.wat', | ||
message: 'read: {causeMessage}' | ||
}); | ||
const err2 = ReadError.wrap( | ||
'read: {code}', new Error('hi'), { | ||
code: 'extra {code}' | ||
} | ||
) | ||
var err2 = ReadError(new Error('hi {causeMessage}')); | ||
assert.ok(err2) | ||
assert.equal(err2.message, 'read: extra {code}: hi') | ||
assert.ok(err2); | ||
assert.equal(err2.message, | ||
'read: hi $INVALID_CAUSE_MESSAGE_LITERAL'); | ||
assert.end() | ||
}) | ||
assert.end(); | ||
}); | ||
test('can wrap real IO errors', function t (assert) { | ||
class ServerListenFailedError extends WError {} | ||
test('can wrap real IO errors', function t(assert) { | ||
var ServerListenError = WrappedError({ | ||
message: 'server: {causeMessage}', | ||
type: 'server.listen-failed', | ||
requestedPort: null, | ||
host: null | ||
}); | ||
const otherServer = net.createServer() | ||
otherServer.once('listening', onPortAllocated) | ||
otherServer.listen(0) | ||
var otherServer = net.createServer(); | ||
otherServer.once('listening', onPortAllocated); | ||
otherServer.listen(0); | ||
function onPortAllocated () { | ||
const port = otherServer.address().port | ||
function onPortAllocated() { | ||
var port = otherServer.address().port; | ||
const server = net.createServer() | ||
server.on('error', onError) | ||
var server = net.createServer(); | ||
server.on('error', onError); | ||
server.listen(port) | ||
server.listen(port); | ||
function onError (cause) { | ||
const err = ServerListenFailedError.wrap( | ||
'server listen failed', cause, { | ||
host: 'localhost', | ||
requestedPort: port | ||
} | ||
) | ||
function onError(cause) { | ||
var err = ServerListenError(cause, { | ||
host: 'localhost', | ||
requestedPort: port | ||
}); | ||
otherServer.close(); | ||
assertOnError(err, cause, port); | ||
} | ||
otherServer.close() | ||
assertOnError(err, cause, port) | ||
} | ||
} | ||
function assertOnError(err, cause, port) { | ||
assert.ok(err.message.indexOf('server: ') >= 0) | ||
assert.ok(err.message.indexOf('listen EADDRINUSE') >= 0) | ||
assert.equal(err.requestedPort, port); | ||
assert.equal(err.host, 'localhost'); | ||
assert.equal(err.code, 'EADDRINUSE'); | ||
function assertOnError (err, cause, port) { | ||
assert.ok(err.message.indexOf('server listen failed: ') >= 0) | ||
assert.ok(err.message.indexOf('listen EADDRINUSE') >= 0) | ||
assert.equal(err.info().requestedPort, port) | ||
assert.equal(err.info().host, 'localhost') | ||
assert.equal(err.info().code, 'EADDRINUSE') | ||
assert.equal(err.cause, cause); | ||
assert.equal(err.cause(), cause) | ||
assert.ok(err.toString().indexOf('ServerListenFailedError: ') >= 0) | ||
assert.ok(err.toString().indexOf('server: ') >= 0) | ||
assert.ok(err.toString().indexOf('listen EADDRINUSE') >= 0) | ||
assert.ok(err.toString().indexOf('ServerListenFailedError: ') >= 0) | ||
assert.ok(err.toString().indexOf('server listen failed: ') >= 0) | ||
assert.ok(err.toString().indexOf('listen EADDRINUSE') >= 0) | ||
var expectedMessage = err.message | ||
var expectedOrigMessage = err.origMessage | ||
assert.equal(JSON.stringify(err), JSON.stringify({ | ||
code: 'EADDRINUSE', | ||
errno: 'EADDRINUSE', | ||
syscall: 'listen', | ||
host: 'localhost', | ||
requestedPort: port, | ||
message: err.message, | ||
stack: err.stack, | ||
type: 'server.listen.failed.error', | ||
fullType: 'server.listen.failed.error~!~' + | ||
'error.wrapped-io.listen.EADDRINUSE', | ||
name: 'ServerListenFailedError', | ||
cause: { | ||
code: 'EADDRINUSE', | ||
errno: 'EADDRINUSE', | ||
syscall: 'listen', | ||
message: err.cause().message, | ||
name: 'Error' | ||
} | ||
})) | ||
assert.ok(err.origMessage.indexOf('listen EADDRINUSE') >= 0) | ||
assert.ok(err.origMessage.indexOf('server: ') === -1) | ||
assert.end() | ||
} | ||
}) | ||
assert.equal(JSON.stringify(err), JSON.stringify({ | ||
type: 'server.listen-failed', | ||
name: 'ServerListenFailedError', | ||
message: expectedMessage, | ||
requestedPort: port, | ||
host: 'localhost', | ||
causeMessage: expectedOrigMessage, | ||
origMessage: expectedOrigMessage, | ||
code: 'EADDRINUSE', | ||
errno: 'EADDRINUSE', | ||
syscall: 'listen', | ||
fullType: 'server.listen-failed~!~' + | ||
'error.wrapped-io.listen.EADDRINUSE' | ||
})); | ||
test('can wrap assert errors', function t (assert) { | ||
class TestError extends WError {} | ||
assert.end(); | ||
} | ||
}); | ||
let assertError | ||
try { | ||
require('assert').strictEqual('a', 'b') | ||
} catch (_err) { | ||
assertError = _err | ||
} | ||
test('can wrap assert errors', function t(assert) { | ||
var TestError = WrappedError({ | ||
message: 'error: {origMessage}', | ||
type: 'error' | ||
}); | ||
const err = TestError.wrap('error', assertError) | ||
assert.equal(err.cause().actual, 'a') | ||
var assertError; | ||
try { require('assert').equal('a', 'b'); } | ||
catch (_err) { assertError = _err; } | ||
if (err.message === `error: 'a' === 'b'`) { | ||
assert.equal(err.message, `error: 'a' === 'b'`) | ||
} else { | ||
assert.ok(/[eE]xpected /.test(err.message)) | ||
assert.ok(err.message.includes('strictly equal')) | ||
} | ||
var err = TestError(assertError); | ||
assert.equal(err.cause.actual, 'a'); | ||
assert.end(); | ||
assert.ok(err.cause().name.includes('AssertionError')) | ||
assert.ok( | ||
err.info().operator === '===' || | ||
err.info().operator === 'strictEqual' | ||
) | ||
assert.equal(JSON.stringify(err), JSON.stringify({ | ||
code: 'ERR_ASSERTION', | ||
actual: 'a', | ||
expected: 'b', | ||
operator: err.info().operator, | ||
message: 'error: ' + err.cause().message, | ||
stack: err.stack, | ||
type: 'test.error', | ||
fullType: 'test.error~!~error.wrapped-unknown', | ||
name: 'TestError', | ||
cause: { | ||
code: 'ERR_ASSERTION', | ||
actual: 'a', | ||
expected: 'b', | ||
operator: err.cause().operator, | ||
message: err.cause().message, | ||
name: err.cause().name | ||
} | ||
})) | ||
assert.end() | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35296
0
825
353
4
2
- Removedstring-template@~0.2.1
- Removedstring-template@0.2.1(transitive)