From df4665b5a18219bd4943a7c566866f67b88ae3a1 Mon Sep 17 00:00:00 2001 From: Basile Spaenlehauer Date: Wed, 23 Oct 2024 16:03:44 +0200 Subject: [PATCH] fix: password inputs required validation (#387) * fix: password inputs * fix: add tests for empty inputs * fix: remove console.log --- .github/workflows/deploy-dev.yml | 2 +- .github/workflows/deploy-prod.yml | 2 +- .github/workflows/deploy-stage.yml | 2 +- cypress/e2e/profile/password.cy.ts | 38 +++++++++++++++ src/langs/ar.json | 1 - src/langs/constants.ts | 1 + src/langs/de.json | 1 - src/langs/en.json | 1 - src/langs/es.json | 1 - src/langs/fr.json | 1 - src/langs/it.json | 1 - .../profile/password/CreatePassword.tsx | 2 +- src/modules/profile/password/EditPassword.tsx | 20 ++++---- .../profile/password/PasswordField.tsx | 46 ++++++++++++------- vite.config.ts | 31 +++++++------ 15 files changed, 100 insertions(+), 50 deletions(-) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index c827b2b29..6b5b3f0c3 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -36,7 +36,7 @@ jobs: VITE_SENTRY_ENV: ${{ vars.VITE_SENTRY_ENV }} VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }} - UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID }} + VITE_UMAMI_WEBSITE_ID: ${{ secrets.VITE_UMAMI_WEBSITE_ID }} run: pnpm build shell: bash diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 7e1676604..3ffdc193c 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -39,7 +39,7 @@ jobs: VITE_SENTRY_ENV: ${{ vars.VITE_SENTRY_ENV }} VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }} - UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID }} + VITE_UMAMI_WEBSITE_ID: ${{ secrets.VITE_UMAMI_WEBSITE_ID }} run: pnpm build shell: bash diff --git a/.github/workflows/deploy-stage.yml b/.github/workflows/deploy-stage.yml index c58506145..c2e1e677b 100644 --- a/.github/workflows/deploy-stage.yml +++ b/.github/workflows/deploy-stage.yml @@ -39,7 +39,7 @@ jobs: VITE_SENTRY_ENV: ${{ vars.VITE_SENTRY_ENV }} VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }} - UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID }} + VITE_UMAMI_WEBSITE_ID: ${{ secrets.VITE_UMAMI_WEBSITE_ID }} run: pnpm build shell: bash diff --git a/cypress/e2e/profile/password.cy.ts b/cypress/e2e/profile/password.cy.ts index 7c8ff1b95..d1c31275a 100644 --- a/cypress/e2e/profile/password.cy.ts +++ b/cypress/e2e/profile/password.cy.ts @@ -67,6 +67,23 @@ describe('Create new password', () => { ); }); + it('Show error on empty inputs', () => { + openPasswordEdition(); + + cy.get(`#${PASSWORD_SAVE_BUTTON_ID}`).click(); + cy.get(`#${PASSWORD_SAVE_BUTTON_ID}`).should('be.disabled'); + + // should show input required message + cy.get(`#${PASSWORD_INPUT_NEW_PASSWORD_ID}-helper-text`).should( + 'contain', + i18n.t(ACCOUNT.REQUIRED_FIELD_ERROR), + ); + cy.get(`#${PASSWORD_INPUT_CONFIRM_PASSWORD_ID}-helper-text`).should( + 'contain', + i18n.t(ACCOUNT.REQUIRED_FIELD_ERROR), + ); + }); + it('Show error on weak new password', () => { openPasswordEdition(); @@ -160,6 +177,27 @@ describe('Update password', () => { i18n.setDefaultNamespace(ACCOUNT_NAMESPACE); }); + it('Show error on empty inputs', () => { + openPasswordEdition(); + + cy.get(`#${PASSWORD_SAVE_BUTTON_ID}`).click(); + cy.get(`#${PASSWORD_SAVE_BUTTON_ID}`).should('be.disabled'); + + // should show input required message + cy.get(`#${PASSWORD_INPUT_NEW_PASSWORD_ID}-helper-text`).should( + 'contain', + i18n.t(ACCOUNT.REQUIRED_FIELD_ERROR), + ); + cy.get(`#${PASSWORD_INPUT_CONFIRM_PASSWORD_ID}-helper-text`).should( + 'contain', + i18n.t(ACCOUNT.REQUIRED_FIELD_ERROR), + ); + cy.get(`#${PASSWORD_INPUT_CURRENT_PASSWORD_ID}-helper-text`).should( + 'contain', + i18n.t(ACCOUNT.REQUIRED_FIELD_ERROR), + ); + }); + it('Show edit message when a password is set', () => { cy.get(`#${PASSWORD_DISPLAY_CONTAINER_ID}`).should( 'contain', diff --git a/src/langs/ar.json b/src/langs/ar.json index 31f5b13b5..cef60fc3d 100644 --- a/src/langs/ar.json +++ b/src/langs/ar.json @@ -42,7 +42,6 @@ "PASSWORD_SETTINGS_INFORMATION": "قم بتحديث كلمة المرور الخاصة بك عن طريق النقر فوق الزر \"تحرير\".", "PASSWORD_SETTINGS_TITLE": "تغيير كلمة السرّ", "PASSWORD_SETTINGS_CURRENT_LABEL": "كلمة السرّ الحالية", - "PASSWORD_SETTINGS_CURRENT_INFORMATION": "اترك هذا الحقل فارغًا إذا لا تملك كلمة سرّ سابقًا.", "PASSWORD_SETTINGS_NEW_LABEL": "كلمة السرّ الجديدة", "PASSWORD_SETTINGS_NEW_CONFIRM_LABEL": "تأكيد كلمة السرّ", "PASSWORD_SETTINGS_CONFIRM_INFORMATION": "تأكد أنّها تتكوّن من 8 أحرف على الأقل, حيث تحتوي على رقم, حرف صغير وحرف كبير.", diff --git a/src/langs/constants.ts b/src/langs/constants.ts index 963b82c9e..fff91728f 100644 --- a/src/langs/constants.ts +++ b/src/langs/constants.ts @@ -8,4 +8,5 @@ export const ACCOUNT = { PASSWORD_DO_NOT_MATCH_ERROR: 'PASSWORD_DO_NOT_MATCH_ERROR', NEW_PASSWORD_SHOULD_NOT_MATCH_CURRENT_PASSWORD_ERROR: 'NEW_PASSWORD_SHOULD_NOT_MATCH_CURRENT_PASSWORD_ERROR', + REQUIRED_FIELD_ERROR: 'REQUIRED_FIELD_ERROR', }; diff --git a/src/langs/de.json b/src/langs/de.json index 6ab033bf6..592c8a3ef 100644 --- a/src/langs/de.json +++ b/src/langs/de.json @@ -42,7 +42,6 @@ "PASSWORD_SETTINGS_INFORMATION": "Aktualisieren Sie Ihr Passwort, indem Sie auf die Schaltfläche „Bearbeiten“ klicken.", "PASSWORD_SETTINGS_TITLE": "Passwort ändern", "PASSWORD_SETTINGS_CURRENT_LABEL": "Aktuelles Passwort", - "PASSWORD_SETTINGS_CURRENT_INFORMATION": "Lassen Sie dieses Feld leer, wenn Sie noch kein Passwort festgelegt haben.", "PASSWORD_SETTINGS_NEW_LABEL": "Neues Passwort", "PASSWORD_SETTINGS_NEW_CONFIRM_LABEL": "Passwort bestätigen", "PASSWORD_SETTINGS_CONFIRM_INFORMATION": "Er muss aus mindestens 8 Zeichen bestehen, darunter eine Zahl, ein Kleinbuchstabe und ein Großbuchstabe.", diff --git a/src/langs/en.json b/src/langs/en.json index 2287d00d7..1412b38c4 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -43,7 +43,6 @@ "PASSWORD_SETTINGS_INFORMATION_NEW_PASSWORD": "Add a password by clicking on the 'Configure' button", "PASSWORD_SETTINGS_TITLE": "Password settings", "PASSWORD_SETTINGS_CURRENT_LABEL": "Current Password", - "PASSWORD_SETTINGS_CURRENT_INFORMATION": "Leave this field empty if you do not already have a password set.", "PASSWORD_SETTINGS_NEW_LABEL": "New Password", "PASSWORD_SETTINGS_NEW_CONFIRM_LABEL": "Confirm Password", "PASSWORD_SETTINGS_CONFIRM_INFORMATION": "Make sure it is at least 8 characters including a number, a lowercase letter and an uppercase letter.", diff --git a/src/langs/es.json b/src/langs/es.json index 46bae39b4..1bc077a16 100644 --- a/src/langs/es.json +++ b/src/langs/es.json @@ -42,7 +42,6 @@ "PASSWORD_SETTINGS_INFORMATION": "Actualice su contraseña haciendo clic en el botón 'Editar'", "PASSWORD_SETTINGS_TITLE": "Cambiar la contraseña", "PASSWORD_SETTINGS_CURRENT_LABEL": "Contraseña actual", - "PASSWORD_SETTINGS_CURRENT_INFORMATION": "Deje este campo vacío si aún no tienes una contraseña establecida.", "PASSWORD_SETTINGS_NEW_LABEL": "Nueva contraseña", "PASSWORD_SETTINGS_NEW_CONFIRM_LABEL": "confirmar Contraseña", "PASSWORD_SETTINGS_CONFIRM_INFORMATION": "Asegúrate de que tenga al menos 8 caracteres, incluido un número, una letra minúscula y una letra mayúscula.", diff --git a/src/langs/fr.json b/src/langs/fr.json index 41784e18e..01bb5404b 100644 --- a/src/langs/fr.json +++ b/src/langs/fr.json @@ -43,7 +43,6 @@ "PASSWORD_SETTINGS_INFORMATION_NEW_PASSWORD": "Définir un mot de passe en cliquant sur le bouton 'Configurer'", "PASSWORD_SETTINGS_TITLE": "Paramètres du mot de passe", "PASSWORD_SETTINGS_CURRENT_LABEL": "Mot de passe actuel", - "PASSWORD_SETTINGS_CURRENT_INFORMATION": "Laissez le champ vide si vous n'avez pas précédemment défini de mot de passe.", "PASSWORD_SETTINGS_NEW_LABEL": "Nouveau mot de passe", "PASSWORD_SETTINGS_NEW_CONFIRM_LABEL": "Confirmer le mot de passe", "PASSWORD_SETTINGS_CONFIRM_INFORMATION": "Le mot de passe doit au moins contenir 8 caractères dont un chiffre, une lettre minuscule et une lettre majuscule.", diff --git a/src/langs/it.json b/src/langs/it.json index dd23cad60..81150ca92 100644 --- a/src/langs/it.json +++ b/src/langs/it.json @@ -42,7 +42,6 @@ "PASSWORD_SETTINGS_INFORMATION": "Aggiorna la tua password facendo clic sul pulsante \"Modifica\".", "PASSWORD_SETTINGS_TITLE": "Cambiare la Password", "PASSWORD_SETTINGS_CURRENT_LABEL": "Password attuale", - "PASSWORD_SETTINGS_CURRENT_INFORMATION": "Lascia vuoto questo campo se non hai già impostato una password.", "PASSWORD_SETTINGS_NEW_LABEL": "Nuova Password", "PASSWORD_SETTINGS_NEW_CONFIRM_LABEL": "Conferma Password", "PASSWORD_SETTINGS_CONFIRM_INFORMATION": "Assicurati che contenga almeno 8 caratteri inclusi un numero, una lettera minuscola e una lettera maiuscola.", diff --git a/src/modules/profile/password/CreatePassword.tsx b/src/modules/profile/password/CreatePassword.tsx index 4d32c8da9..5423eafca 100644 --- a/src/modules/profile/password/CreatePassword.tsx +++ b/src/modules/profile/password/CreatePassword.tsx @@ -24,7 +24,7 @@ import { } from '@/config/selectors'; import { ACCOUNT } from '@/langs/constants'; -import PasswordField from './PasswordField'; +import { PasswordField } from './PasswordField'; type CreatePasswordProps = { onClose: () => void; diff --git a/src/modules/profile/password/EditPassword.tsx b/src/modules/profile/password/EditPassword.tsx index 9cae7f34d..de0b4f289 100644 --- a/src/modules/profile/password/EditPassword.tsx +++ b/src/modules/profile/password/EditPassword.tsx @@ -25,7 +25,7 @@ import { } from '@/config/selectors'; import { ACCOUNT } from '@/langs/constants'; -import PasswordField from './PasswordField'; +import { PasswordField } from './PasswordField'; type EditPasswordProps = { onClose: () => void; @@ -102,10 +102,15 @@ const EditPassword = ({ onClose }: EditPasswordProps): JSX.Element => { id={PASSWORD_EDIT_CONTAINER_ID} title={t('PASSWORD_SETTINGS_TITLE')} > - - {t('PASSWORD_SETTINGS_CONFIRM_INFORMATION')} - - + + + {t('PASSWORD_SETTINGS_CONFIRM_INFORMATION')} + { }, })} /> - - {t('PASSWORD_SETTINGS_CURRENT_INFORMATION')} - - + = { id: string; @@ -10,24 +13,35 @@ type Props = { form: UseFormRegisterReturn; }; -const PasswordField = ({ +export function PasswordField({ id, label, error, helperText, form, -}: Props): JSX.Element => ( - -); +}: Props): JSX.Element { + const [showPassword, setShowPassword] = useState(false); -export default PasswordField; + return ( + + setShowPassword((s) => !s)}> + + + + ), + }} + label={label} + variant="outlined" + size="small" + error={error} + helperText={helperText} + type={showPassword ? 'text' : 'password'} + id={id} + {...form} + /> + ); +} diff --git a/vite.config.ts b/vite.config.ts index d22102761..290ee3a07 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,10 +16,9 @@ const config = ({ mode }: { mode: string }): UserConfigExport => { ...loadEnv(mode, process.cwd()), }; - const { VITE_PORT, BROWSER, UMAMI_WEBSITE_ID } = process.env; + const { VITE_PORT, BROWSER, VITE_UMAMI_WEBSITE_ID } = process.env; // compute the port to use const PORT = parseInt(VITE_PORT || '3114', 10); - // compute whether we should open the browser // this defines if we should automatically open the browser const shouldOpen = BROWSER && BROWSER !== 'none'; @@ -53,21 +52,23 @@ const config = ({ mode }: { mode: string }): UserConfigExport => { }, overlay: { initialIsOpen: false }, }) - : undefined, + : istanbul({ + include: 'src/*', + exclude: ['node_modules', 'test/', '.nyc_output', 'coverage'], + extension: ['.js', '.ts', '.tsx'], + requireEnv: false, + // forces to instrument code also in production build only if the mode is test + // this is useful when we want to build and preview in CI to have faster and more stable tests + forceBuildInstrument: mode === 'test', + checkProd: true, + }), react(), - istanbul({ - include: 'src/*', - exclude: ['node_modules', 'test/', '.nyc_output', 'coverage'], - extension: ['.js', '.ts', '.tsx'], - requireEnv: false, - // forces to instrument code also in production build only if the mode is test - // this is useful when we want to build and preview in CI to have faster and more stable tests - forceBuildInstrument: mode === 'test', - checkProd: true, - }), // only include umami script when the WEBSITE_ID is set - UMAMI_WEBSITE_ID - ? umamiPlugin({ websiteId: UMAMI_WEBSITE_ID }) + VITE_UMAMI_WEBSITE_ID + ? umamiPlugin({ + websiteId: VITE_UMAMI_WEBSITE_ID, + enableInDevMode: true, + }) : undefined, ], resolve: {