From 8e5e7378ac0c39bead6d40c32584ee729352b870 Mon Sep 17 00:00:00 2001 From: sinne10 Date: Sun, 14 Apr 2024 12:38:23 +0200 Subject: [PATCH 1/8] Added basic password-strength-meter --- webapp/package-lock.json | 8 +++- webapp/package.json | 3 +- .../loginAndRegistration/AddUser.js | 45 ++++++++++++++++++- webapp/src/custom.css | 38 ++++++++++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 076761a2..41859609 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -28,7 +28,8 @@ "react-icons": "^5.0.1", "react-router-dom": "^6.22.3", "react-scripts": "^5.0.1", - "web-vitals": "^3.5.1" + "web-vitals": "^3.5.1", + "zxcvbn": "^4.4.2" }, "devDependencies": { "axios-mock-adapter": "^1.22.0", @@ -28453,6 +28454,11 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zxcvbn": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz", + "integrity": "sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==" } } } diff --git a/webapp/package.json b/webapp/package.json index 2ea16917..55422652 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -23,7 +23,8 @@ "react-icons": "^5.0.1", "react-router-dom": "^6.22.3", "react-scripts": "^5.0.1", - "web-vitals": "^3.5.1" + "web-vitals": "^3.5.1", + "zxcvbn": "^4.4.2" }, "scripts": { "start": "react-scripts start", diff --git a/webapp/src/components/loginAndRegistration/AddUser.js b/webapp/src/components/loginAndRegistration/AddUser.js index 2324ecab..213967ca 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.js +++ b/webapp/src/components/loginAndRegistration/AddUser.js @@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next"; import axios from 'axios'; import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import zxcvbn from "zxcvbn"; const AddUser = () => { @@ -14,6 +15,8 @@ const AddUser = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [repeatPassword, setRepeatPassword] = useState(''); + const [passwordStrength, setPasswordStrength] = useState(undefined); + const [passwordStrengthText, setPasswordStrengthText] = useState('Weak password'); const handleSubmit = async (event) => { @@ -34,6 +37,35 @@ const AddUser = () => { } }; + const handlePasswordChange = (e) => { + const newPassword = e.target.value; + setPassword(newPassword); + + const newStrength = zxcvbn(newPassword); + + switch(newStrength.score){ + case 0: + setPasswordStrengthText('Weak password'); + break; + case 1: + setPasswordStrengthText('Weak password'); + break; + case 2: + setPasswordStrengthText('Fair password'); + break; + case 3: + setPasswordStrengthText('Good password'); + break; + case 4: + setPasswordStrengthText('Strong password'); + break; + default: + setPasswordStrengthText('Weak password'); + break; + } + setPasswordStrength(newStrength); + }; + return (
@@ -51,7 +83,7 @@ const AddUser = () => { onChange={(e) => setUsername(e.target.value)} />
-
+

{t("addUser.password_placeholder")}:

{ placeholder={t("addUser.password_placeholder")} required value={password} - onChange={(e) => setPassword(e.target.value)} + onChange={handlePasswordChange} />
+
+ + {passwordStrengthText} + + +

{t("addUser.repeat_password_placeholder")}:

Date: Sun, 14 Apr 2024 13:54:13 +0200 Subject: [PATCH 2/8] Added password policies --- .../components/loginAndRegistration/AddUser.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/webapp/src/components/loginAndRegistration/AddUser.js b/webapp/src/components/loginAndRegistration/AddUser.js index 213967ca..43e751e1 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.js +++ b/webapp/src/components/loginAndRegistration/AddUser.js @@ -17,20 +17,27 @@ const AddUser = () => { const [repeatPassword, setRepeatPassword] = useState(''); const [passwordStrength, setPasswordStrength] = useState(undefined); const [passwordStrengthText, setPasswordStrengthText] = useState('Weak password'); + const [submitError, setSubmitError] = useState(''); const handleSubmit = async (event) => { event.preventDefault(); try { //TODO: Add more validations - if(password === repeatPassword){ //User put the same password + if(password !== repeatPassword){ //User put the same password + setSubmitError('Passwords do not match'); + } else if(/\s/.test(password)){ //User put spaces in password + setSubmitError('Password cannot contain spaces'); + } else if(password.length < 8){ //Password too short + setSubmitError('Password must be at least 8 characters long'); + } else if(password.length > 64){ //Password too long + setSubmitError('Password cannot be over 64 characters long'); + } else{ //Continue + setSubmitError(''); const response = await axios.post(apiUrl, { username, password }); console.log("Registered user: " + response.data.username); navigate('/login'); } - else{ - //TODO: Show some errors to the user - } } catch (error) { console.error('Error adding user:', error); @@ -114,7 +121,7 @@ const AddUser = () => { onChange={(e) => setRepeatPassword(e.target.value)} />
- + {submitError &&

{submitError}

} From 2e0ff2e46246ae013e95dc409304aa160d757a82 Mon Sep 17 00:00:00 2001 From: sinne10 Date: Mon, 15 Apr 2024 01:01:26 +0200 Subject: [PATCH 3/8] User policies and internationalization --- .../loginAndRegistration/AddUser.js | 57 +++++++++++++------ webapp/src/translations/en/global.json | 11 +++- webapp/src/translations/es/global.json | 11 +++- webapp/src/translations/tk/global.json | 11 +++- 4 files changed, 70 insertions(+), 20 deletions(-) diff --git a/webapp/src/components/loginAndRegistration/AddUser.js b/webapp/src/components/loginAndRegistration/AddUser.js index 43e751e1..5b577edf 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.js +++ b/webapp/src/components/loginAndRegistration/AddUser.js @@ -16,23 +16,32 @@ const AddUser = () => { const [password, setPassword] = useState(''); const [repeatPassword, setRepeatPassword] = useState(''); const [passwordStrength, setPasswordStrength] = useState(undefined); - const [passwordStrengthText, setPasswordStrengthText] = useState('Weak password'); + const [passwordStrengthText, setPasswordStrengthText] = useState(""); const [submitError, setSubmitError] = useState(''); const handleSubmit = async (event) => { event.preventDefault(); try { - //TODO: Add more validations - if(password !== repeatPassword){ //User put the same password - setSubmitError('Passwords do not match'); - } else if(/\s/.test(password)){ //User put spaces in password - setSubmitError('Password cannot contain spaces'); - } else if(password.length < 8){ //Password too short - setSubmitError('Password must be at least 8 characters long'); - } else if(password.length > 64){ //Password too long - setSubmitError('Password cannot be over 64 characters long'); - } else{ //Continue + //Validations + //TODO: email validation + if(password !== repeatPassword){ + //User put the same password + setSubmitError(t("addUser.error_passwords_no_match")); + } else if(/\s/.test(password)){ + //User put spaces in password + setSubmitError(t("addUser.error_password_spaces")); + } else if(password.length < 8){ + //Password too short + setSubmitError(t("addUser.error_password_minimum_length")); + } else if(password.length > 64){ + //Password too long + setSubmitError(t("addUser.error_password_maximum_length")); + } else if(/\s/.test(username)){ + //Spaces in username + setSubmitError(t("addUser.error_username_spaces")); + } else{ + //Continue setSubmitError(''); const response = await axios.post(apiUrl, { username, password }); console.log("Registered user: " + response.data.username); @@ -40,10 +49,24 @@ const AddUser = () => { } } catch (error) { + if(error.response.data.error === "Username already in use"){ //TODO: Improve + setSubmitError(t("addUser.error_username_in_use")); + } console.error('Error adding user:', error); } }; + //Possible email validation + /** + const validateEmail = (email) => { + return String(email) + .toLowerCase() + .match( + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + ); + }; + */ + const handlePasswordChange = (e) => { const newPassword = e.target.value; setPassword(newPassword); @@ -52,22 +75,22 @@ const AddUser = () => { switch(newStrength.score){ case 0: - setPasswordStrengthText('Weak password'); + setPasswordStrengthText(t("addUser.very_weak_password")); break; case 1: - setPasswordStrengthText('Weak password'); + setPasswordStrengthText(t("addUser.very_weak_password")); break; case 2: - setPasswordStrengthText('Fair password'); + setPasswordStrengthText(t("addUser.weak_password")); break; case 3: - setPasswordStrengthText('Good password'); + setPasswordStrengthText(t("addUser.good_password")); break; case 4: - setPasswordStrengthText('Strong password'); + setPasswordStrengthText(t("addUser.strong_password")); break; default: - setPasswordStrengthText('Weak password'); + setPasswordStrengthText(t("addUser.very_weak_password")); break; } setPasswordStrength(newStrength); diff --git a/webapp/src/translations/en/global.json b/webapp/src/translations/en/global.json index 8f79adda..154bdfa0 100644 --- a/webapp/src/translations/en/global.json +++ b/webapp/src/translations/en/global.json @@ -50,7 +50,16 @@ "password_placeholder": "Password", "repeat_password_placeholder": "Repeat password", "register_button": "Register", - "login_link": "Do you have an account? Login here." + "login_link": "Do you have an account? Login here.", + "very_weak_password": "Very weak password", + "weak_password": "Weak password", + "good_password": "Good password", + "strong_password": "Strong password", + "error_passwords_no_match": "Passwords do not match", + "error_password_spaces": "Password cannot contain spaces", + "error_password_minimum_length": "Password must be at least 8 characters long", + "error_password_maximum_length": "Password cannot be over 64 characters long", + "error_username_in_use": "Username already in use" }, "gameMenu":{ "history_button":"View Historical Data", diff --git a/webapp/src/translations/es/global.json b/webapp/src/translations/es/global.json index 410eebfa..1c0a5f1b 100644 --- a/webapp/src/translations/es/global.json +++ b/webapp/src/translations/es/global.json @@ -54,7 +54,16 @@ "password_placeholder": "Contraseña", "repeat_password_placeholder": "Repetir contraseña", "register_button": "Registrarse", - "login_link": "¿Ya tienes una cuenta? Inicia sesión aquí." + "login_link": "¿Ya tienes una cuenta? Inicia sesión aquí.", + "very_weak_password": "Contraseña muy débil", + "weak_password": "Contraseña débil", + "good_password": "Contraseña buena", + "strong_password": "Contraseña fuerte", + "error_passwords_no_match": "Las contraseñas no coinciden", + "error_password_spaces": "La contraseña no puede contener espacios", + "error_password_minimum_length": "La contraseña debe tener al menos 8 caracteres", + "error_password_maximum_length": "La contraseña no debe tener más de 64 caracteres", + "error_username_in_use": "Nombre de usuario no disponible" }, "gameMenu":{ "history_button":"Ver Historial", diff --git a/webapp/src/translations/tk/global.json b/webapp/src/translations/tk/global.json index 5a17d359..d79e6e10 100644 --- a/webapp/src/translations/tk/global.json +++ b/webapp/src/translations/tk/global.json @@ -50,7 +50,16 @@ "password_placeholder": "Şifre", "repeat_password_placeholder": "Şifreyi Tekrar Girin", "register_button": "Kayıt Ol", - "login_link": "Hesabınız var mı? Buradan giriş yapın." + "login_link": "Hesabınız var mı? Buradan giriş yapın.", + "very_weak_password": "Çok zayıf şifre", + "weak_password": "Zayıf şifre", + "good_password": "İyi şifre", + "strong_password": "Güçlü şifre", + "error_passwords_no_match": "Şifreler eşleşmiyor", + "error_password_spaces": "Şifre boşluk içeremez", + "error_password_minimum_length": "Şifre en az 8 karakter uzunluğunda olmalıdır", + "error_password_maximum_length": "Şifre en fazla 64 karakter uzunluğunda olabilir", + "error_username_in_use": "Kullanıcı adı zaten kullanımda" }, "gameMenu": { "history_button": "Tarihsel Verileri Görüntüle", From ee46ede9b9589e1924f703a0c14c77cb60dd032a Mon Sep 17 00:00:00 2001 From: sinne10 Date: Mon, 15 Apr 2024 21:04:20 +0200 Subject: [PATCH 4/8] Bugfix --- .../loginAndRegistration/AddUser.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/webapp/src/components/loginAndRegistration/AddUser.js b/webapp/src/components/loginAndRegistration/AddUser.js index 5b577edf..0714bd67 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.js +++ b/webapp/src/components/loginAndRegistration/AddUser.js @@ -16,7 +16,7 @@ const AddUser = () => { const [password, setPassword] = useState(''); const [repeatPassword, setRepeatPassword] = useState(''); const [passwordStrength, setPasswordStrength] = useState(undefined); - const [passwordStrengthText, setPasswordStrengthText] = useState(""); + const [passwordStrengthText, setPasswordStrengthText] = useState(''); const [submitError, setSubmitError] = useState(''); @@ -27,19 +27,19 @@ const AddUser = () => { //TODO: email validation if(password !== repeatPassword){ //User put the same password - setSubmitError(t("addUser.error_passwords_no_match")); + setSubmitError("addUser.error_passwords_no_match"); } else if(/\s/.test(password)){ //User put spaces in password - setSubmitError(t("addUser.error_password_spaces")); + setSubmitError("addUser.error_password_spaces"); } else if(password.length < 8){ //Password too short - setSubmitError(t("addUser.error_password_minimum_length")); + setSubmitError("addUser.error_password_minimum_length"); } else if(password.length > 64){ //Password too long - setSubmitError(t("addUser.error_password_maximum_length")); + setSubmitError("addUser.error_password_maximum_length"); } else if(/\s/.test(username)){ //Spaces in username - setSubmitError(t("addUser.error_username_spaces")); + setSubmitError("addUser.error_username_spaces"); } else{ //Continue setSubmitError(''); @@ -50,7 +50,7 @@ const AddUser = () => { } catch (error) { if(error.response.data.error === "Username already in use"){ //TODO: Improve - setSubmitError(t("addUser.error_username_in_use")); + setSubmitError("addUser.error_username_in_use"); } console.error('Error adding user:', error); } @@ -75,22 +75,22 @@ const AddUser = () => { switch(newStrength.score){ case 0: - setPasswordStrengthText(t("addUser.very_weak_password")); + setPasswordStrengthText("addUser.very_weak_password"); break; case 1: - setPasswordStrengthText(t("addUser.very_weak_password")); + setPasswordStrengthText("addUser.very_weak_password"); break; case 2: - setPasswordStrengthText(t("addUser.weak_password")); + setPasswordStrengthText("addUser.weak_password"); break; case 3: - setPasswordStrengthText(t("addUser.good_password")); + setPasswordStrengthText("addUser.good_password"); break; case 4: - setPasswordStrengthText(t("addUser.strong_password")); + setPasswordStrengthText("addUser.strong_password"); break; default: - setPasswordStrengthText(t("addUser.very_weak_password")); + setPasswordStrengthText("addUser.very_weak_password"); break; } setPasswordStrength(newStrength); @@ -126,7 +126,7 @@ const AddUser = () => {
- {passwordStrengthText} + {t(passwordStrengthText.toString())} { onChange={(e) => setRepeatPassword(e.target.value)} />
- {submitError &&

{submitError}

} + {submitError &&

{t(submitError)}

} From 3aea4680d04ebad6b06759cb5da3e07cee941fdd Mon Sep 17 00:00:00 2001 From: sinne10 Date: Tue, 16 Apr 2024 15:40:35 +0200 Subject: [PATCH 5/8] Missing translation --- webapp/src/translations/en/global.json | 1 + webapp/src/translations/es/global.json | 1 + webapp/src/translations/tk/global.json | 1 + 3 files changed, 3 insertions(+) diff --git a/webapp/src/translations/en/global.json b/webapp/src/translations/en/global.json index 154bdfa0..60fd49fa 100644 --- a/webapp/src/translations/en/global.json +++ b/webapp/src/translations/en/global.json @@ -57,6 +57,7 @@ "strong_password": "Strong password", "error_passwords_no_match": "Passwords do not match", "error_password_spaces": "Password cannot contain spaces", + "error_username_spaces": "Username cannot contain spaces", "error_password_minimum_length": "Password must be at least 8 characters long", "error_password_maximum_length": "Password cannot be over 64 characters long", "error_username_in_use": "Username already in use" diff --git a/webapp/src/translations/es/global.json b/webapp/src/translations/es/global.json index 1c0a5f1b..6c6abaa9 100644 --- a/webapp/src/translations/es/global.json +++ b/webapp/src/translations/es/global.json @@ -61,6 +61,7 @@ "strong_password": "Contraseña fuerte", "error_passwords_no_match": "Las contraseñas no coinciden", "error_password_spaces": "La contraseña no puede contener espacios", + "error_username_spaces": "El nombre de usuario no puede contener espacios", "error_password_minimum_length": "La contraseña debe tener al menos 8 caracteres", "error_password_maximum_length": "La contraseña no debe tener más de 64 caracteres", "error_username_in_use": "Nombre de usuario no disponible" diff --git a/webapp/src/translations/tk/global.json b/webapp/src/translations/tk/global.json index d79e6e10..36d4dd1c 100644 --- a/webapp/src/translations/tk/global.json +++ b/webapp/src/translations/tk/global.json @@ -57,6 +57,7 @@ "strong_password": "Güçlü şifre", "error_passwords_no_match": "Şifreler eşleşmiyor", "error_password_spaces": "Şifre boşluk içeremez", + "error_username_spaces": "Kullanıcı adı boşluk içeremez.", "error_password_minimum_length": "Şifre en az 8 karakter uzunluğunda olmalıdır", "error_password_maximum_length": "Şifre en fazla 64 karakter uzunluğunda olabilir", "error_username_in_use": "Kullanıcı adı zaten kullanımda" From 699f57d66f7d1a564a10448ae35ed2762f471023 Mon Sep 17 00:00:00 2001 From: sinne10 Date: Tue, 16 Apr 2024 16:46:58 +0200 Subject: [PATCH 6/8] Added tests --- .../loginAndRegistration/AddUser.test.js | 153 +++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/webapp/src/components/loginAndRegistration/AddUser.test.js b/webapp/src/components/loginAndRegistration/AddUser.test.js index 8cf04089..56cbfb5f 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.test.js +++ b/webapp/src/components/loginAndRegistration/AddUser.test.js @@ -1,14 +1,19 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import AddUser from './AddUser'; -import { BrowserRouter as Router } from 'react-router-dom'; +import axios from 'axios'; +import { BrowserRouter as Router } from 'react-router-dom'; // Mocking useTranslation hook jest.mock('react-i18next', () => ({ useTranslation: () => ({ t: key => key }), })); +// Mocking axios to simulate an error response +jest.mock('axios'); + describe('', () => { + test('renders the AddUser component', () => { render( @@ -24,6 +29,150 @@ describe('', () => { expect(screen.getByText('addUser.login_link')).toBeInTheDocument(); }); + + test('displays error message when passwords do not match', () => { + render( + + + + ); + + const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); + fireEvent.change(usernameInput, { target: { value: 'username' } }); + + const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); + fireEvent.change(passwordInput, { target: { value: '12345678' } }); + + const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); + fireEvent.change(repeatPasswordInput, { target: { value: '123456789' } }); + + const submitButton = screen.getByText('addUser.register_button'); + fireEvent.click(submitButton); + + expect(screen.getByText('addUser.error_passwords_no_match')).toBeInTheDocument(); + }); + + test('displays error message when spaces in password', () => { + render( + + + + ); + + const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); + fireEvent.change(usernameInput, { target: { value: 'username' } }); + + const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); + fireEvent.change(passwordInput, { target: { value: '1234 5678' } }); + + const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); + fireEvent.change(repeatPasswordInput, { target: { value: '1234 5678' } }); + + const submitButton = screen.getByText('addUser.register_button'); + fireEvent.click(submitButton); + + expect(screen.getByText('addUser.error_password_spaces')).toBeInTheDocument(); + }); + + test('displays error message when passwords too short', () => { + render( + + + + ); + + const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); + fireEvent.change(usernameInput, { target: { value: 'username' } }); + + const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); + fireEvent.change(passwordInput, { target: { value: '1234567' } }); + + const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); + fireEvent.change(repeatPasswordInput, { target: { value: '1234567' } }); + + const submitButton = screen.getByText('addUser.register_button'); + fireEvent.click(submitButton); + + expect(screen.getByText('addUser.error_password_minimum_length')).toBeInTheDocument(); + }); + + test('displays error message when passwords too long', () => { + render( + + + + ); + + const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); + fireEvent.change(usernameInput, { target: { value: 'username' } }); + + const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); + fireEvent.change(passwordInput, { target: { value: '01234567890123456789012345678901234567890123456789012345678901234' } }); + + const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); + fireEvent.change(repeatPasswordInput, { target: { value: '01234567890123456789012345678901234567890123456789012345678901234' } }); + + const submitButton = screen.getByText('addUser.register_button'); + fireEvent.click(submitButton); + + expect(screen.getByText('addUser.error_password_maximum_length')).toBeInTheDocument(); + }); + + test('displays error message when spaces in username', () => { + render( + + + + ); + + const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); + fireEvent.change(usernameInput, { target: { value: 'user name' } }); + + const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); + fireEvent.change(passwordInput, { target: { value: '12345678' } }); + + const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); + fireEvent.change(repeatPasswordInput, { target: { value: '12345678' } }); + + const submitButton = screen.getByText('addUser.register_button'); + fireEvent.click(submitButton); + + expect(screen.getByText('addUser.error_username_spaces')).toBeInTheDocument(); + }); + + test('displays error message when username is already in use', async () => { + + // Mock axios post method to simulate response for username already in use + axios.post.mockRejectedValue({ response: { data: { error: 'Username already in use' } } }); + + render( + + + + ); + + const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); + fireEvent.change(usernameInput, { target: { value: 'existing_user' } }); + + const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); + fireEvent.change(passwordInput, { target: { value: '12345678' } }); + + const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); + fireEvent.change(repeatPasswordInput, { target: { value: '12345678' } }); + + const submitButton = screen.getByText('addUser.register_button'); + fireEvent.click(submitButton); + + // Wait for the asynchronous axios call to be completed + await waitFor(() => { + expect(screen.getByText('addUser.error_username_in_use')).toBeInTheDocument(); + }); + + // Ensure axios.post is called with the correct data + expect(axios.post).toHaveBeenCalledWith(expect.any(String), { username: 'existing_user', password: '12345678' }); + + }); + }); From 46c3e9293c120dcb97fec83ff9d78633eaadaaac Mon Sep 17 00:00:00 2001 From: sinne10 Date: Tue, 16 Apr 2024 16:59:22 +0200 Subject: [PATCH 7/8] Fixed duplicated code --- .../loginAndRegistration/AddUser.test.js | 124 +++--------------- 1 file changed, 16 insertions(+), 108 deletions(-) diff --git a/webapp/src/components/loginAndRegistration/AddUser.test.js b/webapp/src/components/loginAndRegistration/AddUser.test.js index 56cbfb5f..ca05c287 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.test.js +++ b/webapp/src/components/loginAndRegistration/AddUser.test.js @@ -14,12 +14,15 @@ jest.mock('axios'); describe('', () => { - test('renders the AddUser component', () => { + beforeEach(() => { render( ); + }); + + test('renders the AddUser component', () => { expect(screen.getByText('addUser.title')).toBeInTheDocument(); expect(screen.getByText('addUser.username_placeholder:')).toBeInTheDocument(); @@ -30,147 +33,52 @@ describe('', () => { }); - test('displays error message when passwords do not match', () => { - render( - - - - ); - + const fillFormAndSubmit = (username, password, repeatPassword) => { const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); - fireEvent.change(usernameInput, { target: { value: 'username' } }); + fireEvent.change(usernameInput, { target: { value: username } }); const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); - fireEvent.change(passwordInput, { target: { value: '12345678' } }); + fireEvent.change(passwordInput, { target: { value: password } }); const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); - fireEvent.change(repeatPasswordInput, { target: { value: '123456789' } }); + fireEvent.change(repeatPasswordInput, { target: { value: repeatPassword } }); const submitButton = screen.getByText('addUser.register_button'); fireEvent.click(submitButton); + }; + test('displays error message when passwords do not match', () => { + fillFormAndSubmit('username', '12345678', '123456789'); expect(screen.getByText('addUser.error_passwords_no_match')).toBeInTheDocument(); }); test('displays error message when spaces in password', () => { - render( - - - - ); - - const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); - fireEvent.change(usernameInput, { target: { value: 'username' } }); - - const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); - fireEvent.change(passwordInput, { target: { value: '1234 5678' } }); - - const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); - fireEvent.change(repeatPasswordInput, { target: { value: '1234 5678' } }); - - const submitButton = screen.getByText('addUser.register_button'); - fireEvent.click(submitButton); - + fillFormAndSubmit('username', '1234 5678', '1234 5678'); expect(screen.getByText('addUser.error_password_spaces')).toBeInTheDocument(); }); test('displays error message when passwords too short', () => { - render( - - - - ); - - const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); - fireEvent.change(usernameInput, { target: { value: 'username' } }); - - const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); - fireEvent.change(passwordInput, { target: { value: '1234567' } }); - - const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); - fireEvent.change(repeatPasswordInput, { target: { value: '1234567' } }); - - const submitButton = screen.getByText('addUser.register_button'); - fireEvent.click(submitButton); - + fillFormAndSubmit('username', '1234567', '1234567'); expect(screen.getByText('addUser.error_password_minimum_length')).toBeInTheDocument(); }); test('displays error message when passwords too long', () => { - render( - - - - ); - - const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); - fireEvent.change(usernameInput, { target: { value: 'username' } }); - - const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); - fireEvent.change(passwordInput, { target: { value: '01234567890123456789012345678901234567890123456789012345678901234' } }); - - const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); - fireEvent.change(repeatPasswordInput, { target: { value: '01234567890123456789012345678901234567890123456789012345678901234' } }); - - const submitButton = screen.getByText('addUser.register_button'); - fireEvent.click(submitButton); - + fillFormAndSubmit('username', '01234567890123456789012345678901234567890123456789012345678901234', '01234567890123456789012345678901234567890123456789012345678901234'); expect(screen.getByText('addUser.error_password_maximum_length')).toBeInTheDocument(); }); test('displays error message when spaces in username', () => { - render( - - - - ); - - const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); - fireEvent.change(usernameInput, { target: { value: 'user name' } }); - - const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); - fireEvent.change(passwordInput, { target: { value: '12345678' } }); - - const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); - fireEvent.change(repeatPasswordInput, { target: { value: '12345678' } }); - - const submitButton = screen.getByText('addUser.register_button'); - fireEvent.click(submitButton); - + fillFormAndSubmit('user name', '12345678', '12345678'); expect(screen.getByText('addUser.error_username_spaces')).toBeInTheDocument(); }); test('displays error message when username is already in use', async () => { - - // Mock axios post method to simulate response for username already in use axios.post.mockRejectedValue({ response: { data: { error: 'Username already in use' } } }); - - render( - - - - ); - - const usernameInput = screen.getByPlaceholderText('addUser.username_placeholder'); - fireEvent.change(usernameInput, { target: { value: 'existing_user' } }); - - const passwordInput = screen.getByPlaceholderText('addUser.password_placeholder'); - fireEvent.change(passwordInput, { target: { value: '12345678' } }); - - const repeatPasswordInput = screen.getByPlaceholderText('addUser.repeat_password_placeholder'); - fireEvent.change(repeatPasswordInput, { target: { value: '12345678' } }); - - const submitButton = screen.getByText('addUser.register_button'); - fireEvent.click(submitButton); - - // Wait for the asynchronous axios call to be completed + fillFormAndSubmit('existing_user', '12345678', '12345678'); await waitFor(() => { expect(screen.getByText('addUser.error_username_in_use')).toBeInTheDocument(); }); - - // Ensure axios.post is called with the correct data expect(axios.post).toHaveBeenCalledWith(expect.any(String), { username: 'existing_user', password: '12345678' }); - }); }); From aeda7db304b5e4a4e74cf4bfc84f9f7c2f3e7bf0 Mon Sep 17 00:00:00 2001 From: sinne10 Date: Tue, 16 Apr 2024 17:21:33 +0200 Subject: [PATCH 8/8] Refactor --- .../loginAndRegistration/AddUser.test.js | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/webapp/src/components/loginAndRegistration/AddUser.test.js b/webapp/src/components/loginAndRegistration/AddUser.test.js index ca05c287..70493840 100644 --- a/webapp/src/components/loginAndRegistration/AddUser.test.js +++ b/webapp/src/components/loginAndRegistration/AddUser.test.js @@ -47,32 +47,23 @@ describe('', () => { fireEvent.click(submitButton); }; - test('displays error message when passwords do not match', () => { + test('displays correct error messages', async () => { + //Passwords do not match fillFormAndSubmit('username', '12345678', '123456789'); expect(screen.getByText('addUser.error_passwords_no_match')).toBeInTheDocument(); - }); - - test('displays error message when spaces in password', () => { + //Password with spaces fillFormAndSubmit('username', '1234 5678', '1234 5678'); expect(screen.getByText('addUser.error_password_spaces')).toBeInTheDocument(); - }); - - test('displays error message when passwords too short', () => { + //Password too short fillFormAndSubmit('username', '1234567', '1234567'); expect(screen.getByText('addUser.error_password_minimum_length')).toBeInTheDocument(); - }); - - test('displays error message when passwords too long', () => { + //Password too long fillFormAndSubmit('username', '01234567890123456789012345678901234567890123456789012345678901234', '01234567890123456789012345678901234567890123456789012345678901234'); expect(screen.getByText('addUser.error_password_maximum_length')).toBeInTheDocument(); - }); - - test('displays error message when spaces in username', () => { + //Username with spaces fillFormAndSubmit('user name', '12345678', '12345678'); expect(screen.getByText('addUser.error_username_spaces')).toBeInTheDocument(); - }); - - test('displays error message when username is already in use', async () => { + //Username in use axios.post.mockRejectedValue({ response: { data: { error: 'Username already in use' } } }); fillFormAndSubmit('existing_user', '12345678', '12345678'); await waitFor(() => {