From 254e9b02993a979a484151b145e76f0eee2cd901 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 26 Apr 2023 18:48:04 +0100 Subject: [PATCH 1/5] Consolidate login errors --- src/Lifecycle.ts | 16 +--- src/components/structures/auth/Login.tsx | 112 +---------------------- src/i18n/strings/en_EN.json | 18 ++-- src/utils/ErrorUtils.tsx | 112 ++++++++++++++++++++++- 4 files changed, 128 insertions(+), 130 deletions(-) diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 3c679c8a6d8..763cfa1e87f 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -63,6 +63,7 @@ import { Action } from "./dispatcher/actions"; import AbstractLocalStorageSettingsHandler from "./settings/handlers/AbstractLocalStorageSettingsHandler"; import { OverwriteLoginPayload } from "./dispatcher/payloads/OverwriteLoginPayload"; import { SdkContextClass } from "./contexts/SDKContext"; +import { messageForLoginError } from "./utils/ErrorUtils"; const HOMESERVER_URL_KEY = "mx_hs_url"; const ID_SERVER_URL_KEY = "mx_is_url"; @@ -230,17 +231,10 @@ export function attemptTokenLogin( .catch((err) => { Modal.createDialog(ErrorDialog, { title: _t("We couldn't log you in"), - description: - err.name === "ConnectionError" - ? _t( - "Your homeserver was unreachable and was not able to log you in. Please try again. " + - "If this continues, please contact your homeserver administrator.", - ) - : _t( - "Your homeserver rejected your log in attempt. " + - "This could be due to things just taking too long. Please try again. " + - "If this continues, please contact your homeserver administrator.", - ), + description: messageForLoginError(err, { + hsUrl: homeserver, + hsName: homeserver, + }), button: _t("Try again"), onFinished: (tryAgain) => { if (tryAgain) { diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 43147266a4b..744c473e7a1 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -15,15 +15,13 @@ limitations under the License. */ import React, { ReactNode } from "react"; -import { ConnectionError, MatrixError } from "matrix-js-sdk/src/http-api"; import classNames from "classnames"; import { logger } from "matrix-js-sdk/src/logger"; import { ISSOFlow, LoginFlow, SSOAction } from "matrix-js-sdk/src/@types/auth"; import { _t, _td } from "../../../languageHandler"; import Login from "../../../Login"; -import SdkConfig from "../../../SdkConfig"; -import { messageForResourceLimitError } from "../../../utils/ErrorUtils"; +import { messageForConnectionError, messageForLoginError } from "../../../utils/ErrorUtils"; import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils"; import AuthPage from "../../views/auth/AuthPage"; import PlatformPeg from "../../../PlatformPeg"; @@ -212,56 +210,15 @@ export default class LoginComponent extends React.PureComponent this.props.onLoggedIn(data, password); }, (error) => { - if (this.unmounted) { - return; - } - let errorText: ReactNode; + if (this.unmounted) return; // Some error strings only apply for logging in const usingEmail = username && username.indexOf("@") > 0; - if (error.httpStatus === 400 && usingEmail) { - errorText = _t("This homeserver does not support login using email address."); - } else if (error.errcode === "M_RESOURCE_LIMIT_EXCEEDED") { - const errorTop = messageForResourceLimitError(error.data.limit_type, error.data.admin_contact, { - "monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."), - "hs_blocked": _td("This homeserver has been blocked by its administrator."), - "": _td("This homeserver has exceeded one of its resource limits."), - }); - const errorDetail = messageForResourceLimitError(error.data.limit_type, error.data.admin_contact, { - "": _td("Please contact your service administrator to continue using this service."), - }); - errorText = ( -
-
{errorTop}
-
{errorDetail}
-
- ); - } else if (error.httpStatus === 401 || error.httpStatus === 403) { - if (error.errcode === "M_USER_DEACTIVATED") { - errorText = _t("This account has been deactivated."); - } else if (SdkConfig.get("disable_custom_urls")) { - errorText = ( -
-
{_t("Incorrect username and/or password.")}
-
- {_t("Please note you are logging into the %(hs)s server, not matrix.org.", { - hs: this.props.serverConfig.hsName, - })} -
-
- ); - } else { - errorText = _t("Incorrect username and/or password."); - } - } else { - // other errors, not specific to doing a password login - errorText = this.errorTextFromError(error); - } this.setState({ busy: false, busyLoggingIn: false, - errorText: errorText, + errorText: messageForLoginError(error, this.props.serverConfig, usingEmail), // 401 would be the sensible status code for 'incorrect password' // but the login API gives a 403 https://matrix.org/jira/browse/SYN-744 // mentions this (although the bug is for UI auth which is not this) @@ -425,7 +382,7 @@ export default class LoginComponent extends React.PureComponent }, (err) => { this.setState({ - errorText: this.errorTextFromError(err), + errorText: messageForConnectionError(err, this.props.serverConfig), loginIncorrect: false, canTryLogin: false, }); @@ -448,67 +405,6 @@ export default class LoginComponent extends React.PureComponent return true; }; - private errorTextFromError(err: MatrixError): ReactNode { - let errCode = err.errcode; - if (!errCode && err.httpStatus) { - errCode = "HTTP " + err.httpStatus; - } - - let errorText: ReactNode = - _t("There was a problem communicating with the homeserver, please try again later.") + - (errCode ? " (" + errCode + ")" : ""); - - if (err instanceof ConnectionError) { - if ( - window.location.protocol === "https:" && - (this.props.serverConfig.hsUrl.startsWith("http:") || !this.props.serverConfig.hsUrl.startsWith("http")) - ) { - errorText = ( - - {_t( - "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " + - "Either use HTTPS or enable unsafe scripts.", - {}, - { - a: (sub) => { - return ( - - {sub} - - ); - }, - }, - )} - - ); - } else { - errorText = ( - - {_t( - "Can't connect to homeserver - please check your connectivity, ensure your " + - "homeserver's SSL certificate is trusted, and that a browser extension " + - "is not blocking requests.", - {}, - { - a: (sub) => ( - - {sub} - - ), - }, - )} - - ); - } - } - - return errorText; - } - public renderLoginComponentForFlows(): ReactNode { if (!this.state.flows) return null; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4b71b883b05..dde0333ab95 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -103,8 +103,6 @@ "We couldn't log you in": "We couldn't log you in", "We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.": "We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.", "Try again": "Try again", - "Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.": "Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.", - "Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.": "Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.", "Database unexpectedly closed": "Database unexpectedly closed", "This may be caused by having the app open in multiple tabs or due to clearing browser data.": "This may be caused by having the app open in multiple tabs or due to clearing browser data.", "Reload": "Reload", @@ -705,6 +703,14 @@ "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.", "Please contact your service administrator to continue using the service.": "Please contact your service administrator to continue using the service.", "Unable to connect to Homeserver. Retrying…": "Unable to connect to Homeserver. Retrying…", + "This homeserver does not support login using email address.": "This homeserver does not support login using email address.", + "Please contact your service administrator to continue using this service.": "Please contact your service administrator to continue using this service.", + "This account has been deactivated.": "This account has been deactivated.", + "Incorrect username and/or password.": "Incorrect username and/or password.", + "Please note you are logging into the %(hs)s server, not matrix.org.": "Please note you are logging into the %(hs)s server, not matrix.org.", + "There was a problem communicating with the homeserver, please try again later.": "There was a problem communicating with the homeserver, please try again later.", + "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.", + "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.", "%(items)s and %(count)s others|other": "%(items)s and %(count)s others", "%(items)s and %(count)s others|one": "%(items)s and one other", "%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s", @@ -3552,16 +3558,8 @@ "Invalid base_url for m.identity_server": "Invalid base_url for m.identity_server", "Identity server URL does not appear to be a valid identity server": "Identity server URL does not appear to be a valid identity server", "General failure": "General failure", - "This homeserver does not support login using email address.": "This homeserver does not support login using email address.", - "Please contact your service administrator to continue using this service.": "Please contact your service administrator to continue using this service.", - "This account has been deactivated.": "This account has been deactivated.", - "Incorrect username and/or password.": "Incorrect username and/or password.", - "Please note you are logging into the %(hs)s server, not matrix.org.": "Please note you are logging into the %(hs)s server, not matrix.org.", "Failed to perform homeserver discovery": "Failed to perform homeserver discovery", "This homeserver doesn't offer any login flows which are supported by this client.": "This homeserver doesn't offer any login flows which are supported by this client.", - "There was a problem communicating with the homeserver, please try again later.": "There was a problem communicating with the homeserver, please try again later.", - "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.", - "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.", "Syncing…": "Syncing…", "Signing In…": "Signing In…", "If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while", diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index e45e3091a1a..9a51a4e6caf 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -15,9 +15,11 @@ limitations under the License. */ import React, { ReactNode } from "react"; -import { MatrixError } from "matrix-js-sdk/src/http-api"; +import { MatrixError, ConnectionError } from "matrix-js-sdk/src/http-api"; import { _t, _td, Tags, TranslatedString } from "../languageHandler"; +import SdkConfig from "../SdkConfig"; +import { ValidatedServerConfig } from "./ValidatedServerConfig"; /** * Produce a translated error message for a @@ -81,3 +83,111 @@ export function messageForSyncError(err: Error): ReactNode { return
{_t("Unable to connect to Homeserver. Retrying…")}
; } } + +export function messageForLoginError( + err: MatrixError, + serverConfig: Pick, + usingEmail = false, +): ReactNode { + if (err.httpStatus === 400 && usingEmail) { + return _t("This homeserver does not support login using email address."); + } else if (err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") { + const errorTop = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, { + "monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."), + "hs_blocked": _td("This homeserver has been blocked by its administrator."), + "": _td("This homeserver has exceeded one of its resource limits."), + }); + const errorDetail = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, { + "": _td("Please contact your service administrator to continue using this service."), + }); + return ( +
+
{errorTop}
+
{errorDetail}
+
+ ); + } else if (err.httpStatus === 401 || err.httpStatus === 403) { + if (err.errcode === "M_USER_DEACTIVATED") { + return _t("This account has been deactivated."); + } else if (SdkConfig.get("disable_custom_urls")) { + return ( +
+
{_t("Incorrect username and/or password.")}
+
+ {_t("Please note you are logging into the %(hs)s server, not matrix.org.", { + hs: serverConfig.hsName, + })} +
+
+ ); + } else { + return _t("Incorrect username and/or password."); + } + } else { + return messageForConnectionError(err, serverConfig); + } +} + +export function messageForConnectionError( + err: MatrixError, + serverConfig: Pick, +): ReactNode { + let errCode = err.errcode; + if (!errCode && err.httpStatus) { + errCode = "HTTP " + err.httpStatus; + } + + let errorText: ReactNode = + _t("There was a problem communicating with the homeserver, please try again later.") + + (errCode ? " (" + errCode + ")" : ""); + + if (err instanceof ConnectionError) { + if ( + window.location.protocol === "https:" && + (serverConfig.hsUrl.startsWith("http:") || !serverConfig.hsUrl.startsWith("http")) + ) { + errorText = ( + + {_t( + "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " + + "Either use HTTPS or enable unsafe scripts.", + {}, + { + a: (sub) => { + return ( + + {sub} + + ); + }, + }, + )} + + ); + } else { + errorText = ( + + {_t( + "Can't connect to homeserver - please check your connectivity, ensure your " + + "homeserver's SSL certificate is trusted, and that a browser extension " + + "is not blocking requests.", + {}, + { + a: (sub) => ( + + {sub} + + ), + }, + )} + + ); + } + } + + return errorText; +} From bb97d0a264eda9e14f50a40d3ede816819b0d057 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 27 Apr 2023 07:21:45 +0100 Subject: [PATCH 2/5] Consolidate strings further --- src/components/structures/auth/Login.tsx | 9 +++- .../structures/auth/Registration.tsx | 18 +++---- src/i18n/strings/en_EN.json | 5 +- src/utils/ErrorUtils.tsx | 51 +++++++++++-------- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 744c473e7a1..015ed6bbee9 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -212,13 +212,18 @@ export default class LoginComponent extends React.PureComponent (error) => { if (this.unmounted) return; + let errorText: ReactNode; // Some error strings only apply for logging in - const usingEmail = username && username.indexOf("@") > 0; + if (error.httpStatus === 400 && username && username.indexOf("@") > 0) { + errorText = _t("This homeserver does not support login using email address."); + } else { + errorText = messageForLoginError(error, this.props.serverConfig); + } this.setState({ busy: false, busyLoggingIn: false, - errorText: messageForLoginError(error, this.props.serverConfig, usingEmail), + errorText, // 401 would be the sensible status code for 'incorrect password' // but the login API gives a 403 https://matrix.org/jira/browse/SYN-744 // mentions this (although the bug is for UI auth which is not this) diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 15dcda4bc29..86d909748e0 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -21,8 +21,8 @@ import classNames from "classnames"; import { logger } from "matrix-js-sdk/src/logger"; import { ISSOFlow, SSOAction } from "matrix-js-sdk/src/@types/auth"; -import { _t, _td } from "../../../languageHandler"; -import { messageForResourceLimitError } from "../../../utils/ErrorUtils"; +import { _t } from "../../../languageHandler"; +import { adminContactStrings, messageForResourceLimitError, resourceLimitStrings } from "../../../utils/ErrorUtils"; import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils"; import * as Lifecycle from "../../../Lifecycle"; import { IMatrixClientCreds, MatrixClientPeg } from "../../../MatrixClientPeg"; @@ -313,17 +313,15 @@ export default class Registration extends React.Component { let errorText: ReactNode = (response as Error).message || (response as Error).toString(); // can we give a better error message? if (response instanceof MatrixError && response.errcode === "M_RESOURCE_LIMIT_EXCEEDED") { - const errorTop = messageForResourceLimitError(response.data.limit_type, response.data.admin_contact, { - "monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."), - "hs_blocked": _td("This homeserver has been blocked by its administrator."), - "": _td("This homeserver has exceeded one of its resource limits."), - }); + const errorTop = messageForResourceLimitError( + response.data.limit_type, + response.data.admin_contact, + resourceLimitStrings, + ); const errorDetail = messageForResourceLimitError( response.data.limit_type, response.data.admin_contact, - { - "": _td("Please contact your service administrator to continue using this service."), - }, + adminContactStrings, ); errorText = (
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index dde0333ab95..8e305639488 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -701,10 +701,8 @@ "This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.", "This homeserver has been blocked by its administrator.": "This homeserver has been blocked by its administrator.", "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.", - "Please contact your service administrator to continue using the service.": "Please contact your service administrator to continue using the service.", - "Unable to connect to Homeserver. Retrying…": "Unable to connect to Homeserver. Retrying…", - "This homeserver does not support login using email address.": "This homeserver does not support login using email address.", "Please contact your service administrator to continue using this service.": "Please contact your service administrator to continue using this service.", + "Unable to connect to Homeserver. Retrying…": "Unable to connect to Homeserver. Retrying…", "This account has been deactivated.": "This account has been deactivated.", "Incorrect username and/or password.": "Incorrect username and/or password.", "Please note you are logging into the %(hs)s server, not matrix.org.": "Please note you are logging into the %(hs)s server, not matrix.org.", @@ -3558,6 +3556,7 @@ "Invalid base_url for m.identity_server": "Invalid base_url for m.identity_server", "Identity server URL does not appear to be a valid identity server": "Identity server URL does not appear to be a valid identity server", "General failure": "General failure", + "This homeserver does not support login using email address.": "This homeserver does not support login using email address.", "Failed to perform homeserver discovery": "Failed to perform homeserver discovery", "This homeserver doesn't offer any login flows which are supported by this client.": "This homeserver doesn't offer any login flows which are supported by this client.", "Syncing…": "Syncing…", diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index 9a51a4e6caf..dd49789d7bc 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -21,6 +21,16 @@ import { _t, _td, Tags, TranslatedString } from "../languageHandler"; import SdkConfig from "../SdkConfig"; import { ValidatedServerConfig } from "./ValidatedServerConfig"; +export const resourceLimitStrings = { + "monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."), + "hs_blocked": _td("This homeserver has been blocked by its administrator."), + "": _td("This homeserver has exceeded one of its resource limits."), +}; + +export const adminContactStrings = { + "": _td("Please contact your service administrator to continue using this service."), +}; + /** * Produce a translated error message for a * M_RESOURCE_LIMIT_EXCEEDED error @@ -65,14 +75,16 @@ export function messageForResourceLimitError( export function messageForSyncError(err: Error): ReactNode { if (err instanceof MatrixError && err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") { - const limitError = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, { - "monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."), - "hs_blocked": _td("This homeserver has been blocked by its administrator."), - "": _td("This homeserver has exceeded one of its resource limits."), - }); - const adminContact = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, { - "": _td("Please contact your service administrator to continue using the service."), - }); + const limitError = messageForResourceLimitError( + err.data.limit_type, + err.data.admin_contact, + resourceLimitStrings, + ); + const adminContact = messageForResourceLimitError( + err.data.limit_type, + err.data.admin_contact, + adminContactStrings, + ); return (
{limitError}
@@ -87,19 +99,18 @@ export function messageForSyncError(err: Error): ReactNode { export function messageForLoginError( err: MatrixError, serverConfig: Pick, - usingEmail = false, ): ReactNode { - if (err.httpStatus === 400 && usingEmail) { - return _t("This homeserver does not support login using email address."); - } else if (err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") { - const errorTop = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, { - "monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."), - "hs_blocked": _td("This homeserver has been blocked by its administrator."), - "": _td("This homeserver has exceeded one of its resource limits."), - }); - const errorDetail = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, { - "": _td("Please contact your service administrator to continue using this service."), - }); + if (err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") { + const errorTop = messageForResourceLimitError( + err.data.limit_type, + err.data.admin_contact, + resourceLimitStrings, + ); + const errorDetail = messageForResourceLimitError( + err.data.limit_type, + err.data.admin_contact, + adminContactStrings, + ); return (
{errorTop}
From 07f8936d1d20c069dbff2ea8c12bb40a4d4b46f0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 27 Apr 2023 07:35:54 +0100 Subject: [PATCH 3/5] Add test coverage --- src/utils/ErrorUtils.tsx | 56 +++---- test/utils/ErrorUtils-test.ts | 143 ++++++++++++++++++ .../__snapshots__/ErrorUtils-test.ts.snap | 77 ++++++++++ 3 files changed, 248 insertions(+), 28 deletions(-) create mode 100644 test/utils/ErrorUtils-test.ts create mode 100644 test/utils/__snapshots__/ErrorUtils-test.ts.snap diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index dd49789d7bc..59151568a4a 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -140,24 +140,17 @@ export function messageForLoginError( } export function messageForConnectionError( - err: MatrixError, + err: Error, serverConfig: Pick, ): ReactNode { - let errCode = err.errcode; - if (!errCode && err.httpStatus) { - errCode = "HTTP " + err.httpStatus; - } - - let errorText: ReactNode = - _t("There was a problem communicating with the homeserver, please try again later.") + - (errCode ? " (" + errCode + ")" : ""); + let errorText = _t("There was a problem communicating with the homeserver, please try again later."); if (err instanceof ConnectionError) { if ( window.location.protocol === "https:" && (serverConfig.hsUrl.startsWith("http:") || !serverConfig.hsUrl.startsWith("http")) ) { - errorText = ( + return ( {_t( "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " + @@ -179,25 +172,32 @@ export function messageForConnectionError( )} ); - } else { - errorText = ( - - {_t( - "Can't connect to homeserver - please check your connectivity, ensure your " + - "homeserver's SSL certificate is trusted, and that a browser extension " + - "is not blocking requests.", - {}, - { - a: (sub) => ( - - {sub} - - ), - }, - )} - - ); } + + return ( + + {_t( + "Can't connect to homeserver - please check your connectivity, ensure your " + + "homeserver's SSL certificate is trusted, and that a browser extension " + + "is not blocking requests.", + {}, + { + a: (sub) => ( + + {sub} + + ), + }, + )} + + ); + } else if (err instanceof MatrixError) { + let errCode = err.errcode; + if (!errCode && err.httpStatus) { + errCode = "HTTP " + err.httpStatus; + } + + errorText += errCode ? " (" + errCode + ")" : ""; } return errorText; diff --git a/test/utils/ErrorUtils-test.ts b/test/utils/ErrorUtils-test.ts new file mode 100644 index 00000000000..b29f1c7ac64 --- /dev/null +++ b/test/utils/ErrorUtils-test.ts @@ -0,0 +1,143 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { ReactElement } from "react"; +import { render } from "@testing-library/react"; +import { MatrixError, ConnectionError } from "matrix-js-sdk/src/http-api"; + +import { + adminContactStrings, + messageForConnectionError, + messageForLoginError, + messageForResourceLimitError, + messageForSyncError, + resourceLimitStrings, +} from "../../src/utils/ErrorUtils"; + +describe("messageForResourceLimitError", () => { + it("should match snapshot for monthly_active_user", () => { + const { asFragment } = render( + messageForResourceLimitError( + "monthly_active_user", + "some@email", + resourceLimitStrings, + adminContactStrings, + ) as ReactElement, + ); + + expect(asFragment()).toMatchSnapshot(); + }); +}); + +describe("messageForSyncError", () => { + it("should match snapshot for M_RESOURCE_LIMIT_EXCEEDED", () => { + const err = new MatrixError({ + errcode: "M_RESOURCE_LIMIT_EXCEEDED", + data: { + limit_type: "monthly_active_user", + admin_contact: "some@email", + }, + }); + const { asFragment } = render(messageForSyncError(err) as ReactElement); + expect(asFragment()).toMatchSnapshot(); + }); +}); + +describe("messageForLoginError", () => { + it("should match snapshot for M_RESOURCE_LIMIT_EXCEEDED", () => { + const err = new MatrixError({ + errcode: "M_RESOURCE_LIMIT_EXCEEDED", + data: { + limit_type: "monthly_active_user", + admin_contact: "some@email", + }, + }); + const { asFragment } = render( + messageForLoginError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should match snapshot for M_USER_DEACTIVATED", () => { + const err = new MatrixError( + { + errcode: "M_USER_DEACTIVATED", + }, + 403, + ); + const { asFragment } = render( + messageForLoginError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should match snapshot for 401", () => { + const err = new MatrixError( + { + errcode: "UNKNOWN", + }, + 401, + ); + const { asFragment } = render( + messageForLoginError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should match snapshot for unknown error", () => { + const err = new MatrixError({}, 400); + const { asFragment } = render( + messageForLoginError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); +}); + +describe("messageForConnectionError", () => { + it("should match snapshot for ConnectionError", () => { + const err = new ConnectionError("Internal Server Error", new MatrixError({}, 500)); + const { asFragment } = render( + messageForConnectionError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should match snapshot for unknown error", () => { + const err = new Error("What even"); + const { asFragment } = render( + messageForConnectionError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/test/utils/__snapshots__/ErrorUtils-test.ts.snap b/test/utils/__snapshots__/ErrorUtils-test.ts.snap new file mode 100644 index 00000000000..f1a5d791bb8 --- /dev/null +++ b/test/utils/__snapshots__/ErrorUtils-test.ts.snap @@ -0,0 +1,77 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`messageForConnectionError should match snapshot for ConnectionError 1`] = ` + + + + Can't connect to homeserver - please check your connectivity, ensure your + + homeserver's SSL certificate + + is trusted, and that a browser extension is not blocking requests. + + + +`; + +exports[`messageForConnectionError should match snapshot for unknown error 1`] = ` + + There was a problem communicating with the homeserver, please try again later. + +`; + +exports[`messageForLoginError should match snapshot for 401 1`] = ` + + Incorrect username and/or password. + +`; + +exports[`messageForLoginError should match snapshot for M_RESOURCE_LIMIT_EXCEEDED 1`] = ` + +
+
+ This homeserver has exceeded one of its resource limits. +
+ +
+
+`; + +exports[`messageForLoginError should match snapshot for M_USER_DEACTIVATED 1`] = ` + + This account has been deactivated. + +`; + +exports[`messageForLoginError should match snapshot for unknown error 1`] = ` + + There was a problem communicating with the homeserver, please try again later. (HTTP 400) + +`; + +exports[`messageForResourceLimitError should match snapshot for monthly_active_user 1`] = ` + + This homeserver has hit its Monthly Active User limit. + +`; + +exports[`messageForSyncError should match snapshot for M_RESOURCE_LIMIT_EXCEEDED 1`] = ` + +
+
+ This homeserver has exceeded one of its resource limits. +
+
+ Please contact your service administrator to continue using this service. +
+
+
+`; From 6252d1f6bdcda8e2b1cae1c07caa79f1104c2112 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 27 Apr 2023 08:19:30 +0100 Subject: [PATCH 4/5] Increase test coverage --- test/utils/ErrorUtils-test.ts | 35 +++++++++++++--- .../__snapshots__/ErrorUtils-test.ts.snap | 42 +++++++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/test/utils/ErrorUtils-test.ts b/test/utils/ErrorUtils-test.ts index b29f1c7ac64..a5aef9b465e 100644 --- a/test/utils/ErrorUtils-test.ts +++ b/test/utils/ErrorUtils-test.ts @@ -30,12 +30,15 @@ import { describe("messageForResourceLimitError", () => { it("should match snapshot for monthly_active_user", () => { const { asFragment } = render( - messageForResourceLimitError( - "monthly_active_user", - "some@email", - resourceLimitStrings, - adminContactStrings, - ) as ReactElement, + messageForResourceLimitError("monthly_active_user", "some@email", resourceLimitStrings) as ReactElement, + ); + + expect(asFragment()).toMatchSnapshot(); + }); + + it("should match snapshot for admin contact links", () => { + const { asFragment } = render( + messageForResourceLimitError("", "some@email", adminContactStrings) as ReactElement, ); expect(asFragment()).toMatchSnapshot(); @@ -54,6 +57,14 @@ describe("messageForSyncError", () => { const { asFragment } = render(messageForSyncError(err) as ReactElement); expect(asFragment()).toMatchSnapshot(); }); + + it("should match snapshot for other errors", () => { + const err = new MatrixError({ + errcode: "OTHER_ERROR", + }); + const { asFragment } = render(messageForSyncError(err) as ReactElement); + expect(asFragment()).toMatchSnapshot(); + }); }); describe("messageForLoginError", () => { @@ -140,4 +151,16 @@ describe("messageForConnectionError", () => { ); expect(asFragment()).toMatchSnapshot(); }); + + it("should match snapshot for mixed content error", () => { + const err = new ConnectionError("Mixed content maybe?"); + Object.defineProperty(window, "location", { value: { protocol: "https:" } }); + const { asFragment } = render( + messageForConnectionError(err, { + hsUrl: "http://server.com", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); }); diff --git a/test/utils/__snapshots__/ErrorUtils-test.ts.snap b/test/utils/__snapshots__/ErrorUtils-test.ts.snap index f1a5d791bb8..0104064e2b8 100644 --- a/test/utils/__snapshots__/ErrorUtils-test.ts.snap +++ b/test/utils/__snapshots__/ErrorUtils-test.ts.snap @@ -18,6 +18,24 @@ exports[`messageForConnectionError should match snapshot for ConnectionError 1`] `; +exports[`messageForConnectionError should match snapshot for mixed content error 1`] = ` + + + + Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or + + enable unsafe scripts + + . + + + +`; + exports[`messageForConnectionError should match snapshot for unknown error 1`] = ` There was a problem communicating with the homeserver, please try again later. @@ -57,6 +75,22 @@ exports[`messageForLoginError should match snapshot for unknown error 1`] = ` `; +exports[`messageForResourceLimitError should match snapshot for admin contact links 1`] = ` + + + Please + + contact your service administrator + + to continue using this service. + + +`; + exports[`messageForResourceLimitError should match snapshot for monthly_active_user 1`] = ` This homeserver has hit its Monthly Active User limit. @@ -75,3 +109,11 @@ exports[`messageForSyncError should match snapshot for M_RESOURCE_LIMIT_EXCEEDED
`; + +exports[`messageForSyncError should match snapshot for other errors 1`] = ` + +
+ Unable to connect to Homeserver. Retrying… +
+
+`; From b53e95fe2aecbb4b1a3c9f578fdfb1f3da129761 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 27 Apr 2023 08:43:16 +0100 Subject: [PATCH 5/5] Increase test coverage --- src/utils/ErrorUtils.tsx | 9 ++++----- test/utils/ErrorUtils-test.ts | 16 ++++++++++++++++ test/utils/__snapshots__/ErrorUtils-test.ts.snap | 6 ++++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index 59151568a4a..365bd916c5d 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -192,12 +192,11 @@ export function messageForConnectionError( ); } else if (err instanceof MatrixError) { - let errCode = err.errcode; - if (!errCode && err.httpStatus) { - errCode = "HTTP " + err.httpStatus; + if (err.errcode) { + errorText += `(${err.errcode})`; + } else if (err.httpStatus) { + errorText += ` (HTTP ${err.httpStatus})`; } - - errorText += errCode ? " (" + errCode + ")" : ""; } return errorText; diff --git a/test/utils/ErrorUtils-test.ts b/test/utils/ErrorUtils-test.ts index a5aef9b465e..14fa70ef7ee 100644 --- a/test/utils/ErrorUtils-test.ts +++ b/test/utils/ErrorUtils-test.ts @@ -141,6 +141,22 @@ describe("messageForConnectionError", () => { expect(asFragment()).toMatchSnapshot(); }); + it("should match snapshot for MatrixError M_NOT_FOUND", () => { + const err = new MatrixError( + { + errcode: "M_NOT_FOUND", + }, + 404, + ); + const { asFragment } = render( + messageForConnectionError(err, { + hsUrl: "hsUrl", + hsName: "hsName", + }) as ReactElement, + ); + expect(asFragment()).toMatchSnapshot(); + }); + it("should match snapshot for unknown error", () => { const err = new Error("What even"); const { asFragment } = render( diff --git a/test/utils/__snapshots__/ErrorUtils-test.ts.snap b/test/utils/__snapshots__/ErrorUtils-test.ts.snap index 0104064e2b8..bad4e0a1447 100644 --- a/test/utils/__snapshots__/ErrorUtils-test.ts.snap +++ b/test/utils/__snapshots__/ErrorUtils-test.ts.snap @@ -18,6 +18,12 @@ exports[`messageForConnectionError should match snapshot for ConnectionError 1`] `; +exports[`messageForConnectionError should match snapshot for MatrixError M_NOT_FOUND 1`] = ` + + There was a problem communicating with the homeserver, please try again later.(M_NOT_FOUND) + +`; + exports[`messageForConnectionError should match snapshot for mixed content error 1`] = `