Skip to content
Permalink
Browse files
feat(CordovaError): support for error cause & more (#121)
This commit bases CordovaError on the popular [joyent/node-verror].

We actually use @netflix/nerror, a VError fork, for now. That's because
we do not want printf style error formatting support and that fork
allows to disable it. There's [ongoing work][1] to integrate that change
into the original VError.

So basically CordovaError behaves like PError but with all the static
methods from VError and different parameter ordering for its
constructor.

One change that could break some existing tests in repositories that use
cordova-common is that `toString` (for errors without a cause argument)
now behaves like the Error default again:

    new CordovaError('foo').toString();
    // old result: 'foo'
    // new result: 'CordovaError: foo'

[joyent/node-verror]: https://github.com/joyent/node-verror
[1]: TritonDataCenter/node-verror#63 (comment)
  • Loading branch information
raphinesse committed Mar 14, 2020
1 parent f6e8cab commit fe6a73fc80ebf974b4c27251091de89e1df2c0f3
Showing 4 changed files with 117 additions and 28 deletions.

Some generated files are not rendered by default. Learn more.

@@ -23,6 +23,7 @@
"cover": "nyc npm run test:unit"
},
"dependencies": {
"@netflix/nerror": "^1.1.3",
"ansi": "^0.3.1",
"bplist-parser": "^0.2.0",
"cross-spawn": "^6.0.5",
@@ -17,15 +17,78 @@
under the License.
*/

var CordovaError = require('../../src/CordovaError');
const endent = require('endent');
const CordovaError = require('../../src/CordovaError');

describe('CordovaError class', function () {
it('Test 001 : should be constructable', function () {
expect(new CordovaError('error')).toEqual(jasmine.any(CordovaError));
describe('CordovaError class', () => {
let error;

beforeEach(() => {
error = new CordovaError('error');
});

it('should be an error', () => {
expect(error).toEqual(jasmine.any(Error));
});

it('should have a name property', () => {
expect(error.name).toEqual('CordovaError');
});

it('Test 003 : toString works', function () {
var error003_1 = new CordovaError('error');
expect(error003_1.toString()).toEqual('error');
it('should have a working toString method', () => {
expect(error.toString()).toEqual('CordovaError: error');
});

describe('given a cause', () => {
let cause;

beforeEach(() => {
cause = new Error('cause');
error = new CordovaError('error', cause);
});

it('should save it', () => {
expect(error.cause()).toBe(cause);
expect(CordovaError.cause(error)).toBe(cause);
});

it('should include the cause in toString result', () => {
const stringifiedError = 'CordovaError: error: cause';
expect(String(error)).toEqual(stringifiedError);
expect(error.toString()).toEqual(stringifiedError);
});

it('should include the cause stack in CordovaError.fullStack', () => {
cause.stack = 'CAUSE_STACK';
error.stack = 'ERROR_STACK';

expect(CordovaError.fullStack(error)).toEqual(endent`
ERROR_STACK
caused by: CAUSE_STACK
`);
});
});

describe('given options', () => {
it('should apply name option', () => {
const name = 'FooError';
error = new CordovaError('error', { name });

expect(error.name).toEqual(name);
});

it('should apply cause option', () => {
const cause = new Error('cause');
error = new CordovaError('error', { cause });

expect(CordovaError.cause(error)).toBe(cause);
});

it('should apply info option', () => {
const info = { foo: 'bar' };
error = new CordovaError('error', { info });

expect(CordovaError.info(error)).toEqual(info);
});
});
});
@@ -17,30 +17,36 @@
under the License.
*/

// @ts-check

const { VError } = require('@netflix/nerror');

/**
* A derived exception class
*
* Based on: https://stackoverflow.com/a/8460753/380229
* @public
* @typedef {Object} CordovaErrorOptions
* @param {String} [name] - Name of the error.
* @param {Error} [cause] - Indicates that the new error was caused by `cause`.
* @param {Object} [info] - Specifies arbitrary informational properties.
*/
class CordovaError extends Error {
/**
* Creates new CordovaError with given error message
*
* @param {String} message Error message
*/
constructor (message) {
super(message);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}

/**
* A custom exception class derived from VError
*/
class CordovaError extends VError {
/**
* Converts this to its string representation
*
* @return {String} Stringified error representation
* @param {String} message - Error message
* @param {Error|CordovaErrorOptions} [causeOrOpts] - The Error that caused
* this to be thrown or a CordovaErrorOptions object.
*/
toString () {
return this.message;
constructor (message, causeOrOpts = {}) {
const defaults = { name: 'CordovaError' };
const overrides = { strict: false, skipPrintf: true };
const userOpts = causeOrOpts instanceof Error
? { cause: causeOrOpts }
: causeOrOpts;
const opts = Object.assign(defaults, userOpts, overrides);

super(opts, message);
}
}

0 comments on commit fe6a73f

Please sign in to comment.