Skip to content

Commit

Permalink
Merge pull request #274 from Arquisoft/feat/webapp/changes
Browse files Browse the repository at this point in the history
More descriptive errors for the login and signup
  • Loading branch information
jjgancfer authored Apr 23, 2024
2 parents 6abbd04 + ca2557b commit 783214d
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 29 deletions.
6 changes: 3 additions & 3 deletions webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@
"login-send": "Your email or password are not found in our database",
"validation": {
"type": "Validation Error: ",
"message": "Incorrect data"
"message": "Invalid email format"
},
"conflict": {
"type": "Conflict Error: ",
"message": "User already exists"
"message": "Invalid email format or credentials (username or email) already in use"
},
"unknown": {
"type": "Unknown Error",
"message": ""
},
"authorized": {
"type": "Authorization Error: ",
"message": "Incorrect password"
"message": "Invalid email or password, check for them to be correct"
}
},
"rules": {
Expand Down
6 changes: 3 additions & 3 deletions webapp/public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@
"login-send": "Tu email o contraseña no se encuentran en nuestra base de datos",
"validation": {
"type": "Error de Validación: ",
"message": "Datos incorrectos"
"message": "El formato del correo electrónico no es correcto"
},
"conflict": {
"type": "Error de Conflicto: ",
"message": "El usuario ya existe"
"message": "Formato de correo electrónico no válido o credenciales (nombre de usuario o correo electrónico) ya en uso"
},
"unknown": {
"type": "Error Desconocido",
"message": ""
},
"authorized": {
"type": "Error de Autorización: ",
"message": "Contraseña incorrecta"
"message": "Correo electrónico o contraseña no válidos, verifique que sean correctos"
}
},
"rules": {
Expand Down
17 changes: 3 additions & 14 deletions webapp/src/components/auth/AuthManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default class AuthManager {
static #instance = null;
#isLoggedIn = false;
#axiosInstance = null;


constructor() {
if (!AuthManager.#instance) {
Expand Down Expand Up @@ -46,7 +47,7 @@ export default class AuthManager {
throw requestAnswer;
}
} catch (error) {
onError(error);
onError(error);
}
}

Expand Down Expand Up @@ -100,19 +101,7 @@ export default class AuthManager {
throw requestAnswer;
}
} catch (error) {
let errorType;
switch (error.response ? error.response.status : null) {
case 400:
errorType = { type: "error.validation.type", message: "error.validation.message"};
break;
case 409:
errorType = { type: "error.conflict.type", message: "error.conflict.message"};
break;
default:
errorType = { type: "error.unknown.type", message: "error.unknown.message"};
break;
}
onError(errorType);
onError(error);
}
}
}
19 changes: 17 additions & 2 deletions webapp/src/pages/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,24 @@ export default function Login() {
"password": password
};
try {
await new AuthManager().login(loginData, navigateToDashboard, setErrorMessage);
await new AuthManager().login(loginData, navigateToDashboard, setLocalizedErrorMessage);
} catch {
setErrorMessage("Error desconocido");
const message = { type: t("error.login"), message: t("error.login-desc")};
setErrorMessage(message);
}
}

const setLocalizedErrorMessage = (error) => {
switch (error.response.status) {
case 400:
setErrorMessage({ type: t("error.validation.type"), message: t("error.validation.message")});
break;
case 401:
setErrorMessage({ type: t("error.authorized.type"), message: t("error.authorized.message")});
break;
default:
setErrorMessage({ type: t("error.login"), message: t("error.login-desc")});
break;
}
}

Expand Down
9 changes: 5 additions & 4 deletions webapp/src/pages/Signup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,21 @@ export default function Signup() {
try {
await new AuthManager().register(registerData, navigateToDashboard, setLocalizedErrorMessage);
} catch {
setErrorMessage("Error desconocido");
const message = { type: t("error.register"), message: t("error.register-desc")};
setErrorMessage(message);
}
};

const setLocalizedErrorMessage = (error) => {
switch (error.response ? error.response.status : null) {
switch (error.response.status) {
case 400:
setErrorMessage({ type: t("error.validation.type"), message: t("error.validation.message")});
setErrorMessage({ type: t("error.conflict.type"), message: t("error.conflict.message")});
break;
case 401:
setErrorMessage({ type: t("error.authorized.type"), message: t("error.authorized.message")});
break;
default:
setErrorMessage({ type: t("error.unknown.type"), message: t("error.unknown.message")});
setErrorMessage({ type: t("error.register"), message: t("error.register-desc")});
break;
}
}
Expand Down
47 changes: 45 additions & 2 deletions webapp/src/tests/Login.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { render, fireEvent, waitFor, act } from '@testing-library/react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { MemoryRouter } from 'react-router';
import Login from '../pages/Login';
Expand All @@ -8,7 +8,6 @@ import MockAdapter from 'axios-mock-adapter';
import { HttpStatusCode } from 'axios';
import { ChakraProvider } from '@chakra-ui/react';
import theme from '../styles/theme';
import Signup from 'pages/Signup';

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
Expand Down Expand Up @@ -87,4 +86,48 @@ describe('Login Component', () => {
expect(getByTestId('error-message')).toBeInTheDocument();
});
});

