From ab4c5a13b425a7c1154e00971cb17617000245d9 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sat, 27 Apr 2024 23:40:18 +0200 Subject: [PATCH 01/12] Fixed appearance --- questionGenerator/src/main/java/Main.java | 8 +++++--- webapp/src/App.js | 5 ++++- webapp/src/custom.css | 9 +++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/questionGenerator/src/main/java/Main.java b/questionGenerator/src/main/java/Main.java index cd0480f..b5ac6cb 100644 --- a/questionGenerator/src/main/java/Main.java +++ b/questionGenerator/src/main/java/Main.java @@ -13,9 +13,9 @@ public class Main { private static QuestionGenerator qg = QuestionGenerator.getInstance(); - private static final long TIME_SKIP = 18000000; //5 hours + // private static final long TIME_SKIP = 18000000; //5 hours // private static final long TIME_SKIP = 43200000; //12 hours - //private static final long TIME_SKIP = 1000; //1 minute + private static final long TIME_SKIP = 10000; //10 minutes private static String[] languages = {"en", "es", "tr"}; @@ -32,10 +32,12 @@ public class Main { public static void main(String[] args) { List questions = generate().stream().map(q -> q.getJSON().toString()).toList(); while(true) { + long timeStart = System.currentTimeMillis(); QuestionRepository.getInstance().populate(questions); questions = generate().stream().map(q -> q.getJSON().toString()).toList(); + long timeFinish = System.currentTimeMillis(); try { - Thread.sleep(TIME_SKIP); + Thread.sleep(TIME_SKIP - (timeFinish - timeStart)); } catch (InterruptedException e) { e.printStackTrace(); } diff --git a/webapp/src/App.js b/webapp/src/App.js index 07b0c74..d7895c6 100644 --- a/webapp/src/App.js +++ b/webapp/src/App.js @@ -32,7 +32,8 @@ function App() {
- + + } /> @@ -49,7 +50,9 @@ function App() { } /> } /> + +
diff --git a/webapp/src/custom.css b/webapp/src/custom.css index 5cc05a4..73c69fa 100644 --- a/webapp/src/custom.css +++ b/webapp/src/custom.css @@ -115,6 +115,15 @@ margin: 0.5em; } + .user-button{ + margin-right: 10px; + box-shadow: 0 0 10px black; + cursor:pointer; + font-size: 20px; + font-weight: 700; + margin: 0.5em; + } + .right-nav{ display: flex; } From a8aeed52265b9aa8b1599f9de6338cbde908cc48 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 00:18:57 +0200 Subject: [PATCH 02/12] New email error test --- .../ForgetPassword/ForgetPassword.test.js | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/webapp/src/components/ForgetPassword/ForgetPassword.test.js b/webapp/src/components/ForgetPassword/ForgetPassword.test.js index b108e9a..0b693b8 100644 --- a/webapp/src/components/ForgetPassword/ForgetPassword.test.js +++ b/webapp/src/components/ForgetPassword/ForgetPassword.test.js @@ -19,6 +19,10 @@ i18en.use(initReactI18next).init({ }); global.i18en = i18en; const mockAxios = new MockAdapter(axios); + +const code = 111111 +const token = "mockedToken" + describe('ForgetPassword Component', () => { test('renders Ask Email component', async () => { act( () => { @@ -28,42 +32,41 @@ describe('ForgetPassword Component', () => { expect(screen.getByText(/addUser.email_placeholder/)).toBeInTheDocument(); expect(screen.getByText(/addUser.username_placeholder/)).toBeInTheDocument(); }); - test('renders AskForCode component', async () => { - var code = 111111 - var token = "mockedToken" - act( () => { - render(); + + test('show email errors', async () => { + await act( () => { + render(); }); await waitFor(() => expect(screen.getByText(i18en.t("forgotPassword.enter_email"))).toBeInTheDocument()); - const emailInput = screen.getByPlaceholderText(/addUser.email_placeholder/i); - const usernameInput = screen.getByPlaceholderText(/addUser.username_placeholder/i); - //introducimos email y username - expect(screen.getByText(/addUser.email_placeholder/)).toBeInTheDocument(); - userEvent.type(emailInput, 'test@example.com'); - userEvent.type(usernameInput, 'testuser'); + + await act(async () => { await insertEmail('testexample.com', 'testuser') }) - // Hacer clic en el botón de enviar - const submitButton = screen.getByText(/forgotPassword.enter_email_button/i); // Ajusta el texto según el texto real del botón - userEvent.click(submitButton); + await waitFor(() => { + expect(screen.getByText('addUser.error_wrong_email_format')).toBeInTheDocument(); + }) + }) + + + test('change password', async () => { + act( () => { + render(); + }); mockAxios.onPost('http://localhost:8000/forgetPassword').reply(200, "Email sent"); + await waitFor(() => expect(screen.getByText(i18en.t("forgotPassword.enter_email"))).toBeInTheDocument()); + insertEmail('test@example.com', 'testuser') + + act(async ()=>{ await waitFor(async () => expect(screen.getByText(i18en.t("forgotPassword.enter_code")).toBeInTheDocument())); - const inputs = screen.getAllByPlaceholderText('X'); - // Introducir el mismo carácter en todos los inputs - userEvent.type(inputs[0], '1'); // Introducir el carácter '1', puedes cambiarlo al que desees - userEvent.type(inputs[1], '1'); - userEvent.type(inputs[2], '1'); - userEvent.type(inputs[3], '1'); - userEvent.type(inputs[4], '1'); - userEvent.type(inputs[5], '1'); - // Simula un clic en el botón de submit - fireEvent.click(screen.getByText(/"forgotPassword.send_code"/)); mockAxios.onGet('http://localhost:8000/tokenFromCode/' + code).reply(200, {token: token}); + insertCode(['1', '1', '1', '1' ,'1' ,'1' ,'1']) + //llegamos al replace await waitFor(async () => expect(screen.getByText(i18en.t("forgotPassword.enter_password")).toBeInTheDocument())); mockAxios.onPost('http://localhost:8000/changePassword').reply(200, { token: token, username: username}); + await insertPassword('123456789', '123456789') //me redirigen a game Menu await waitFor(async () => expect(screen.getByText(i18en.t('gameMenu.title')).toBeInTheDocument())); //la cookie queda bien seteada @@ -73,3 +76,38 @@ describe('ForgetPassword Component', () => { }); + +async function insertEmail(email, username) { + const emailInput = screen.getByPlaceholderText(/addUser.email_placeholder/i); + const usernameInput = screen.getByPlaceholderText(/addUser.username_placeholder/i); + //introducimos email y username + expect(screen.getByText(/addUser.email_placeholder/)).toBeInTheDocument(); + userEvent.type(emailInput, email); + userEvent.type(usernameInput, username); + const submitButton = screen.getByText(/forgotPassword.enter_email_button/i); // Ajusta el texto según el texto real del botón + userEvent.click(submitButton); +} + +async function insertCode(code){ + const inputs = screen.getAllByPlaceholderText('X'); + // Introducir el mismo carácter en todos los inputs + userEvent.type(inputs[0], code[0]); + userEvent.type(inputs[1], code[1]); + userEvent.type(inputs[2], code[2]); + userEvent.type(inputs[3], code[3]); + userEvent.type(inputs[4], code[4]); + userEvent.type(inputs[5], code[5]); + // Simula un clic en el botón de submit + fireEvent.click(screen.getByText(/"forgotPassword.send_code"/)); +} + +async function insertPassword(password, repeatPassword) { + const passwordInput = screen.getByPlaceholderText(/addUser.password_placeholder/i); + const passwordRepeatInput = screen.getByPlaceholderText(/addUser.repeat_password_placeholder/i); + + expect(screen.getByText(/addUser.email_placeholder/)).toBeInTheDocument(); + userEvent.type(passwordInput, password); + userEvent.type(passwordRepeatInput, repeatPassword); + const submitButton = screen.getByText(/forgotPassword.enter_password_button/i); // Ajusta el texto según el texto real del botón + userEvent.click(submitButton); +} \ No newline at end of file From c77a5cc11aea4bd7068fb341ec42a747657b7d63 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 00:45:18 +0200 Subject: [PATCH 03/12] More gateway service tests --- gatewayservice/gateway-service.test.js | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/gatewayservice/gateway-service.test.js b/gatewayservice/gateway-service.test.js index 0517d12..1592da0 100644 --- a/gatewayservice/gateway-service.test.js +++ b/gatewayservice/gateway-service.test.js @@ -235,4 +235,46 @@ describe('Gateway Service without mocked micro services', () => { expect(error.response.data.error).toBe('Internal server error'); } }); + + it('should not forward login request and give 400', async () => { + axios.post.mockImplementation((url, data) => { + if (url.endsWith('/login')) { + return Promise.reject({ + response: { + status: 400, + data: { message: 'Invalid username or password' }, + }, + }); + } + }); + + try{ + await request(app) + .post('/login') + .send({ username: 'testuser', password: 'testpassword' }); + + } catch(error){ + expect(error.response.status).toBe(400); + expect(error.response.data.error).toBe('Invalid username or password'); + } + }); + + it('should not forward any url and give 500', async () => { + const urls = ['/adduser', '/forgetPassword', '/changePassword', '/questions', + '/questions/es/1/CAPITAL', '/questions/es/1', '/questions/es', + '/record', '/record/ranking/top10', '/record/ranking/user', + '/record/user'] + urls.forEach(async (url) => { + try{ + await request(app) + .post(url) + .send({ username: 'testuser', password: 'testpassword' }); + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }) + + }) }); From c799b3d062ba0e639bfb70baa02bd7d039408fea Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 00:57:50 +0200 Subject: [PATCH 04/12] Removed wrong test --- gatewayservice/gateway-service.test.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/gatewayservice/gateway-service.test.js b/gatewayservice/gateway-service.test.js index 1592da0..ed156e8 100644 --- a/gatewayservice/gateway-service.test.js +++ b/gatewayservice/gateway-service.test.js @@ -258,23 +258,4 @@ describe('Gateway Service without mocked micro services', () => { expect(error.response.data.error).toBe('Invalid username or password'); } }); - - it('should not forward any url and give 500', async () => { - const urls = ['/adduser', '/forgetPassword', '/changePassword', '/questions', - '/questions/es/1/CAPITAL', '/questions/es/1', '/questions/es', - '/record', '/record/ranking/top10', '/record/ranking/user', - '/record/user'] - urls.forEach(async (url) => { - try{ - await request(app) - .post(url) - .send({ username: 'testuser', password: 'testpassword' }); - - } catch(error){ - expect(error.response.status).toBe(500); - expect(error.response.data.error).toBe('Internal server error'); - } - }) - - }) }); From 1c14d9e0a0c8e756e354df7603dacccddb8db961 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 01:03:11 +0200 Subject: [PATCH 05/12] More gateway service tests --- gatewayservice/gateway-service.test.js | 131 +++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/gatewayservice/gateway-service.test.js b/gatewayservice/gateway-service.test.js index ed156e8..a98da05 100644 --- a/gatewayservice/gateway-service.test.js +++ b/gatewayservice/gateway-service.test.js @@ -258,4 +258,135 @@ describe('Gateway Service without mocked micro services', () => { expect(error.response.data.error).toBe('Invalid username or password'); } }); + + it('should not forward adduser request and give 500', async () => { + try{ + await request(app) + .post('/adduser') + .send({ username: 'testuser', password: 'testpassword' }); + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward forgetPassword request and give 500', async () => { + try{ + await request(app) + .post('/forgetPassword'); + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward changePassword request and give 500', async () => { + try{ + await request(app) + .post('/changePassword') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward questions request and give 500', async () => { + try{ + await request(app) + .get('/questions') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward questions request and give 500', async () => { + try{ + await request(app) + .get('/questions/es/1/CAPITAL') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward questions request and give 500', async () => { + try{ + await request(app) + .get('/questions/es/1') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward questions request and give 500', async () => { + try{ + await request(app) + .get('/questions/es') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward record request and give 500', async () => { + try{ + await request(app) + .post('/record') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward record request and give 500', async () => { + try{ + await request(app) + .get('/record/ranking/top10') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward record request and give 500', async () => { + try{ + await request(app) + .get('/record/ranking/user') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); + + it('should not forward record request and give 500', async () => { + try{ + await request(app) + .get('/record/user') + .set('token', 'valorDelToken');; + + } catch(error){ + expect(error.response.status).toBe(500); + expect(error.response.data.error).toBe('Internal server error'); + } + }); }); From eb6f18231d7429d488771166f8c2770349ff4e70 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 01:08:47 +0200 Subject: [PATCH 06/12] Extracted the components of the forgetPassword --- .../ForgetPassword/AskEmailUsername.js | 34 +++++ .../components/ForgetPassword/EnterCode.js | 20 +++ .../ForgetPassword/ForgetPassword.js | 138 +----------------- .../ForgetPassword/PendingComponent.js | 10 ++ .../ForgetPassword/RestorePassword.js | 70 +++++++++ 5 files changed, 138 insertions(+), 134 deletions(-) create mode 100644 webapp/src/components/ForgetPassword/AskEmailUsername.js create mode 100644 webapp/src/components/ForgetPassword/EnterCode.js create mode 100644 webapp/src/components/ForgetPassword/PendingComponent.js create mode 100644 webapp/src/components/ForgetPassword/RestorePassword.js diff --git a/webapp/src/components/ForgetPassword/AskEmailUsername.js b/webapp/src/components/ForgetPassword/AskEmailUsername.js new file mode 100644 index 0000000..340a464 --- /dev/null +++ b/webapp/src/components/ForgetPassword/AskEmailUsername.js @@ -0,0 +1,34 @@ +import "../../custom.css"; + +export default function AskEmailUsername({ email, setEmail, username, setUsername, t, handleSubmit, showErrors }) { + return ( +
+

{t("forgotPassword.enter_email")}

+ {showErrors()} +
+

{t("addUser.email_placeholder")}:

+ setEmail(e.target.value)} + /> +
+
+

{t("addUser.username_placeholder")}:

+ setUsername(e.target.value)} + /> +
+ +
+
+ ); + } \ No newline at end of file diff --git a/webapp/src/components/ForgetPassword/EnterCode.js b/webapp/src/components/ForgetPassword/EnterCode.js new file mode 100644 index 0000000..40ee9c5 --- /dev/null +++ b/webapp/src/components/ForgetPassword/EnterCode.js @@ -0,0 +1,20 @@ +export default function EnterCode({ t, obtainCode, showErrors }) { + return ( +
+
+

{t("forgotPassword.enter_code")}

+ {showErrors()} +
+ + + + + + +
+ +
+
+
+ ); + } \ No newline at end of file diff --git a/webapp/src/components/ForgetPassword/ForgetPassword.js b/webapp/src/components/ForgetPassword/ForgetPassword.js index c00bc34..12b073b 100644 --- a/webapp/src/components/ForgetPassword/ForgetPassword.js +++ b/webapp/src/components/ForgetPassword/ForgetPassword.js @@ -7,6 +7,10 @@ import zxcvbn from "zxcvbn"; import { useNavigate } from "react-router-dom"; import { validateEmail, validatePasswords, validateUsername } from "../../utils/utils"; +import AskEmailUsername from "./AskEmailUsername"; +import PendingComponent from "./PendingComponent"; +import EnterCode from "./EnterCode"; +import RestorePassword from "./RestorePassword"; const forgetPasswordFunctions = new ForgetPasswordFunctions(); export default function ForgotPassword() { @@ -219,137 +223,3 @@ export default function ForgotPassword() { ); } - -// Sub-components used in the main component -function AskEmailUsername({ email, setEmail, username, setUsername, t, handleSubmit, showErrors }) { - return ( -
-

{t("forgotPassword.enter_email")}

- {showErrors()} -
-

{t("addUser.email_placeholder")}:

- setEmail(e.target.value)} - /> -
-
-

{t("addUser.username_placeholder")}:

- setUsername(e.target.value)} - /> -
- -
-
- ); -} - -function PendingComponent({ t }) { - return ( -
-

{t("forgotPassword.sending_title")}

-

{t("forgotPassword.sending_paragraph")}

-
- ); -} - -function EnterCode({ t, obtainCode, showErrors }) { - return ( -
-
-

{t("forgotPassword.enter_code")}

- {showErrors()} -
- - - - - - -
- -
-
-
- ); -} - -function RestorePassword({ - email, - username, - passwordStrength, - passwordStrengthText, - newPassword, - handlePasswordChange, - repeatPassword, - setRepeatPassword, - handleSubmit, - t, - showErrors -}) { - return ( -
-

{t("forgotPassword.enter_password")}

- {showErrors()} -
-

{t("addUser.email_placeholder")}:

- -
-
-

{t("addUser.username_placeholder")}:

- -
-
-

{t("addUser.password_placeholder")}:

- -
-
- {t(passwordStrengthText)} - -
-
-

{t("addUser.repeat_password_placeholder")}:

- setRepeatPassword(e.target.value)} - /> -
- -
-
- ); -} diff --git a/webapp/src/components/ForgetPassword/PendingComponent.js b/webapp/src/components/ForgetPassword/PendingComponent.js new file mode 100644 index 0000000..46e0cad --- /dev/null +++ b/webapp/src/components/ForgetPassword/PendingComponent.js @@ -0,0 +1,10 @@ + +export default function PendingComponent({ t }) { + return ( +
+

{t("forgotPassword.sending_title")}

+

{t("forgotPassword.sending_paragraph")}

+
+ ); +} + \ No newline at end of file diff --git a/webapp/src/components/ForgetPassword/RestorePassword.js b/webapp/src/components/ForgetPassword/RestorePassword.js new file mode 100644 index 0000000..1ac505e --- /dev/null +++ b/webapp/src/components/ForgetPassword/RestorePassword.js @@ -0,0 +1,70 @@ +export default function RestorePassword({ + email, + username, + passwordStrength, + passwordStrengthText, + newPassword, + handlePasswordChange, + repeatPassword, + setRepeatPassword, + handleSubmit, + t, + showErrors + }) { + return ( +
+

{t("forgotPassword.enter_password")}

+ {showErrors()} +
+

{t("addUser.email_placeholder")}:

+ +
+
+

{t("addUser.username_placeholder")}:

+ +
+
+

{t("addUser.password_placeholder")}:

+ +
+
+ {t(passwordStrengthText)} + +
+
+

{t("addUser.repeat_password_placeholder")}:

+ setRepeatPassword(e.target.value)} + /> +
+ +
+
+ ); + } + \ No newline at end of file From 5bc0d6062de57bb686ae99673aa16cdace804642 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 01:23:13 +0200 Subject: [PATCH 07/12] Added tests for two components --- .../ForgetPassword/AskEmailUsername.test.js | 70 +++++++++++++++++++ .../ForgetPassword/PendingComponent.test.js | 28 ++++++++ 2 files changed, 98 insertions(+) create mode 100644 webapp/src/components/ForgetPassword/AskEmailUsername.test.js create mode 100644 webapp/src/components/ForgetPassword/PendingComponent.test.js diff --git a/webapp/src/components/ForgetPassword/AskEmailUsername.test.js b/webapp/src/components/ForgetPassword/AskEmailUsername.test.js new file mode 100644 index 0000000..a7cec1e --- /dev/null +++ b/webapp/src/components/ForgetPassword/AskEmailUsername.test.js @@ -0,0 +1,70 @@ +import { render, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom'; // Ensures custom assertions work +import AskEmailUsername from './AskEmailUsername'; // Path to the component to be tested + +// Mock for useTranslation +jest.mock('react-i18next', () => ({ + useTranslation: jest.fn().mockReturnValue({ + t: (key) => key, // Simulate translation by returning the key + }), +})); + +// Test for the component +describe('AskEmailUsername Component', () => { + it('should render the form with email and username inputs', () => { + const mockHandleSubmit = jest.fn(); + const mockShowErrors = jest.fn().mockReturnValue(null); // Simulate no errors + + const { getByText, getByPlaceholderText } = render( + key} // Mock for translation + handleSubmit={mockHandleSubmit} + showErrors={mockShowErrors} + /> + ); + + // Verify that the title and inputs are rendered + expect(getByText('forgotPassword.enter_email')).toBeInTheDocument(); + expect(getByPlaceholderText('addUser.email_placeholder')).toBeInTheDocument(); + expect(getByPlaceholderText('addUser.username_placeholder')).toBeInTheDocument(); + + // Simulate the submit event + const form = getByText('forgotPassword.enter_email_button').closest('form'); + fireEvent.submit(form); + + // Verify that handleSubmit is called + expect(mockHandleSubmit).toHaveBeenCalled(); + }); + + it('should call setEmail and setUsername on input change', () => { + const mockSetEmail = jest.fn(); + const mockSetUsername = jest.fn(); + + const { getByPlaceholderText } = render( + key} + handleSubmit={jest.fn()} // No need to verify handleSubmit here + showErrors={jest.fn()} + /> + ); + + // Simulate input change for email and username + const emailInput = getByPlaceholderText('addUser.email_placeholder'); + const usernameInput = getByPlaceholderText('addUser.username_placeholder'); + + fireEvent.change(emailInput, { target: { value: 'test@example.com' } }); + fireEvent.change(usernameInput, { target: { value: 'testuser' } }); + + // Verify that setEmail and setUsername were called with correct values + expect(mockSetEmail).toHaveBeenCalledWith('test@example.com'); + expect(mockSetUsername).toHaveBeenCalledWith('testuser'); + }); +}); diff --git a/webapp/src/components/ForgetPassword/PendingComponent.test.js b/webapp/src/components/ForgetPassword/PendingComponent.test.js new file mode 100644 index 0000000..1dd7497 --- /dev/null +++ b/webapp/src/components/ForgetPassword/PendingComponent.test.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; +import { act } from 'react-dom/test-utils'; +import { initReactI18next } from 'react-i18next'; +import i18en from 'i18next'; +import PendingComponent from './PendingComponent'; + + +i18en.use(initReactI18next).init({ + resources: {}, + lng: 'en', + interpolation:{ + escapeValue: false, + } +}); +global.i18en = i18en; + + +describe('Pending Component', () => { + test('renders Ask Email component', async () => { + act( () => { + render(); + }); + await waitFor(() => expect(screen.getByText(/forgotPassword.sending_title/)).toBeInTheDocument()); + expect(screen.getByText(/forgotPassword.sending_paragraph/)).toBeInTheDocument(); + }); +}); From 81ea4bf6fe3732dfdff3a33d0fb2b32f099ae5a6 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 01:36:08 +0200 Subject: [PATCH 08/12] Reducing code duplication --- .../ForgetPassword/AskEmailUsername.js | 26 ++------------- .../loginAndRegistration/AddUser.js | 26 ++------------- .../InputEmailAndUsername.js | 32 +++++++++++++++++++ 3 files changed, 36 insertions(+), 48 deletions(-) create mode 100644 webapp/src/components/loginAndRegistration/InputEmailAndUsername.js diff --git a/webapp/src/components/ForgetPassword/AskEmailUsername.js b/webapp/src/components/ForgetPassword/AskEmailUsername.js index 340a464..c936cde 100644 --- a/webapp/src/components/ForgetPassword/AskEmailUsername.js +++ b/webapp/src/components/ForgetPassword/AskEmailUsername.js @@ -1,32 +1,10 @@ import "../../custom.css"; +import InputEmailAndUsername from "../loginAndRegistration/InputEmailAndUsername" export default function AskEmailUsername({ email, setEmail, username, setUsername, t, handleSubmit, showErrors }) { return (
-

{t("forgotPassword.enter_email")}

- {showErrors()} -
-

{t("addUser.email_placeholder")}:

- setEmail(e.target.value)} - /> -
-
-

{t("addUser.username_placeholder")}:

- setUsername(e.target.value)} - /> -
+ < InputEmailAndUsername title={"forgotPassword.enter_email"} email={email} setEmail={setEmail} username={username} setUsername={setUsername} showErrors={showErrors} t={t}/>
diff --git a/webapp/src/components/loginAndRegistration/AddUser.js b/webapp/src/components/loginAndRegistration/AddUser.js index cabc827..08a1c42 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.js +++ b/webapp/src/components/loginAndRegistration/AddUser.js @@ -7,6 +7,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import zxcvbn from "zxcvbn"; import Cookies from 'js-cookie'; +import InputEmailAndUsername from './InputEmailAndUsername' import { manageError, validateEmail, validateUsername, validatePasswords } from "../../utils/utils"; @@ -95,30 +96,7 @@ const AddUser = () => {
-

{t("addUser.title")}

- {showErrors()} -
-

{t("addUser.email_placeholder")}:

- setEmail(e.target.value)} - /> -
-
-

{t("addUser.username_placeholder")}:

- setUsername(e.target.value)} - /> -
+ < InputEmailAndUsername title={"addUser.title"} email={email} setEmail={setEmail} username={username} setUsername={setUsername} showErrors={showErrors} t={t}/>

