Skip to content

Commit

Permalink
fix: password inputs required validation (#387)
Browse files Browse the repository at this point in the history
* fix: password inputs

* fix: add tests for empty inputs

* fix: remove console.log
  • Loading branch information
spaenleh authored Oct 23, 2024
1 parent 42e4c1f commit df4665b
Show file tree
Hide file tree
Showing 15 changed files with 100 additions and 50 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
38 changes: 38 additions & 0 deletions cypress/e2e/profile/password.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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',
Expand Down
1 change: 0 additions & 1 deletion src/langs/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 أحرف على الأقل, حيث تحتوي على رقم, حرف صغير وحرف كبير.",
Expand Down
1 change: 1 addition & 0 deletions src/langs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
};
1 change: 0 additions & 1 deletion src/langs/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
1 change: 0 additions & 1 deletion src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
1 change: 0 additions & 1 deletion src/langs/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
1 change: 0 additions & 1 deletion src/langs/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
1 change: 0 additions & 1 deletion src/langs/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
2 changes: 1 addition & 1 deletion src/modules/profile/password/CreatePassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 11 additions & 9 deletions src/modules/profile/password/EditPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -102,10 +102,15 @@ const EditPassword = ({ onClose }: EditPasswordProps): JSX.Element => {
id={PASSWORD_EDIT_CONTAINER_ID}
title={t('PASSWORD_SETTINGS_TITLE')}
>
<Typography variant="body1">
{t('PASSWORD_SETTINGS_CONFIRM_INFORMATION')}
</Typography>
<Stack spacing={2} component="form" onSubmit={handleSubmit(onSubmit)}>
<Stack
direction="column"
gap={2}
component="form"
onSubmit={handleSubmit(onSubmit)}
>
<Typography variant="body1">
{t('PASSWORD_SETTINGS_CONFIRM_INFORMATION')}
</Typography>
<Box>
<PasswordField
id={PASSWORD_INPUT_CURRENT_PASSWORD_ID}
Expand All @@ -122,12 +127,9 @@ const EditPassword = ({ onClose }: EditPasswordProps): JSX.Element => {
},
})}
/>
<Typography variant="subtitle2">
{t('PASSWORD_SETTINGS_CURRENT_INFORMATION')}
</Typography>
</Box>

<Stack direction="row" spacing={2}>
<Stack direction="row" gap={2}>
<PasswordField
label={t('PASSWORD_SETTINGS_NEW_LABEL')}
error={Boolean(newPasswordErrorMessage)}
Expand Down
46 changes: 30 additions & 16 deletions src/modules/profile/password/PasswordField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useState } from 'react';
import { UseFormRegisterReturn } from 'react-hook-form';

import { TextField } from '@mui/material';
import { IconButton, InputAdornment, TextField } from '@mui/material';

import { Eye } from 'lucide-react';

type Props<T extends string> = {
id: string;
Expand All @@ -10,24 +13,35 @@ type Props<T extends string> = {
form: UseFormRegisterReturn<T>;
};

const PasswordField = <T extends string>({
export function PasswordField<T extends string>({
id,
label,
error,
helperText,
form,
}: Props<T>): JSX.Element => (
<TextField
required
label={label}
variant="outlined"
size="small"
error={error}
helperText={helperText}
type="password"
id={id}
{...form}
/>
);
}: Props<T>): JSX.Element {
const [showPassword, setShowPassword] = useState(false);

export default PasswordField;
return (
<TextField
InputProps={{
sx: { paddingRight: 0 },
endAdornment: (
<InputAdornment position="end" sx={{ margin: 0 }}>
<IconButton onClick={() => setShowPassword((s) => !s)}>
<Eye />
</IconButton>
</InputAdornment>
),
}}
label={label}
variant="outlined"
size="small"
error={error}
helperText={helperText}
type={showPassword ? 'text' : 'password'}
id={id}
{...form}
/>
);
}
31 changes: 16 additions & 15 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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: {
Expand Down

0 comments on commit df4665b

Please sign in to comment.