Skip to content

Commit

Permalink
feat(CordovaError): support for error cause & more
Browse files Browse the repository at this point in the history
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 Jan 9, 2020
1 parent 6f922c0 commit 3f8c8ee
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 28 deletions.
23 changes: 21 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
77 changes: 70 additions & 7 deletions spec/CordovaError/CordovaError.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
44 changes: 25 additions & 19 deletions src/CordovaError.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down

0 comments on commit 3f8c8ee

Please sign in to comment.