diff --git a/package-lock.json b/package-lock.json index 28700c3..e5cfb22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@oat-sa/tao-core-sdk", - "version": "1.7.0", + "version": "1.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6a40bec..38a9f75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oat-sa/tao-core-sdk", - "version": "1.7.0", + "version": "1.8.0", "displayName": "TAO Core SDK", "description": "Core libraries of TAO", "homepage": "https://github.com/oat-sa/tao-core-sdk-fe#readme", diff --git a/src/core/error/ApiError.js b/src/core/error/ApiError.js new file mode 100644 index 0000000..9f3f11e --- /dev/null +++ b/src/core/error/ApiError.js @@ -0,0 +1,49 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +import errorTypes from 'core/error/types'; + +/** + * Errors sent by HTTP API / backend + */ +//eslint-disable-next-line +export default class ApiError extends Error { + + /** + * Instantiate an error + * @param {string} message - the error message + * @param {number} errorCode - the API error code + * @param {Object} response - the full response object + * @param {boolean} [recoverable=true] - can the user recover after having such error ? + * @param {...} params - additional error parameters (line, etc.) + */ + constructor(message, errorCode, response, recoverable = true, ...params) { + super(message, ...params); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, ApiError); + } + + this.name = 'ApiError'; + this.message = message; + this.errorCode = errorCode; + this.response = response; + this.recoverable = !!recoverable; + this.type = errorTypes.api; + } +} diff --git a/src/core/error/AuthError.js b/src/core/error/AuthError.js new file mode 100644 index 0000000..7e82c61 --- /dev/null +++ b/src/core/error/AuthError.js @@ -0,0 +1,45 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +import errorTypes from 'core/error/types'; + +/** + * Error due to client side authentication mechanisms + */ +//eslint-disable-next-line +export default class AuthError extends Error { + + /** + * Instantiate an error + * @param {string} message - the error message + * @param {Boolean} [recoverable=true] - can the user recover after having such error ? + * @param {...} params - additional error parameters (line, etc.) + */ + constructor(message, recoverable = true, ...params) { + super(message, ...params); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, AuthError); + } + + this.name = 'AuthError'; + this.message = message; + this.recoverable = !!recoverable; + this.type = errorTypes.auth; + } +} diff --git a/src/core/error/NetworkError.js b/src/core/error/NetworkError.js new file mode 100644 index 0000000..45a790d --- /dev/null +++ b/src/core/error/NetworkError.js @@ -0,0 +1,49 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +import errorTypes from 'core/error/types'; + +/** + * Network errors + */ +//eslint-disable-next-line +export default class NetworkError extends Error { + + /** + * Instantiate an error + * @param {string} message - the error message + * @param {number} [errorCode] - the HTTP status if any + * @param {Object} [response] - the full response object if any + * @param {boolean} [recoverable=true] - can the user recover after having such error ? + * @param {...} params - additional error parameters (line, etc.) + */ + constructor(message, errorCode, response, recoverable = true, ...params) { + super(message, ...params); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, NetworkError); + } + + this.name = 'NetworkError'; + this.message = message; + this.errorCode = errorCode; + this.response = response; + this.recoverable = !!recoverable; + this.type = errorTypes.network; + } +} diff --git a/src/core/error/RenderingError.js b/src/core/error/RenderingError.js new file mode 100644 index 0000000..59ac60f --- /dev/null +++ b/src/core/error/RenderingError.js @@ -0,0 +1,45 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +import errorTypes from 'core/error/types'; + +/** + * Error in rendering + */ +//eslint-disable-next-line +export default class RenderingError extends Error { + + /** + * Instantiate an error + * @param {string} message - the error message + * @param {Boolean} [recoverable=true] - can the user recover after having such error ? + * @param {...} params - additional error parameters (line, etc.) + */ + constructor(message, recoverable = true, ...params) { + super(message, ...params); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, RenderingError); + } + + this.name = 'RenderingError'; + this.message = message; + this.recoverable = !!recoverable; + this.type = errorTypes.rendering; + } +} diff --git a/src/core/error/TimeoutError.js b/src/core/error/TimeoutError.js new file mode 100644 index 0000000..f8dcf96 --- /dev/null +++ b/src/core/error/TimeoutError.js @@ -0,0 +1,47 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +import errorTypes from 'core/error/types'; + +/** + * Error when an action times out + */ +//eslint-disable-next-line +export default class TimeoutError extends Error { + + /** + * Instantiate an error + * @param {string} message - the error message + * @param {number} timeout - the timeout value + * @param {boolean} [recoverable=true] - can the user recover after having such error ? + * @param {...} params - additional error parameters (line, etc.) + */ + constructor(message, timeout, recoverable = true, ...params) { + super(message, ...params); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, TimeoutError); + } + + this.name = 'TimeoutError'; + this.message = message; + this.timeout = timeout; + this.recoverable = !!recoverable; + this.type = errorTypes.timeout; + } +} diff --git a/src/core/error/UserError.js b/src/core/error/UserError.js new file mode 100644 index 0000000..3e49d90 --- /dev/null +++ b/src/core/error/UserError.js @@ -0,0 +1,45 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +import errorTypes from 'core/error/types'; + +/** + * Error due to wrong user input + */ +//eslint-disable-next-line +export default class UserError extends Error { + + /** + * Instantiate an error + * @param {string} message - the error message + * @param {boolean} [recoverable=true] - can the user recover after having such error ? + * @param {...} params - additional error parameters (line, etc.) + */ + constructor(message, recoverable = true, ...params) { + super(message, ...params); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, UserError); + } + + this.name = 'UserError'; + this.message = message; + this.recoverable = !!recoverable; + this.type = errorTypes.user; + } +} diff --git a/src/core/error/types.js b/src/core/error/types.js new file mode 100644 index 0000000..10cdaf0 --- /dev/null +++ b/src/core/error/types.js @@ -0,0 +1,37 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; + */ + +export default Object.freeze({ + // the server API is not successful: 500, 412, 403, etc. + api: 'api', + + // any network error: CORS, offline, etc. + network: 'network', + + // timeout error: an action cannot be performed in the given time + timeout: 'timeout', + + // authentication: internal error about authentication (token pool issue, etc.) + auth: 'auth', + + // errors due to user's input: wrong data range, etc. + user: 'user', + + // rendering error: an interface, a component fails to render + rendering: 'rendering' +}); diff --git a/src/core/fetchRequest.js b/src/core/fetchRequest.js index 8a8f6be..87fe8e9 100644 --- a/src/core/fetchRequest.js +++ b/src/core/fetchRequest.js @@ -16,6 +16,10 @@ * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; */ +import ApiError from 'core/error/ApiError'; +import NetworkError from 'core/error/NetworkError'; +import TimeoutError from 'core/error/TimeoutError'; + /** * !!! IE11 requires polyfill https://www.npmjs.com/package/whatwg-fetch * Creates an HTTP request to the url based on the provided parameters @@ -49,14 +53,16 @@ const requestFactory = (url, options) => { }); } - flow = flow.then(() => + flow = flow.then(() => ( Promise.race([ fetch(url, options), new Promise((resolve, reject) => { - setTimeout(() => reject(new Error('Timeout')), options.timeout); + setTimeout(() => { + reject(new TimeoutError('Timeout', options.timeout)); + }, options.timeout); }) ]) - ); + )); if (options.jwtTokenHandler) { flow = flow.then(response => { @@ -102,14 +108,26 @@ const requestFactory = (url, options) => { // create error let err; if (response.errorCode) { - err = new Error( - `${response.errorCode} : ${response.errorMsg || response.errorMessage || response.error}` + err = new ApiError( + `${response.errorCode} : ${response.errorMsg || response.errorMessage || response.error}`, + response.errorCode, + originalResponse ); } else { - err = new Error(`${responseCode} : Request error`); + err = new NetworkError( + `${responseCode} : Request error`, + responseCode || 0, + originalResponse + ); } - err.response = originalResponse; throw err; + }) + .catch(err => { + if(!err.type){ + //offline, CORS, etc. + return Promise.reject(new NetworkError(err.message, 0)); + } + return Promise.reject(err); }); return flow; diff --git a/test/core/error/api/test.html b/test/core/error/api/test.html new file mode 100644 index 0000000..3e1be66 --- /dev/null +++ b/test/core/error/api/test.html @@ -0,0 +1,20 @@ + + +
+ + + + + + + + + diff --git a/test/core/error/api/test.js b/test/core/error/api/test.js new file mode 100644 index 0000000..1b96e68 --- /dev/null +++ b/test/core/error/api/test.js @@ -0,0 +1,49 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA + * + */ + +define(['core/error/types', 'core/error/ApiError'], function (errorTypes, ApiError) { + 'use strict'; + + QUnit.module('ApiError'); + + QUnit.test('construct', assert => { + assert.expect(6); + + const response = { success: false, errorCode: 500 }; + const err = new ApiError('Server error', 500, response, true); + assert.equal(err.name, 'ApiError'); + assert.equal(err.type, errorTypes.api); + assert.equal(err.message, 'Server error'); + assert.equal(err.errorCode, 500); + assert.deepEqual(err.response, response); + assert.equal(err.recoverable, true); + }); + + QUnit.test('throw', assert => { + assert.expect(1); + + assert.throws( + () => { + throw new ApiError('Invalid request', 412, { success: false, errorCode: 500 }, true, 'foo.js', 123); + }, + ApiError, + 'Thrown error type is matching' + ); + }); +}); diff --git a/test/core/error/auth/test.html b/test/core/error/auth/test.html new file mode 100644 index 0000000..28905d2 --- /dev/null +++ b/test/core/error/auth/test.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/test/core/error/auth/test.js b/test/core/error/auth/test.js new file mode 100644 index 0000000..59e2de1 --- /dev/null +++ b/test/core/error/auth/test.js @@ -0,0 +1,46 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA + * + */ + +define(['core/error/types', 'core/error/AuthError'], function (errorTypes, AuthError) { + 'use strict'; + + QUnit.module('AuthError'); + + QUnit.test('construct', assert => { + assert.expect(4); + + const err = new AuthError('Token pool reading error', false); + assert.equal(err.name, 'AuthError'); + assert.equal(err.type, errorTypes.auth); + assert.equal(err.message, 'Token pool reading error'); + assert.equal(err.recoverable, false); + }); + + QUnit.test('throw', assert => { + assert.expect(1); + + assert.throws( + () => { + throw new AuthError('Wrong key'); + }, + AuthError, + 'Thrown error type is matching' + ); + }); +}); diff --git a/test/core/error/network/test.html b/test/core/error/network/test.html new file mode 100644 index 0000000..e1b1a45 --- /dev/null +++ b/test/core/error/network/test.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/test/core/error/network/test.js b/test/core/error/network/test.js new file mode 100644 index 0000000..8067ea2 --- /dev/null +++ b/test/core/error/network/test.js @@ -0,0 +1,48 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA + * + */ + +define(['core/error/types', 'core/error/NetworkError'], function (errorTypes, NetworkError) { + 'use strict'; + + QUnit.module('NetworkError'); + + QUnit.test('construct', assert => { + assert.expect(6); + + const err = new NetworkError('No connection', 0, null, true); + assert.equal(err.name, 'NetworkError'); + assert.equal(err.type, errorTypes.network); + assert.equal(err.message, 'No connection'); + assert.equal(err.errorCode, 0); + assert.equal(err.response, null); + assert.equal(err.recoverable, true); + }); + + QUnit.test('throw', assert => { + assert.expect(1); + + assert.throws( + () => { + throw new NetworkError('Port closed during the connection'); + }, + NetworkError, + 'Thrown error type is matching' + ); + }); +}); diff --git a/test/core/error/rendering/test.html b/test/core/error/rendering/test.html new file mode 100644 index 0000000..a61bcf9 --- /dev/null +++ b/test/core/error/rendering/test.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/test/core/error/rendering/test.js b/test/core/error/rendering/test.js new file mode 100644 index 0000000..ccc8a70 --- /dev/null +++ b/test/core/error/rendering/test.js @@ -0,0 +1,46 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA + * + */ + +define(['core/error/types', 'core/error/RenderingError'], function (errorTypes, RenderingError) { + 'use strict'; + + QUnit.module('RenderingError'); + + QUnit.test('construct', assert => { + assert.expect(4); + + const err = new RenderingError('Fail to render an item due to inconsitent model.', true); + assert.equal(err.name, 'RenderingError'); + assert.equal(err.type, errorTypes.rendering); + assert.equal(err.message, 'Fail to render an item due to inconsitent model.'); + assert.equal(err.recoverable, true); + }); + + QUnit.test('throw', assert => { + assert.expect(1); + + assert.throws( + () => { + throw new RenderingError('No mount point'); + }, + RenderingError, + 'Thrown error type is matching' + ); + }); +}); diff --git a/test/core/error/timeout/test.html b/test/core/error/timeout/test.html new file mode 100644 index 0000000..b70dd91 --- /dev/null +++ b/test/core/error/timeout/test.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/test/core/error/timeout/test.js b/test/core/error/timeout/test.js new file mode 100644 index 0000000..54548d7 --- /dev/null +++ b/test/core/error/timeout/test.js @@ -0,0 +1,48 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA + * + */ + +define(['core/error/types', 'core/error/TimeoutError'], function (errorTypes, TimeoutError) { + 'use strict'; + + QUnit.module('TimeoutError'); + + QUnit.test('construct', assert => { + assert.expect(5); + + const err = new TimeoutError('Submition timeout', 30, true); + + assert.equal(err.name, 'TimeoutError'); + assert.equal(err.type, errorTypes.timeout); + assert.equal(err.message, 'Submition timeout'); + assert.equal(err.timeout, 30); + assert.equal(err.recoverable, true); + }); + + QUnit.test('throw', assert => { + assert.expect(1); + + assert.throws( + () => { + throw new TimeoutError('Unable to import'); + }, + TimeoutError, + 'Thrown error type is matching' + ); + }); +}); diff --git a/test/core/error/user/test.html b/test/core/error/user/test.html new file mode 100644 index 0000000..7200a78 --- /dev/null +++ b/test/core/error/user/test.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/test/core/error/user/test.js b/test/core/error/user/test.js new file mode 100644 index 0000000..cdad3b8 --- /dev/null +++ b/test/core/error/user/test.js @@ -0,0 +1,49 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2020 (original work) Open Assessment Technologies SA + * + */ + +/** + * Test the error types + */ +define(['core/error/types', 'core/error/UserError'], function (errorTypes, UserError) { + 'use strict'; + + QUnit.module('UserError'); + + QUnit.test('construct', assert => { + assert.expect(4); + + const err = new UserError('This value is not a date', true); + assert.equal(err.name, 'UserError'); + assert.equal(err.type, errorTypes.user); + assert.equal(err.message, 'This value is not a date'); + assert.equal(err.recoverable, true); + }); + + QUnit.test('throw', assert => { + assert.expect(1); + + assert.throws( + () => { + throw new UserError('The text is too long'); + }, + UserError, + 'Thrown error type is matching' + ); + }); +}); diff --git a/test/core/fetchRequest/test.js b/test/core/fetchRequest/test.js index 693eb00..5c5bc28 100644 --- a/test/core/fetchRequest/test.js +++ b/test/core/fetchRequest/test.js @@ -16,10 +16,13 @@ * Copyright (c) 2020 (original work) Open Assessment Technologies SA ; */ -define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock'], ( +define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock', 'core/error/ApiError','core/error/NetworkError', 'core/error/TimeoutError'], ( request, jwtTokenHandlerFactory, - fetchMock + fetchMock, + ApiError, + NetworkError, + TimeoutError ) => { 'use strict'; @@ -130,7 +133,7 @@ define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock'], ( }); QUnit.test('request returns with a correct error response if success false', assert => { - assert.expect(2); + assert.expect(4); const done = assert.async(); fetchMock.mock( @@ -141,8 +144,10 @@ define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock'], ( ); request('/foo').catch(error => { + assert.ok(error instanceof ApiError); assert.equal(error.message, 'ABC123 : Cannot trigger ABC'); assert.equal(error.response.status, 406); + assert.equal(error.errorCode, 'ABC123'); done(); }); }); @@ -272,7 +277,7 @@ define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock'], ( ); QUnit.test('request fails if token is refreshed and is still not valid', function (assert) { - assert.expect(2); + assert.expect(4); const done = assert.async(); const refreshToken = 'refreshToken'; @@ -288,8 +293,10 @@ define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock'], ( .then(() => this.jwtTokenHandler.storeAccessToken(accessToken)) .then(() => request(url, { jwtTokenHandler: this.jwtTokenHandler })) .catch(error => { + assert.ok(error instanceof NetworkError); assert.equal(error.message, '401 : Request error'); assert.equal(error.response.status, 401); + assert.equal(error.errorCode, 401); done(); }); }); @@ -298,6 +305,6 @@ define(['core/fetchRequest', 'core/jwt/jwtTokenHandler', 'fetch-mock'], ( assert.expect(1); fetchMock.mock('/', new Promise(resolve => setTimeout(resolve, 2000))); - assert.rejects(request('/', { timeout: 1000 }), /Timeout/); + assert.rejects(request('/', { timeout: 1000 }), TimeoutError); }); });