{t("addUser.password_placeholder")}:

+

{t(title)}

+ {showErrors()} +
+

{t("addUser.email_placeholder")}:

+ setEmail(e.target.value)} + /> +
+
+

{t("addUser.username_placeholder")}:

+ setUsername(e.target.value)} + /> +
+ + ); + } \ No newline at end of file From e2d3a53a8ca7b9fa3c09ca2b73525f2312735c7c Mon Sep 17 00:00:00 2001 From: uo289267 Date: Sun, 28 Apr 2024 01:45:17 +0200 Subject: [PATCH 09/12] Added EnterCode test --- webapp/package-lock.json | 123 ++---------------- webapp/package.json | 2 +- .../ForgetPassword/EnterCode.test.js | 42 ++++++ 3 files changed, 56 insertions(+), 111 deletions(-) create mode 100644 webapp/src/components/ForgetPassword/EnterCode.test.js diff --git a/webapp/package-lock.json b/webapp/package-lock.json index e71a4dd..1284ec2 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -12,7 +12,6 @@ "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.3", "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^14.1.2", "@testing-library/user-event": "^14.5.2", "axios": "^1.6.5", "bcrypt": "^5.1.1", @@ -34,6 +33,7 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@testing-library/react": "^15.0.5", "axios-mock-adapter": "^1.22.0", "expect-puppeteer": "^9.0.2", "jest": "^29.3.1", @@ -5451,21 +5451,21 @@ } }, "node_modules/@testing-library/dom": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", - "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz", + "integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==", "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", + "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/@testing-library/dom/node_modules/ansi-styles": { @@ -5482,14 +5482,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, "node_modules/@testing-library/dom/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5623,16 +5615,17 @@ } }, "node_modules/@testing-library/react": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.1.2.tgz", - "integrity": "sha512-z4p7DVBTPjKM5qDZ0t5ZjzkpSNb+fZy1u6bzO7kk8oeGagpPCAtgh4cx1syrfp7a+QWkM021jGqjJaxJJnXAZg==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.5.tgz", + "integrity": "sha512-ttodVWYA2i2w4hRa6krKrmS1vKxAEkwDz34y+CwbcrbZUxFzUYN3a5xZyFKo+K6LBseCRCUkwcjATpaNn/UsIA==", + "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^9.0.0", + "@testing-library/dom": "^10.0.0", "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "react": "^18.0.0", @@ -5982,6 +5975,7 @@ "version": "18.2.18", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dev": true, "dependencies": { "@types/react": "*" } @@ -9300,37 +9294,6 @@ } } }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -9865,25 +9828,6 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-iterator-helpers": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", @@ -12729,21 +12673,6 @@ "node": ">= 0.10" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -20066,21 +19995,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -25918,17 +25832,6 @@ "node": ">= 0.8" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", diff --git a/webapp/package.json b/webapp/package.json index c258e1f..3e23cdd 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -7,7 +7,6 @@ "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.3", "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^14.1.2", "@testing-library/user-event": "^14.5.2", "axios": "^1.6.5", "bcrypt": "^5.1.1", @@ -55,6 +54,7 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@testing-library/react": "^15.0.5", "axios-mock-adapter": "^1.22.0", "expect-puppeteer": "^9.0.2", "jest": "^29.3.1", diff --git a/webapp/src/components/ForgetPassword/EnterCode.test.js b/webapp/src/components/ForgetPassword/EnterCode.test.js new file mode 100644 index 0000000..f071300 --- /dev/null +++ b/webapp/src/components/ForgetPassword/EnterCode.test.js @@ -0,0 +1,42 @@ +import React from 'react'; +import { render , screen, waitFor, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // Importa para extender expect +import { act } from 'react-dom/test-utils'; +import EnterCode from './EnterCode'; +import i18en from 'i18next'; +import { initReactI18next } from 'react-i18next'; +i18en.use(initReactI18next).init({ + resources: {}, + lng: 'en', + interpolation:{ + escapeValue: false, + } +}); +global.i18en = i18en; +describe('EnterCode component', () => { + it('renders six input fields correctly',async () => { + const obtainCodeMock = jest.fn(); + const showErrors = jest.fn(); + act(()=>{ + render(); + }); + + await waitFor(async () => await expect(screen.getByText(i18en.t("forgotPassword.enter_code")).toBeInTheDocument())); + expect(screen.getByText('X').toBeInTheDocument()); + // Expect to find six elements with the class 'input' + //expect(inputFields.length).toBe(6); + }); + /* + it('calls obtainCode function when form is submitted', () => { + + const obtainCodeMock = jest.fn(); + const showErrors = jest.fn(); + const { getByText } = render(); + + fireEvent.submit(getByText('Submit')); + + expect(obtainCodeMock).toHaveBeenCalledTimes(1); + }); +*/ + // Add more tests as needed +}); From 67c3948bb6010ff16f6d49f8d7ceb949ac88e850 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 01:51:22 +0200 Subject: [PATCH 10/12] Entercode tests --- .../ForgetPassword/EnterCode.test.js | 77 +++++++++++-------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/webapp/src/components/ForgetPassword/EnterCode.test.js b/webapp/src/components/ForgetPassword/EnterCode.test.js index f071300..1e425c5 100644 --- a/webapp/src/components/ForgetPassword/EnterCode.test.js +++ b/webapp/src/components/ForgetPassword/EnterCode.test.js @@ -1,42 +1,53 @@ import React from 'react'; -import { render , screen, waitFor, fireEvent } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; // Importa para extender expect -import { act } from 'react-dom/test-utils'; -import EnterCode from './EnterCode'; -import i18en from 'i18next'; -import { initReactI18next } from 'react-i18next'; -i18en.use(initReactI18next).init({ - resources: {}, - lng: 'en', - interpolation:{ - escapeValue: false, - } -}); -global.i18en = i18en; -describe('EnterCode component', () => { - it('renders six input fields correctly',async () => { +import { render, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // Permite usar aserciones extendidas +import EnterCode from './EnterCode'; // Ruta al componente + +// Mock de `useTranslation` +jest.mock('react-i18next', () => ({ + useTranslation: jest.fn().mockReturnValue({ + t: (key) => key, // Simula la traducción devolviendo la clave + }), +})); + +describe('EnterCode Component', () => { + it('should render correctly with six input fields', () => { const obtainCodeMock = jest.fn(); - const showErrors = jest.fn(); - act(()=>{ - render(); - }); + const showErrorsMock = jest.fn(); // Mock de función para mostrar errores + + const { getAllByPlaceholderText, getByText } = render( + key} + obtainCode={obtainCodeMock} + showErrors={showErrorsMock} + /> + ); + + // Verificar que se rendericen seis campos de entrada + const inputFields = getAllByPlaceholderText('X'); + expect(inputFields.length).toBe(6); // Espera seis campos de entrada - await waitFor(async () => await expect(screen.getByText(i18en.t("forgotPassword.enter_code")).toBeInTheDocument())); - expect(screen.getByText('X').toBeInTheDocument()); - // Expect to find six elements with the class 'input' - //expect(inputFields.length).toBe(6); + // Verificar que el título y el botón de envío están presentes + expect(getByText('forgotPassword.enter_code')).toBeInTheDocument(); + expect(getByText('forgotPassword.send_code')).toBeInTheDocument(); }); - /* - it('calls obtainCode function when form is submitted', () => { - + + it('should call obtainCode when the form is submitted', () => { const obtainCodeMock = jest.fn(); - const showErrors = jest.fn(); - const { getByText } = render(); + const showErrorsMock = jest.fn(); + const { getByText } = render( + key} + obtainCode={obtainCodeMock} + showErrors={showErrorsMock} + /> + ); - fireEvent.submit(getByText('Submit')); + // Simular el evento de envío del formulario + const form = getByText('forgotPassword.send_code').closest('form'); + fireEvent.submit(form); - expect(obtainCodeMock).toHaveBeenCalledTimes(1); + // Verificar que `obtainCode` fue llamado al enviar el formulario + expect(obtainCodeMock).toHaveBeenCalled(); }); -*/ - // Add more tests as needed }); From 323060e5ea14671a3cb60daa804c3c762dad7c12 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 02:09:44 +0200 Subject: [PATCH 11/12] RestorePassword tests added --- .../ForgetPassword/RestorePassword.test.js | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 webapp/src/components/ForgetPassword/RestorePassword.test.js diff --git a/webapp/src/components/ForgetPassword/RestorePassword.test.js b/webapp/src/components/ForgetPassword/RestorePassword.test.js new file mode 100644 index 0000000..292d03d --- /dev/null +++ b/webapp/src/components/ForgetPassword/RestorePassword.test.js @@ -0,0 +1,99 @@ +import { screen, render, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom'; // Ensures custom assertions are available +import RestorePassword from './RestorePassword'; // Path to the component to test + +// Mock for useTranslation +jest.mock('react-i18next', () => ({ + useTranslation: jest.fn().mockReturnValue({ + t: (key) => key, // Simulate translation by returning the key + }), +})); + +describe('RestorePassword Component', () => { + it('should render the form with all expected fields', () => { + const mockHandleSubmit = jest.fn(); // Mock for form submission + const mockHandlePasswordChange = jest.fn(); + const mockShowErrors = jest.fn().mockReturnValue(null); // Simulate no errors + + const { getByText } = render( + key} // Mock for translation + showErrors={mockShowErrors} + /> + ); + + // Verify key elements are rendered + expect(getByText('forgotPassword.enter_password')).toBeInTheDocument(); + expect(getByText(/addUser.password_placeholder/i)).toBeInTheDocument(); + expect(getByText(/addUser.repeat_password_placeholder/i)).toBeInTheDocument(); + + // Check if the email and username are read-only and have correct values + const inputs = screen.getAllByRole('textbox'); + expect(inputs[0].value).toBe('test@example.com'); + expect(inputs[1].value).toBe('testuser'); + }); + + it('should call handlePasswordChange on password input change', () => { + const mockHandlePasswordChange = jest.fn(); + + const { container } = render( + key} + showErrors={jest.fn()} + /> + ); + + // Simulate changing the password input + + const passwordInput = container.querySelector(`input[name="password"]`); + fireEvent.change(passwordInput, { target: { value: 'newPassword' } }); + + // Ensure handlePasswordChange was called with the correct argument + expect(mockHandlePasswordChange).toHaveBeenCalledWith(expect.any(Object)); // Expecting event object + }); + + it('should call handleSubmit on form submission', () => { + const mockHandleSubmit = jest.fn(); + + const { getByText } = render( + key} + showErrors={jest.fn()} + /> + ); + + // Simulate form submission + const form = getByText('forgotPassword.enter_password_button').closest('form'); + fireEvent.submit(form); + + // Verify handleSubmit was called on form submission + expect(mockHandleSubmit).toHaveBeenCalled(); + }); +}); From 7036926c0dbe2437c6ced22cf3b2251d3f2e4b83 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sun, 28 Apr 2024 02:15:24 +0200 Subject: [PATCH 12/12] Small tweak --- webapp/src/components/ForgetPassword/RestorePassword.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webapp/src/components/ForgetPassword/RestorePassword.test.js b/webapp/src/components/ForgetPassword/RestorePassword.test.js index 292d03d..626099f 100644 --- a/webapp/src/components/ForgetPassword/RestorePassword.test.js +++ b/webapp/src/components/ForgetPassword/RestorePassword.test.js @@ -66,6 +66,8 @@ describe('RestorePassword Component', () => { const passwordInput = container.querySelector(`input[name="password"]`); fireEvent.change(passwordInput, { target: { value: 'newPassword' } }); + const rPasswordInput = container.querySelector(`input[name="repeat_password"]`); + fireEvent.change(rPasswordInput, { target: { value: 'newPassword' } }); // Ensure handlePasswordChange was called with the correct argument expect(mockHandlePasswordChange).toHaveBeenCalledWith(expect.any(Object)); // Expecting event object });