From 4aaa8cf2c0dd00ca1542e6ba8eede1f66859e2a0 Mon Sep 17 00:00:00 2001 From: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:34:17 +0530 Subject: [PATCH] fix: simplified error messages for invalid inputs at profile settings (#2500) --- public/locales/en/errors.json | 7 +++- public/locales/fr/errors.json | 7 +++- public/locales/hi/errors.json | 7 +++- public/locales/sp/errors.json | 7 +++- public/locales/zh/errors.json | 7 +++- src/utils/errorHandler.test.tsx | 74 ++++++++++++++++++++++++++++++--- src/utils/errorHandler.tsx | 24 +++++++---- 7 files changed, 115 insertions(+), 18 deletions(-) diff --git a/public/locales/en/errors.json b/public/locales/en/errors.json index 752c0db750..ffb0e6f146 100644 --- a/public/locales/en/errors.json +++ b/public/locales/en/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "Email not registered", "notFoundMsg": "Oops! The Page you requested was not found!", "errorOccurredCouldntCreate": "An error occurred. Couldn't create {{entity}}", - "errorLoading": "Error occured while loading {{entity}} data" + "errorLoading": "Error occured while loading {{entity}} data", + "invalidPhoneNumber": "Please enter a valid phone number", + "invalidEducationGrade": "Please select a valid education grade", + "invalidEmploymentStatus": "Please select a valid employment status", + "invalidMaritalStatus": "Please select a valid marital status", + "error400": "The submitted information is invalid. Please check your inputs and try again" } diff --git a/public/locales/fr/errors.json b/public/locales/fr/errors.json index e9a7cf4fd9..ae53237404 100644 --- a/public/locales/fr/errors.json +++ b/public/locales/fr/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "Email non enregistré", "notFoundMsg": "Oops! ", "errorOccurredCouldntCreate": "Une erreur s'est produite. Impossible de créer {{entity}}", - "errorLoading": "Une erreur s'est produite lors du chargement des données {{entity}}" + "errorLoading": "Une erreur s'est produite lors du chargement des données {{entity}}", + "invalidPhoneNumber": "Veuillez entrer un numéro de téléphone valide", + "invalidEducationGrade": "Veuillez sélectionner un niveau d'études valide", + "invalidEmploymentStatus": "Veuillez sélectionner un statut d'emploi valide", + "invalidMaritalStatus": "Veuillez sélectionner un état matrimonial valide", + "error400": "Réponse non réussie. Code d'état 400 reçu du serveur" } diff --git a/public/locales/hi/errors.json b/public/locales/hi/errors.json index 63b6c3f5d3..64f9523180 100644 --- a/public/locales/hi/errors.json +++ b/public/locales/hi/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "ईमेल पंजीकृत नहीं है", "notFoundMsg": "उफ़! ", "errorOccurredCouldntCreate": "एक त्रुटि हुई। {{entity}} नहीं बना सके", - "errorLoading": "{{entity}} डेटा लोड करते समय त्रुटि हुई" + "errorLoading": "{{entity}} डेटा लोड करते समय त्रुटि हुई", + "invalidPhoneNumber": "कृपया एक मान्य फोन-नंबर दर्ज करे", + "invalidEducationGrade": "कृपया एक शिक्षा ग्रेड चुनें", + "invalidEmploymentStatus": "कृपया वैध रोजगार स्थिति चुनें", + "invalidMaritalStatus": "कृपया वैध वैवाहिक स्थिति चुनें", + "error400": "आपकी जानकारी सहेजी नहीं जा सकी। कृपया अपनी प्रविष्टियों की जांच करें और पुनः प्रयास करें।" } diff --git a/public/locales/sp/errors.json b/public/locales/sp/errors.json index 39b579abac..7489356b5e 100644 --- a/public/locales/sp/errors.json +++ b/public/locales/sp/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "Email not registered", "notFoundMsg": "Oops! The Page you requested was not found!", "errorOccurredCouldntCreate": "Ocurrió un error. No se pudo crear {{entity}}", - "errorLoading": "Ocurrió un error al cargar los datos de {{entity}}" + "errorLoading": "Ocurrió un error al cargar los datos de {{entity}}", + "invalidPhoneNumber": "Por favor, introduzca un número de teléfono válido", + "invalidEducationGrade": "Por favor seleccione un grado de educación válido", + "invalidEmploymentStatus": "Por favor seleccione un estado de empleo válido", + "invalidMaritalStatus": "Por favor seleccione un estado civil válido", + "error400": "Respuesta no exitosa. Se recibió el código de estado 400 del servidor" } diff --git a/public/locales/zh/errors.json b/public/locales/zh/errors.json index c872f367a5..c289d67aa1 100644 --- a/public/locales/zh/errors.json +++ b/public/locales/zh/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "邮箱未注册", "notFoundMsg": "哎呀!", "errorOccurredCouldntCreate": "发生错误。 无法创建{{entity}}", - "errorLoading": "加载{{entity}}数据时出错" + "errorLoading": "加载{{entity}}数据时出错", + "invalidPhoneNumber": "请选择一个有效的电话号码", + "invalidEducationGrade": "请选择教育年级", + "invalidEmploymentStatus": "请选择有效的就业状况", + "invalidMaritalStatus": "请选择有效的婚姻状况", + "error400": "响应不成功. 从服务器收到状态代码 400" } diff --git a/src/utils/errorHandler.test.tsx b/src/utils/errorHandler.test.tsx index 45f46e6389..f229e8d5fa 100644 --- a/src/utils/errorHandler.test.tsx +++ b/src/utils/errorHandler.test.tsx @@ -11,23 +11,87 @@ jest.mock('react-toastify', () => ({ describe('Test if errorHandler is working properly', () => { const t: TFunction = (key: string) => key; - const tErrors: TFunction = (key: string, options?: Record) => - key; + const tErrors: TFunction = ( + key: string, + options?: Record, + ) => { + if (options) { + console.log(`options are passed, but the function returns only ${key}`); + } + return key; + }; - it('should call toast.error with the correct message if error message is "Failed to fetch"', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should call toast.error with the correct message if error message is "Failed to fetch"', async () => { const error = new Error('Failed to fetch'); errorHandler(t, error); expect(toast.error).toHaveBeenCalledWith(tErrors('talawaApiUnavailable')); }); - it('should call toast.error with the error message if it is not "Failed to fetch"', () => { - const error = new Error('Some other error message'); + it('should call toast.error with the correct message if error message contains this substring "Value is not a valid phone number"', () => { + const error = new Error('This value is not a valid phone number'); errorHandler(t, error); + expect(toast.error).toHaveBeenCalledWith(tErrors('invalidPhoneNumber')); + }); + + test.each([ + ['EducationGrade', 'invalidEducationGrade'], + ['EmploymentStatus', 'invalidEmploymentStatus'], + ['MaritalStatus', 'invalidMaritalStatus'], + ])('should handle invalid %s error', (field, expectedKey) => { + const error = new Error(`This value does not exist in "${field}"`); + errorHandler(t, error); + expect(toast.error).toHaveBeenCalledWith(tErrors(expectedKey)); + }); + + it('should call toast.error with the correct message if error message contains this substring "status code 400"', () => { + const error = new Error('Server responded with status code 400'); + errorHandler(t, error); + + expect(toast.error).toHaveBeenCalledWith(tErrors('error400')); + }); + + it('should handle error messages with different cases', () => { + errorHandler(t, new Error('VALUE IS NOT A VALID PHONE NUMBER')); + expect(toast.error).toHaveBeenCalledWith(tErrors('invalidPhoneNumber')); + + errorHandler(t, new Error('This Value Does Not Exist in "EducationGrade"')); + expect(toast.error).toHaveBeenCalledWith(tErrors('invalidEducationGrade')); + }); + it('should call toast.error with the error message if it is an instance of error but have not matched any error message patterns', () => { + const error = new Error('Bandhan sent an error message'); + errorHandler(t, error); expect(toast.error).toHaveBeenCalledWith(error.message); }); + it('should handle different types for the first parameter while still showing error messages', () => { + errorHandler(undefined, new Error('Some error')); + expect(toast.error).toHaveBeenCalled(); + + errorHandler(null, new Error('Some error')); + expect(toast.error).toHaveBeenCalled(); + + errorHandler({}, new Error('Some error')); + expect(toast.error).toHaveBeenCalled(); + }); + + it('should handle non-null but non-Error objects for the error parameter', () => { + errorHandler(t, { message: 'Error message in object' }); + expect(toast.error).toHaveBeenCalledWith( + tErrors('unknownError', { msg: { message: 'Error message in object' } }), + ); + + errorHandler(t, 'Direct error message'); + expect(toast.error).toHaveBeenCalledWith( + tErrors('unknownError', { msg: 'Direct error message' }), + ); + }); + it('should call toast.error with the error message if error object is falsy', () => { const error = null; errorHandler(t, error); diff --git a/src/utils/errorHandler.tsx b/src/utils/errorHandler.tsx index b7a22210a8..e4e543e940 100644 --- a/src/utils/errorHandler.tsx +++ b/src/utils/errorHandler.tsx @@ -5,18 +5,26 @@ import i18n from './i18n'; /** This function is used to handle api errors in the application. It takes in the error object and displays the error message to the user. - If the error is due to the Talawa API being unavailable, it displays a custom message. + If the error is due to the Talawa API being unavailable, it displays a custom message. And for other error cases, it is using regular expression (case-insensitive) to match and show valid messages */ export const errorHandler = (a: unknown, error: unknown): void => { const tErrors: TFunction = i18n.getFixedT(null, 'errors'); if (error instanceof Error) { - switch (error.message) { - case 'Failed to fetch': - toast.error(tErrors('talawaApiUnavailable') as string); - break; - // Add more cases as needed - default: - toast.error(error.message); + const errorMessage = error.message; + if (errorMessage === 'Failed to fetch') { + toast.error(tErrors('talawaApiUnavailable')); + } else if (errorMessage.match(/value is not a valid phone number/i)) { + toast.error(tErrors('invalidPhoneNumber')); + } else if (errorMessage.match(/does not exist in "EducationGrade"/i)) { + toast.error(tErrors('invalidEducationGrade')); + } else if (errorMessage.match(/does not exist in "EmploymentStatus"/i)) { + toast.error(tErrors('invalidEmploymentStatus')); + } else if (errorMessage.match(/does not exist in "MaritalStatus"/i)) { + toast.error(tErrors('invalidMaritalStatus')); + } else if (errorMessage.match(/status code 400/i)) { + toast.error(tErrors('error400')); + } else { + toast.error(errorMessage); } } else { toast.error(tErrors('unknownError', { msg: error }) as string);