From 28158bbaf9feede4a6582ce6bc53cd947d4db2fe Mon Sep 17 00:00:00 2001 From: Richard Tibbles Date: Wed, 28 Aug 2024 14:58:07 -0700 Subject: [PATCH] Migrate disconnectionErrorCodes into constants. --- kolibri/core/assets/src/constants.js | 2 + kolibri/core/assets/src/core-app/client.js | 4 +- .../assets/src/disconnectionErrorCodes.js | 1 - kolibri/core/assets/src/heartbeat.js | 15 +++-- .../assets/src/state/modules/core/actions.js | 10 +++- kolibri/core/assets/test/heartbeat.spec.js | 58 +++++++++---------- 6 files changed, 48 insertions(+), 42 deletions(-) delete mode 100644 kolibri/core/assets/src/disconnectionErrorCodes.js diff --git a/kolibri/core/assets/src/constants.js b/kolibri/core/assets/src/constants.js index b4ddbef3356..2d59d5a4649 100644 --- a/kolibri/core/assets/src/constants.js +++ b/kolibri/core/assets/src/constants.js @@ -198,3 +198,5 @@ export const Presets = Object.freeze({ // This should be kept in sync with the value in // kolibri/core/exams/constants.py export const MAX_QUESTIONS_PER_QUIZ_SECTION = 25; + +export const DisconnectionErrorCodes = [0, 502, 504, 511]; diff --git a/kolibri/core/assets/src/core-app/client.js b/kolibri/core/assets/src/core-app/client.js index a6ab675835a..0bed7ef724e 100644 --- a/kolibri/core/assets/src/core-app/client.js +++ b/kolibri/core/assets/src/core-app/client.js @@ -8,7 +8,7 @@ import heartbeat from 'kolibri.heartbeat'; import logger from 'kolibri.lib.logging'; import { get } from '@vueuse/core'; import useUser from 'kolibri.coreVue.composables.useUser'; -import errorCodes from '../disconnectionErrorCodes'; +import { DisconnectionErrorCodes } from 'kolibri.coreVue.vuex.constants'; import useConnection from '../composables/useConnection'; import clientFactory from './baseClient'; @@ -58,7 +58,7 @@ baseClient.interceptors.response.use( } // On every error, check to see if the status code is one of our designated // disconnection status codes. - if (errorCodes.includes(error.response.status)) { + if (DisconnectionErrorCodes.includes(error.response.status)) { // If so, set our heartbeat module to start monitoring the disconnection state heartbeat.monitorDisconnect(error.response.status); } diff --git a/kolibri/core/assets/src/disconnectionErrorCodes.js b/kolibri/core/assets/src/disconnectionErrorCodes.js deleted file mode 100644 index 77b91a55215..00000000000 --- a/kolibri/core/assets/src/disconnectionErrorCodes.js +++ /dev/null @@ -1 +0,0 @@ -export default [0, 502, 504, 511]; diff --git a/kolibri/core/assets/src/heartbeat.js b/kolibri/core/assets/src/heartbeat.js index 2301afa7c62..9f9cd8e69e6 100644 --- a/kolibri/core/assets/src/heartbeat.js +++ b/kolibri/core/assets/src/heartbeat.js @@ -5,10 +5,12 @@ import Lockr from 'lockr'; import urls from 'kolibri.urls'; import { get, set } from '@vueuse/core'; import useUser from 'kolibri.coreVue.composables.useUser'; +import { + DisconnectionErrorCodes, + SIGNED_OUT_DUE_TO_INACTIVITY, +} from 'kolibri.coreVue.vuex.constants'; import useConnection from './composables/useConnection'; import clientFactory from './core-app/baseClient'; -import { SIGNED_OUT_DUE_TO_INACTIVITY } from './constants'; -import errorCodes from './disconnectionErrorCodes'; import { createTryingToReconnectSnackbar, createDisconnectedSnackbar, @@ -62,7 +64,10 @@ export class HeartBeat { function (response) { // If the response does not have one of the disconnect error codes // then we have reconnected. - if (!get(heartbeat._connection.connected) && !errorCodes.includes(response.status)) { + if ( + !get(heartbeat._connection.connected) && + !DisconnectionErrorCodes.includes(response.status) + ) { // Not one of our 'disconnected' status codes, so we are connected again // Set connected and return the response here to prevent any further processing. heartbeat._setConnected(); @@ -73,7 +78,7 @@ export class HeartBeat { if (!get(heartbeat._connection.connected)) { // If the response does not have one of the disconnect error codes // then we have reconnected. - if (!errorCodes.includes(error.response.status)) { + if (!DisconnectionErrorCodes.includes(error.response.status)) { // Not one of our 'disconnected' status codes, so we are connected again // Set connected and return the response here to prevent any further processing. heartbeat._setConnected(); @@ -211,7 +216,7 @@ export class HeartBeat { .catch(error => { // An error occurred. logging.error('Session polling failed, with error: ', error); - if (errorCodes.includes(error.response.status)) { + if (DisconnectionErrorCodes.includes(error.response.status)) { // We had an error that indicates that we are disconnected, so start to monitor // the disconnection. return this.monitorDisconnect(error.response.status); diff --git a/kolibri/core/assets/src/state/modules/core/actions.js b/kolibri/core/assets/src/state/modules/core/actions.js index 4b7029a0863..8dc92ad295b 100644 --- a/kolibri/core/assets/src/state/modules/core/actions.js +++ b/kolibri/core/assets/src/state/modules/core/actions.js @@ -19,11 +19,15 @@ import Vue from 'kolibri.lib.vue'; import Lockr from 'lockr'; import { set, get } from '@vueuse/core'; import useUser from 'kolibri.coreVue.composables.useUser'; +import { + DisconnectionErrorCodes, + LoginErrors, + ERROR_CONSTANTS, + UPDATE_MODAL_DISMISSED, +} from 'kolibri.coreVue.vuex.constants'; import { baseSessionState } from '../session'; -import { LoginErrors, ERROR_CONSTANTS, UPDATE_MODAL_DISMISSED } from '../../../constants'; import { browser, os } from '../../../utils/browserInfo'; import useConnection from '../../../composables/useConnection'; -import errorCodes from './../../../disconnectionErrorCodes.js'; const logging = logger.getLogger(__filename); @@ -79,7 +83,7 @@ export function handleApiError(store, { error, reloadOnReconnect = false } = {}) if (typeof error === 'object' && !(error instanceof Error)) { errorString = JSON.stringify(error, null, 2); } else if (error.response) { - if (errorCodes.includes(error.response.status)) { + if (DisconnectionErrorCodes.includes(error.response.status)) { // Do not log errors for disconnections, as it disrupts the user experience // and should already be being handled by our disconnection overlay. set(useConnection().reloadOnReconnect, reloadOnReconnect); diff --git a/kolibri/core/assets/test/heartbeat.spec.js b/kolibri/core/assets/test/heartbeat.spec.js index f189a088e74..471c6b9221a 100644 --- a/kolibri/core/assets/test/heartbeat.spec.js +++ b/kolibri/core/assets/test/heartbeat.spec.js @@ -5,8 +5,8 @@ import * as serverClock from 'kolibri.utils.serverClock'; import { get, set } from '@vueuse/core'; import useSnackbar, { useSnackbarMock } from 'kolibri.coreVue.composables.useSnackbar'; import { ref } from 'kolibri.lib.vueCompositionApi'; +import { DisconnectionErrorCodes } from 'kolibri.coreVue.vuex.constants'; import { HeartBeat } from '../src/heartbeat.js'; -import disconnectionErrorCodes from '../src/disconnectionErrorCodes'; import { trs } from '../src/disconnection'; import coreModule from '../src/state/modules/core'; import { stubWindowLocation } from 'testUtils'; // eslint-disable-line @@ -264,20 +264,18 @@ describe('HeartBeat', function () { // Rather it is the status code that our request client library returns // when the connection is refused by the host, or is otherwise unable to connect. // What happens for a zero code is tested later in this file. - disconnectionErrorCodes - .filter(code => code !== 0) - .forEach(errorCode => { - it('should call monitorDisconnect if it receives error code ' + errorCode, function () { - const monitorStub = jest.spyOn(heartBeat, 'monitorDisconnect'); - mock.put(/.*/, { - status: errorCode, - headers: { 'Content-Type': 'application/json' }, - }); - return heartBeat._checkSession().finally(() => { - expect(monitorStub).toHaveBeenCalledTimes(1); - }); + DisconnectionErrorCodes.filter(code => code !== 0).forEach(errorCode => { + it('should call monitorDisconnect if it receives error code ' + errorCode, function () { + const monitorStub = jest.spyOn(heartBeat, 'monitorDisconnect'); + mock.put(/.*/, { + status: errorCode, + headers: { 'Content-Type': 'application/json' }, + }); + return heartBeat._checkSession().finally(() => { + expect(monitorStub).toHaveBeenCalledTimes(1); }); }); + }); }); describe('when not connected', function () { let snackbar; @@ -297,26 +295,24 @@ describe('HeartBeat', function () { expect(get(snackbar.snackbarIsVisible)).toEqual(true); expect(get(snackbar.snackbarOptions).text).toEqual(trs.$tr('tryingToReconnect')); }); - disconnectionErrorCodes - .filter(code => code !== 0) - .forEach(errorCode => { - it('should set snackbar to disconnected for error code ' + errorCode, function () { - jest.spyOn(heartBeat, 'monitorDisconnect'); - mock.put(/.*/, { - status: errorCode, - headers: { 'Content-Type': 'application/json' }, - }); - heartBeat._wait = jest.fn(); - return heartBeat._checkSession().finally(() => { - expect(get(snackbar.snackbarIsVisible)).toEqual(true); - expect( - get(snackbar.snackbarOptions).text.startsWith( - 'Disconnected from server. Will try to reconnect in', - ), - ).toEqual(true); - }); + DisconnectionErrorCodes.filter(code => code !== 0).forEach(errorCode => { + it('should set snackbar to disconnected for error code ' + errorCode, function () { + jest.spyOn(heartBeat, 'monitorDisconnect'); + mock.put(/.*/, { + status: errorCode, + headers: { 'Content-Type': 'application/json' }, + }); + heartBeat._wait = jest.fn(); + return heartBeat._checkSession().finally(() => { + expect(get(snackbar.snackbarIsVisible)).toEqual(true); + expect( + get(snackbar.snackbarOptions).text.startsWith( + 'Disconnected from server. Will try to reconnect in', + ), + ).toEqual(true); }); }); + }); it('should set snackbar to disconnected for error code 0', function () { jest.spyOn(heartBeat, 'monitorDisconnect'); mock.put(/.*/, () => Promise.reject(new Error()));