it('renders button "GoBack"', () => {
const { getByTestId } = render(
<ChakraProvider theme={theme}>
<MemoryRouter initialEntries={['/signup']}>
<Login />
</MemoryRouter>
</ChakraProvider>
);
const goBackButton = getByTestId('GoBack');
expect(goBackButton).toBeInTheDocument();
});

it('displays error message on failed format login attempt', async () => {
mockAxios.onPost().replyOnce(HttpStatusCode.BadRequest);
const { getByPlaceholderText, getByTestId } = render(<ChakraProvider theme={theme}><MemoryRouter><Login /></MemoryRouter></ChakraProvider>);
const emailInput = getByPlaceholderText('session.email');
const passwordInput = getByPlaceholderText('session.password');
const loginButton = getByTestId('Login');

fireEvent.change(emailInput, { target: { value: 'test' } });
fireEvent.change(passwordInput, { target: { value: 'test' } });
fireEvent.click(loginButton);

await waitFor(() => {
expect(getByTestId('error-message')).toBeInTheDocument();
});
});

it('displays error message on unauthorized login attempt', async () => {
mockAxios.onPost().replyOnce(HttpStatusCode.Unauthorized);
const { getByPlaceholderText, getByTestId } = render(<ChakraProvider theme={theme}><MemoryRouter><Login /></MemoryRouter></ChakraProvider>);
const emailInput = getByPlaceholderText('session.email');
const passwordInput = getByPlaceholderText('session.password');
const loginButton = getByTestId('Login');

fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'test' } });
fireEvent.click(loginButton);

await waitFor(() => {
expect(getByTestId('error-message')).toBeInTheDocument();
});
});
});
47 changes: 46 additions & 1 deletion webapp/src/tests/Signup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import { MemoryRouter } from 'react-router';
import Signup from '../pages/Signup';
import { ChakraProvider } from '@chakra-ui/react';
import theme from '../styles/theme';
import MockAdapter from 'axios-mock-adapter';
import AuthManager from 'components/auth/AuthManager';
import { HttpStatusCode } from 'axios';
import MockAdapter from 'axios-mock-adapter';

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
}));

jest.mock('react-i18next', () => ({
useTranslation: () => {
Expand All @@ -19,8 +24,17 @@ jest.mock('react-i18next', () => ({
},
}));

const authManager = new AuthManager();
let mockAxios = new MockAdapter(authManager.getAxiosInstance());

describe('Signup Component', () => {

beforeEach(() => {
authManager.reset();
jest.clearAllMocks();
mockAxios = new MockAdapter(authManager.getAxiosInstance());
});

it('renders form elements correctly', () => {
const { getByPlaceholderText } = render(<ChakraProvider theme={theme}><MemoryRouter><Signup /></MemoryRouter></ChakraProvider>);

Expand Down Expand Up @@ -74,4 +88,35 @@ describe('Signup Component', () => {
expect(confirmPasswordInput.value).toBe('newPassword');
});

it('displays error message on failed register attempt', async () => {
mockAxios.onPost().replyOnce(HttpStatusCode.BadRequest);
const { getByPlaceholderText, getByTestId } = render(<ChakraProvider theme={theme}><MemoryRouter><Signup /></MemoryRouter></ChakraProvider>);
const emailInput = getByPlaceholderText('session.email');
const passwordInput = getByPlaceholderText('session.password');
const registerButton = getByTestId('Sign up');

fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'password123' } });
fireEvent.click(registerButton);

await waitFor(() => {
expect(getByTestId('error-message')).toBeInTheDocument();
});
});

it('displays error message on unauthorized register attempt', async () => {
mockAxios.onPost().replyOnce(HttpStatusCode.Unauthorized);
const { getByPlaceholderText, getByTestId } = render(<ChakraProvider theme={theme}><MemoryRouter><Signup /></MemoryRouter></ChakraProvider>);
const emailInput = getByPlaceholderText('session.email');
const passwordInput = getByPlaceholderText('session.password');
const registerButton = getByTestId('Sign up');

fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'test' } });
fireEvent.click(registerButton);

await waitFor(() => {
expect(getByTestId('error-message')).toBeInTheDocument();
});
});
});

0 comments on commit 783214d

Please sign in to comment.