Refactored AxiosError to a constructor;

Refactored `Cancel` to a constructor, a subclass of the `AxiosError`;
Expose CanceledError class;
Refactored axios error codes;
Added `toFlatObject` util;
This commit is contained in:
DigitalBrainJS 2021-10-14 18:53:46 +03:00
parent 1025d1231a
commit 7f1236652a
29 changed files with 332 additions and 221 deletions

23
index.d.ts vendored
View File

@ -121,13 +121,34 @@ export interface AxiosResponse<T = unknown, D = any> {
request?: any;
}
export interface AxiosError<T = unknown, D = any> extends Error {
export class AxiosError<T = unknown, D = any> extends Error {
constructor(
message?: string,
code?: string,
config?: AxiosRequestConfig<D>,
request?: any,
response?: AxiosResponse<T, D>
);
config: AxiosRequestConfig<D>;
code?: string;
request?: any;
response?: AxiosResponse<T, D>;
isAxiosError: boolean;
status?: string;
toJSON: () => object;
static readonly ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS";
static readonly ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE";
static readonly ERR_BAD_OPTION = "ERR_BAD_OPTION";
static readonly ERR_NETWORK = "ERR_NETWORK";
static readonly ERR_DEPRECATED = "ERR_DEPRECATED";
static readonly ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE";
static readonly ERR_BAD_REQUEST = "ERR_BAD_REQUEST";
static readonly ERR_CANCELED = "ERR_CANCELED";
static readonly ECONNABORTED = "ECONNABORTED";
static readonly ETIMEDOUT = "ETIMEDOUT";
}
export class CanceledError<T> extends AxiosError<T> {
}
export interface AxiosPromise<T = unknown> extends Promise<AxiosResponse<T>> {

View File

@ -11,10 +11,9 @@ var httpsFollow = require('follow-redirects').https;
var url = require('url');
var zlib = require('zlib');
var VERSION = require('./../env/data').version;
var createError = require('../core/createError');
var enhanceError = require('../core/enhanceError');
var defaults = require('../defaults');
var Cancel = require('../cancel/Cancel');
var AxiosError = require('../core/AxiosError');
var CanceledError = require('../cancel/CanceledError');
var isHttps = /https:?/;
@ -93,8 +92,9 @@ module.exports = function httpAdapter(config) {
} else if (utils.isString(data)) {
data = Buffer.from(data, 'utf-8');
} else {
return reject(createError(
return reject(new AxiosError(
'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream',
AxiosError.ERR_BAD_REQUEST,
config
));
}
@ -270,14 +270,14 @@ module.exports = function httpAdapter(config) {
// make sure the content length is not over the maxContentLength if specified
if (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) {
stream.destroy();
reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
config, null, lastRequest));
reject(new AxiosError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
AxiosError.ERR_BAD_RESPONSE, config, lastRequest));
}
});
stream.on('error', function handleStreamError(err) {
if (req.aborted) return;
reject(enhanceError(err, config, null, lastRequest));
reject(AxiosError.from(err, null, config, lastRequest));
});
stream.on('end', function handleStreamEnd() {
@ -297,8 +297,8 @@ module.exports = function httpAdapter(config) {
// Handle errors
req.on('error', function handleRequestError(err) {
if (req.aborted && err.code !== 'ERR_FR_TOO_MANY_REDIRECTS') return;
reject(enhanceError(err, config, null, req));
if (req.aborted && err.code !== AxiosError.ERR_FR_TOO_MANY_REDIRECTS) return;
reject(AxiosError.from(err, null, config, req));
});
// Handle request timeout
@ -307,10 +307,10 @@ module.exports = function httpAdapter(config) {
var timeout = parseInt(config.timeout, 10);
if (isNaN(timeout)) {
reject(createError(
reject(new AxiosError(
'error trying to parse `config.timeout` to int',
AxiosError.ERR_BAD_OPTION_VALUE,
config,
'ERR_PARSE_TIMEOUT',
req
));
@ -325,10 +325,10 @@ module.exports = function httpAdapter(config) {
req.setTimeout(timeout, function handleRequestTimeout() {
req.abort();
var transitional = config.transitional || defaults.transitional;
reject(createError(
reject(new AxiosError(
'timeout of ' + timeout + 'ms exceeded',
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
config,
transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
req
));
});
@ -341,7 +341,7 @@ module.exports = function httpAdapter(config) {
if (req.aborted) return;
req.abort();
reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
reject(!cancel || (cancel && cancel.type) ? new CanceledError() : cancel);
};
config.cancelToken && config.cancelToken.subscribe(onCanceled);
@ -354,7 +354,7 @@ module.exports = function httpAdapter(config) {
// Send the request
if (utils.isStream(data)) {
data.on('error', function handleStreamError(err) {
reject(enhanceError(err, config, null, req));
reject(AxiosError.from(err, config, null, req));
}).pipe(req);
} else {
req.end(data);

View File

@ -7,9 +7,9 @@ var buildURL = require('./../helpers/buildURL');
var buildFullPath = require('../core/buildFullPath');
var parseHeaders = require('./../helpers/parseHeaders');
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
var createError = require('../core/createError');
var defaults = require('../defaults');
var Cancel = require('../cancel/Cancel');
var AxiosError = require('../core/AxiosError');
var CanceledError = require('../cancel/CanceledError');
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
@ -104,7 +104,7 @@ module.exports = function xhrAdapter(config) {
return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));
// Clean up request
request = null;
@ -114,7 +114,7 @@ module.exports = function xhrAdapter(config) {
request.onerror = function handleError() {
// Real errors are hidden from us by the browser
// onerror should only fire if it's a network error
reject(createError('Network Error', config, null, request));
reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request, request));
// Clean up request
request = null;
@ -127,10 +127,10 @@ module.exports = function xhrAdapter(config) {
if (config.timeoutErrorMessage) {
timeoutErrorMessage = config.timeoutErrorMessage;
}
reject(createError(
reject(new AxiosError(
timeoutErrorMessage,
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
config,
transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
request));
// Clean up request
@ -191,7 +191,7 @@ module.exports = function xhrAdapter(config) {
if (!request) {
return;
}
reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
reject(!cancel || (cancel && cancel.type) ? new CanceledError() : cancel);
request.abort();
request = null;
};

View File

@ -37,11 +37,17 @@ var axios = createInstance(defaults);
axios.Axios = Axios;
// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CanceledError = require('./cancel/CanceledError');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
axios.VERSION = require('./env/data').version;
// Expose AxiosError class
axios.AxiosError = require('../lib/core/AxiosError');
// alias for CanceledError for backward compatibility
axios.Cancel = axios.CanceledError;
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);

View File

@ -1,19 +0,0 @@
'use strict';
/**
* A `Cancel` is an object that is thrown when an operation is canceled.
*
* @class
* @param {string=} message The message.
*/
function Cancel(message) {
this.message = message;
}
Cancel.prototype.toString = function toString() {
return 'Cancel' + (this.message ? ': ' + this.message : '');
};
Cancel.prototype.__CANCEL__ = true;
module.exports = Cancel;

View File

@ -1,6 +1,6 @@
'use strict';
var Cancel = require('./Cancel');
var CanceledError = require('./CanceledError');
/**
* A `CancelToken` is an object that can be used to request cancellation of an operation.
@ -56,13 +56,13 @@ function CancelToken(executor) {
return;
}
token.reason = new Cancel(message);
token.reason = new CanceledError(message);
resolvePromise(token.reason);
});
}
/**
* Throws a `Cancel` if cancellation has been requested.
* Throws a `CanceledError` if cancellation has been requested.
*/
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {

View File

@ -0,0 +1,22 @@
'use strict';
var AxiosError = require('../core/AxiosError');
var utils = require('../utils');
/**
* A `CanceledError` is an object that is thrown when an operation is canceled.
*
* @class
* @param {string=} message The message.
*/
function CanceledError(message) {
// eslint-disable-next-line no-eq-null,eqeqeq
AxiosError.call(this, message == null ? 'canceled' : message, AxiosError.ERR_CANCELED);
this.name = 'CanceledError';
}
utils.inherits(CanceledError, AxiosError, {
__CANCEL__: true
});
module.exports = CanceledError;

86
lib/core/AxiosError.js Normal file
View File

@ -0,0 +1,86 @@
'use strict';
var utils = require('../utils');
/**
* Create an Error with the specified message, config, error code, request and response.
*
* @param {string} message The error message.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [config] The config.
* @param {Object} [request] The request.
* @param {Object} [response] The response.
* @returns {Error} The created error.
*/
function AxiosError(message, code, config, request, response) {
Error.call(this);
this.message = message;
this.name = 'AxiosError';
code && (this.code = code);
config && (this.config = config);
request && (this.request = request);
response && (this.response = response);
}
utils.inherits(AxiosError, Error, {
toJSON: function toJSON() {
return {
// Standard
message: this.message,
name: this.name,
// Microsoft
description: this.description,
number: this.number,
// Mozilla
fileName: this.fileName,
lineNumber: this.lineNumber,
columnNumber: this.columnNumber,
stack: this.stack,
// Axios
config: this.config,
code: this.code,
status: this.response && this.response.status ? this.response.status : null
};
}
});
var prototype = AxiosError.prototype;
var descriptors = {};
[
'ERR_BAD_OPTION_VALUE',
'ERR_BAD_OPTION',
'ECONNABORTED',
'ETIMEDOUT',
'ERR_NETWORK',
'ERR_FR_TOO_MANY_REDIRECTS',
'ERR_DEPRECATED',
'ERR_BAD_RESPONSE',
'ERR_BAD_REQUEST',
'ERR_CANCELED'
// eslint-disable-next-line func-names
].forEach(function(code) {
descriptors[code] = {value: code};
});
Object.defineProperties(AxiosError, descriptors);
Object.defineProperty(prototype, 'isAxiosError', {value: true});
// eslint-disable-next-line func-names
AxiosError.from = function(error, code, config, request, response, customProps) {
var axiosError = Object.create(prototype);
utils.toFlatObject(error, axiosError, function filter(obj) {
return obj !== Error.prototype;
});
AxiosError.call(axiosError, error.message, code, config, request, response);
axiosError.name = error.name;
customProps && Object.assign(axiosError, customProps);
return axiosError;
};
module.exports = AxiosError;

View File

@ -1,18 +0,0 @@
'use strict';
var enhanceError = require('./enhanceError');
/**
* Create an Error with the specified message, config, error code, request and response.
*
* @param {string} message The error message.
* @param {Object} config The config.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [request] The request.
* @param {Object} [response] The response.
* @returns {Error} The created error.
*/
module.exports = function createError(message, config, code, request, response) {
var error = new Error(message);
return enhanceError(error, config, code, request, response);
};

View File

@ -4,10 +4,10 @@ var utils = require('./../utils');
var transformData = require('./transformData');
var isCancel = require('../cancel/isCancel');
var defaults = require('../defaults');
var Cancel = require('../cancel/Cancel');
var CanceledError = require('../cancel/CanceledError');
/**
* Throws a `Cancel` if cancellation has been requested.
* Throws a `CanceledError` if cancellation has been requested.
*/
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
@ -15,7 +15,7 @@ function throwIfCancellationRequested(config) {
}
if (config.signal && config.signal.aborted) {
throw new Cancel('canceled');
throw new CanceledError();
}
}

View File

@ -1,43 +0,0 @@
'use strict';
/**
* Update an Error with the specified config, error code, and response.
*
* @param {Error} error The error to update.
* @param {Object} config The config.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [request] The request.
* @param {Object} [response] The response.
* @returns {Error} The error.
*/
module.exports = function enhanceError(error, config, code, request, response) {
error.config = config;
if (code) {
error.code = code;
}
error.request = request;
error.response = response;
error.isAxiosError = true;
error.toJSON = function toJSON() {
return {
// Standard
message: this.message,
name: this.name,
// Microsoft
description: this.description,
number: this.number,
// Mozilla
fileName: this.fileName,
lineNumber: this.lineNumber,
columnNumber: this.columnNumber,
stack: this.stack,
// Axios
config: this.config,
code: this.code,
status: this.response && this.response.status ? this.response.status : null
};
};
return error;
};

View File

@ -1,6 +1,6 @@
'use strict';
var createError = require('./createError');
var AxiosError = require('./AxiosError');
/**
* Resolve or reject a Promise based on response status.
@ -14,10 +14,10 @@ module.exports = function settle(resolve, reject, response) {
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(createError(
reject(new AxiosError(
'Request failed with status code ' + response.status,
[AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],
response.config,
null,
response.request,
response
));

View File

@ -2,7 +2,7 @@
var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');
var enhanceError = require('./core/enhanceError');
var AxiosError = require('./core/AxiosError');
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
@ -90,7 +90,7 @@ var defaults = {
} catch (e) {
if (strictJSONParsing) {
if (e.name === 'SyntaxError') {
throw enhanceError(e, this, 'E_JSON_PARSE');
throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response);
}
throw e;
}

View File

@ -1,6 +1,7 @@
'use strict';
var VERSION = require('../env/data').version;
var AxiosError = require('../core/AxiosError');
var validators = {};
@ -28,7 +29,10 @@ validators.transitional = function transitional(validator, version, message) {
// eslint-disable-next-line func-names
return function(value, opt, opts) {
if (validator === false) {
throw new Error(formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')));
throw new AxiosError(
formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')),
AxiosError.ERR_DEPRECATED
);
}
if (version && !deprecatedWarnings[opt]) {
@ -55,7 +59,7 @@ validators.transitional = function transitional(validator, version, message) {
function assertOptions(options, schema, allowUnknown) {
if (typeof options !== 'object') {
throw new TypeError('options must be an object');
throw new AxiosError('options must be an object', AxiosError.ERR_BAD_OPTION_VALUE);
}
var keys = Object.keys(options);
var i = keys.length;
@ -66,12 +70,12 @@ function assertOptions(options, schema, allowUnknown) {
var value = options[opt];
var result = value === undefined || validator(value, opt, options);
if (result !== true) {
throw new TypeError('option ' + opt + ' must be ' + result);
throw new AxiosError('option ' + opt + ' must be ' + result, AxiosError.ERR_BAD_OPTION_VALUE);
}
continue;
}
if (allowUnknown !== true) {
throw Error('Unknown option ' + opt);
throw new AxiosError('Unknown option ' + opt, AxiosError.ERR_BAD_OPTION);
}
}
}

View File

@ -323,6 +323,52 @@ function stripBOM(content) {
return content;
}
/**
* Inherit the prototype methods from one constructor into another
* @param {function} constructor
* @param {function} superConstructor
* @param {object} [props]
* @param {object} [descriptors]
*/
function inherits(constructor, superConstructor, props, descriptors) {
constructor.prototype = Object.create(superConstructor.prototype, descriptors);
constructor.prototype.constructor = constructor;
props && Object.assign(constructor.prototype, props);
}
/**
* Resolve object with deep prototype chain to a flat object
* @param {Object} sourceObj source object
* @param {Object} [destObj]
* @param {Function} [filter]
* @returns {Object}
*/
function toFlatObject(sourceObj, destObj, filter) {
var props;
var i;
var prop;
var merged = {};
destObj = destObj || {};
do {
props = Object.getOwnPropertyNames(sourceObj);
i = props.length;
while (i-- > 0) {
prop = props[i];
if (!merged[prop]) {
destObj[prop] = sourceObj[prop];
merged[prop] = true;
}
}
sourceObj = Object.getPrototypeOf(sourceObj);
} while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);
return destObj;
}
module.exports = {
isArray: isArray,
isArrayBuffer: isArrayBuffer,
@ -345,5 +391,7 @@ module.exports = {
merge: merge,
extend: extend,
trim: trim,
stripBOM: stripBOM
stripBOM: stripBOM,
inherits: inherits,
toFlatObject: toFlatObject
};

View File

@ -36,7 +36,7 @@ describe('static api', function () {
expect(typeof axios.create).toEqual('function');
});
it('should have Cancel, CancelToken, and isCancel properties', function () {
it('should have CanceledError, CancelToken, and isCancel properties', function () {
expect(typeof axios.Cancel).toEqual('function');
expect(typeof axios.CancelToken).toEqual('function');
expect(typeof axios.isCancel).toEqual('function');

View File

@ -14,7 +14,7 @@ describe('cancel', function() {
});
describe('when called before sending request', function() {
it('rejects Promise with a Cancel object', function(done) {
it('rejects Promise with a CanceledError object', function(done) {
var source = CancelToken.source();
source.cancel('Operation has been canceled.');
axios.get('/foo', {
@ -28,7 +28,7 @@ describe('cancel', function() {
});
describe('when called after request has been sent', function() {
it('rejects Promise with a Cancel object', function(done) {
it('rejects Promise with a CanceledError object', function(done) {
var source = CancelToken.source();
axios.get('/foo/bar', {
cancelToken: source.token

View File

@ -1,15 +0,0 @@
var Cancel = require('../../../lib/cancel/Cancel');
describe('Cancel', function() {
describe('toString', function() {
it('returns correct result when message is not specified', function() {
var cancel = new Cancel();
expect(cancel.toString()).toBe('Cancel');
});
it('returns correct result when message is specified', function() {
var cancel = new Cancel('Operation has been canceled.');
expect(cancel.toString()).toBe('Cancel: Operation has been canceled.');
});
});
});

View File

@ -1,5 +1,5 @@
var CancelToken = require('../../../lib/cancel/CancelToken');
var Cancel = require('../../../lib/cancel/Cancel');
var CanceledError = require('../../../lib/cancel/CanceledError');
describe('CancelToken', function() {
describe('constructor', function() {
@ -17,13 +17,13 @@ describe('CancelToken', function() {
});
describe('reason', function() {
it('returns a Cancel if cancellation has been requested', function() {
it('returns a CanceledError if cancellation has been requested', function() {
var cancel;
var token = new CancelToken(function(c) {
cancel = c;
});
cancel('Operation has been canceled.');
expect(token.reason).toEqual(jasmine.any(Cancel));
expect(token.reason).toEqual(jasmine.any(CanceledError));
expect(token.reason.message).toBe('Operation has been canceled.');
});
@ -40,7 +40,7 @@ describe('CancelToken', function() {
cancel = c;
});
token.promise.then(function onFulfilled(value) {
expect(value).toEqual(jasmine.any(Cancel));
expect(value).toEqual(jasmine.any(CanceledError));
expect(value.message).toBe('Operation has been canceled.');
done();
});
@ -50,7 +50,7 @@ describe('CancelToken', function() {
describe('throwIfRequested', function() {
it('throws if cancellation has been requested', function() {
// Note: we cannot use expect.toThrowError here as Cancel does not inherit from Error
// Note: we cannot use expect.toThrowError here as CanceledError does not inherit from Error
var cancel;
var token = new CancelToken(function(c) {
cancel = c;
@ -60,8 +60,8 @@ describe('CancelToken', function() {
token.throwIfRequested();
fail('Expected throwIfRequested to throw.');
} catch (thrown) {
if (!(thrown instanceof Cancel)) {
fail('Expected throwIfRequested to throw a Cancel, but it threw ' + thrown + '.');
if (!(thrown instanceof CanceledError)) {
fail('Expected throwIfRequested to throw a CanceledError, but it threw ' + thrown + '.');
}
expect(thrown.message).toBe('Operation has been canceled.');
}
@ -80,7 +80,7 @@ describe('CancelToken', function() {
expect(source.cancel).toEqual(jasmine.any(Function));
expect(source.token.reason).toBeUndefined();
source.cancel('Operation has been canceled.');
expect(source.token.reason).toEqual(jasmine.any(Cancel));
expect(source.token.reason).toEqual(jasmine.any(CanceledError));
expect(source.token.reason.message).toBe('Operation has been canceled.');
});
});

View File

@ -0,0 +1,15 @@
var CanceledError = require('../../../lib/cancel/CanceledError');
describe('Cancel', function() {
describe('toString', function() {
it('returns correct result when message is not specified', function() {
var cancel = new CanceledError();
expect(cancel.toString()).toBe('CanceledError: canceled');
});
it('returns correct result when message is specified', function() {
var cancel = new CanceledError('Operation has been canceled.');
expect(cancel.toString()).toBe('CanceledError: Operation has been canceled.');
});
});
});

View File

@ -1,12 +1,12 @@
var isCancel = require('../../../lib/cancel/isCancel');
var Cancel = require('../../../lib/cancel/Cancel');
var CanceledError = require('../../../lib/cancel/CanceledError');
describe('isCancel', function() {
it('returns true if value is a Cancel', function() {
expect(isCancel(new Cancel())).toBe(true);
it('returns true if value is a CanceledError', function() {
expect(isCancel(new CanceledError())).toBe(true);
});
it('returns false if value is not a Cancel', function() {
it('returns false if value is not a CanceledError', function() {
expect(isCancel({ foo: 'bar' })).toBe(false);
});
});

View File

@ -0,0 +1,50 @@
var AxiosError = require('../../../lib/core/AxiosError');
describe('core::AxiosError', function() {
it('should create an Error with message, config, code, request, response and isAxiosError', function() {
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
var error = new AxiosError('Boom!', 'ESOMETHING', { foo: 'bar' }, request, response);
expect(error instanceof Error).toBe(true);
expect(error.message).toBe('Boom!');
expect(error.config).toEqual({ foo: 'bar' });
expect(error.code).toBe('ESOMETHING');
expect(error.request).toBe(request);
expect(error.response).toBe(response);
expect(error.isAxiosError).toBe(true);
});
it('should create an Error that can be serialized to JSON', function() {
// Attempting to serialize request and response results in
// TypeError: Converting circular structure to JSON
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
var error = new AxiosError('Boom!', 'ESOMETHING', { foo: 'bar' }, request, response);
var json = error.toJSON();
expect(json.message).toBe('Boom!');
expect(json.config).toEqual({ foo: 'bar' });
expect(json.code).toBe('ESOMETHING');
expect(json.status).toBe(200);
expect(json.request).toBe(undefined);
expect(json.response).toBe(undefined);
});
describe('core::createError.from', function() {
it('should add config, config, request and response to error', function() {
var error = new Error('Boom!');
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
var axiosError = AxiosError.from(error, 'ESOMETHING', { foo: 'bar' }, request, response);
expect(axiosError.config).toEqual({ foo: 'bar' });
expect(axiosError.code).toBe('ESOMETHING');
expect(axiosError.request).toBe(request);
expect(axiosError.response).toBe(response);
expect(axiosError.isAxiosError).toBe(true);
});
it('should return error', function() {
var error = new Error('Boom!');
expect(AxiosError.from(error, 'ESOMETHING', { foo: 'bar' }) instanceof AxiosError).toBeTruthy();
});
});
});

View File

@ -1,30 +0,0 @@
var createError = require('../../../lib/core/createError');
describe('core::createError', function() {
it('should create an Error with message, config, code, request, response and isAxiosError', function() {
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
var error = createError('Boom!', { foo: 'bar' }, 'ESOMETHING', request, response);
expect(error instanceof Error).toBe(true);
expect(error.message).toBe('Boom!');
expect(error.config).toEqual({ foo: 'bar' });
expect(error.code).toBe('ESOMETHING');
expect(error.request).toBe(request);
expect(error.response).toBe(response);
expect(error.isAxiosError).toBe(true);
});
it('should create an Error that can be serialized to JSON', function() {
// Attempting to serialize request and response results in
// TypeError: Converting circular structure to JSON
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
var error = createError('Boom!', { foo: 'bar' }, 'ESOMETHING', request, response);
var json = error.toJSON();
expect(json.message).toBe('Boom!');
expect(json.config).toEqual({ foo: 'bar' });
expect(json.code).toBe('ESOMETHING');
expect(json.status).toBe(200);
expect(json.request).toBe(undefined);
expect(json.response).toBe(undefined);
});
});

View File

@ -1,31 +0,0 @@
var enhanceError = require('../../../lib/core/enhanceError');
describe('core::enhanceError', function() {
it('should add config, code, request, response, and toJSON function to error', function() {
var error = new Error('Boom!');
var request = { path: '/foo' };
var response = { status: 200, data: { foo: 'bar' } };
enhanceError(error, { foo: 'bar' }, 'ESOMETHING', request, response);
expect(error.config).toEqual({ foo: 'bar' });
expect(error.code).toBe('ESOMETHING');
expect(error.request).toBe(request);
expect(error.response).toBe(response);
expect(typeof error.toJSON).toBe('function');
expect(error.isAxiosError).toBe(true);
});
it('should serialize to JSON with a status of null when there is no response', function() {
var error = new Error('Boom!');
var request = { path: '/foo' };
var response = undefined;
var errorAsJson = enhanceError(error, { foo: 'bar' }, 'ESOMETHING', request, response).toJSON();
expect(errorAsJson.status).toEqual(null);
});
it('should return error', function() {
var error = new Error('Boom!');
expect(enhanceError(error, { foo: 'bar' }, 'ESOMETHING')).toBe(error);
});
});

View File

@ -1,19 +1,18 @@
var createError = require('../../../lib/core/createError');
var enhanceError = require('../../../lib/core/enhanceError');
var AxiosError = require('../../../lib/core/AxiosError');
var isAxiosError = require('../../../lib/helpers/isAxiosError');
describe('helpers::isAxiosError', function () {
it('should return true if the error is created by core::createError', function () {
expect(isAxiosError(createError('Boom!', { foo: 'bar' })))
describe('helpers::isAxiosError', function() {
it('should return true if the error is created by core::createError', function() {
expect(isAxiosError(new AxiosError('Boom!', null, { foo: 'bar' })))
.toBe(true);
});
it('should return true if the error is enhanced by core::enhanceError', function () {
expect(isAxiosError(enhanceError(new Error('Boom!'), { foo: 'bar' })))
it('should return true if the error is enhanced by core::enhanceError', function() {
expect(isAxiosError(AxiosError.from(new Error('Boom!'), null, { foo: 'bar' })))
.toBe(true);
});
it('should return false if the error is a normal Error instance', function () {
it('should return false if the error is a normal Error instance', function() {
expect(isAxiosError(new Error('Boom!')))
.toBe(false);
});

View File

@ -13,8 +13,10 @@ describe('instance', function () {
for (var prop in axios) {
if ([
'Axios',
'AxiosError',
'create',
'Cancel',
'CanceledError',
'CancelToken',
'isCancel',
'all',

View File

@ -1,3 +1,5 @@
var AxiosError = require("../../lib/core/AxiosError");
describe('transform', function () {
beforeEach(function () {
jasmine.Ajax.install();
@ -64,6 +66,7 @@ describe('transform', function () {
setTimeout(function () {
expect(thrown).toBeTruthy();
expect(thrown.name).toContain('SyntaxError');
expect(thrown.code).toEqual(AxiosError.ERR_BAD_RESPONSE);
done();
}, 100);
});

View File

@ -0,0 +1,10 @@
var toFlatObject = require('../../../lib/utils').toFlatObject;
describe('utils::toFlatObject', function () {
it('should resolve object proto chain to a flat object representation', function () {
var a = {x: 1};
var b = Object.create(a, {y: {value: 2}});
var c = Object.create(b, {z: {value: 3}});
expect(toFlatObject(c)).toEqual({x: 1, y: 2, z: 3});
});
});

View File

@ -9,6 +9,7 @@ var fs = require('fs');
var path = require('path');
var pkg = require('./../../../package.json');
var server, proxy;
var AxiosError = require('../../../lib/core/AxiosError');
describe('supports http with nodejs', function () {
@ -51,7 +52,7 @@ describe('supports http with nodejs', function () {
setTimeout(function () {
assert.equal(success, false, 'request should not succeed');
assert.equal(failure, true, 'request should fail');
assert.equal(error.code, 'ERR_PARSE_TIMEOUT');
assert.equal(error.code, AxiosError.ERR_BAD_OPTION_VALUE);
assert.equal(error.message, 'error trying to parse `config.timeout` to int');
done();
}, 300);
@ -953,7 +954,7 @@ describe('supports http with nodejs', function () {
axios.get('http://localhost:4444/', {
cancelToken: source.token
}).catch(function (thrown) {
assert.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a Cancel object');
assert.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a CanceledError object');
assert.equal(thrown.message, 'Operation has been canceled.');
done();
});