From 975eb5245a28ceb4c2547d435cc875628c2215cd Mon Sep 17 00:00:00 2001 From: Sandra Nymark-Brand Date: Tue, 24 Jun 2025 14:13:44 +0200 Subject: [PATCH 1/7] fix(ui): improve delete account modal with inline errors --- .../account/profile/AccountProfilePage.tsx | 10 ++- .../account/profile/ActionConfirmModal.tsx | 81 ++++++++++++------- 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx index 2b1d3ea12bd69..d036a88c7fae7 100644 --- a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx +++ b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx @@ -92,10 +92,11 @@ const AccountProfilePage = (): ReactElement => { ); const handleDeleteOwnAccount = useCallback(async () => { - const handleConfirm = async (passwordOrUsername: string): Promise => { + const handleConfirm = async (passwordOrUsername: string, setInputError: (message: string) => void ): Promise => { try { await deleteOwnAccount({ password: SHA256(passwordOrUsername) }); dispatchToastMessage({ type: 'success', message: t('User_has_been_deleted') }); + setModal(null); logout(); } catch (error: any) { if (error.error === 'user-last-owner') { @@ -103,7 +104,12 @@ const AccountProfilePage = (): ReactElement => { return handleConfirmOwnerChange(passwordOrUsername, shouldChangeOwner, shouldBeRemoved); } - dispatchToastMessage({ type: 'error', message: error }); + if ( + error.errorType === 'error-invalid-password' + ) { + setInputError(t('Invalid_password')); + return; + } } }; diff --git a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx index 20a00c195cd85..1a737777dd220 100644 --- a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx +++ b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx @@ -1,44 +1,43 @@ import { Box, PasswordInput, TextInput, FieldGroup, Field, FieldRow, FieldError } from '@rocket.chat/fuselage'; -import type { ChangeEvent } from 'react'; -import { useState, useCallback, useId } from 'react'; +import { useId } from 'react'; +import { useForm, Controller } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import GenericModal from '../../../components/GenericModal'; type ActionConfirmModalProps = { isPassword: boolean; - onConfirm: (input: string) => void; + onConfirm: (input: string, setInputError: (message: string) => void) => void; onCancel: () => void; }; // TODO: Use react-hook-form const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmModalProps) => { const { t } = useTranslation(); - const [inputText, setInputText] = useState(''); - const [inputError, setInputError] = useState(); + const actionTextId = useId(); + const inputId = useId(); + const errorId = `${inputId}-error`; - const handleChange = useCallback( - (e: ChangeEvent) => { - e.target.value !== '' && setInputError(undefined); - setInputText(e.currentTarget.value); - }, - [setInputText], - ); + const { + control, + handleSubmit, + setError, + setFocus, + formState: { errors }, + } = useForm<{ credential: string}>({ + defaultValues: { credential: '' }, + mode: 'onBlur', + }); - const handleSave = useCallback( - (e: ChangeEvent) => { - e.preventDefault(); - if (inputText === '') { - setInputError(t('Invalid_field')); - return; + const handleSave = handleSubmit(({ credential }) =>{ + onConfirm(credential, (message) =>{ + if (message) { + setError( 'credential', { message }); + setFocus('credential'); } - onConfirm(inputText); - onCancel(); - }, - [inputText, onConfirm, onCancel, t], - ); + }); + }); - const actionTextId = useId(); return ( } @@ -55,10 +54,38 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo - {isPassword && } - {!isPassword && } + + isPassword ? ( + + ) : ( + + ) + } + /> - {inputError} + {errors.credential && ( + {errors.credential.message} + )} + From af6baea318de28a7dfe477f03edea256341ab5dc Mon Sep 17 00:00:00 2001 From: Sandra Nymark-Brand Date: Tue, 16 Sep 2025 22:11:02 +0200 Subject: [PATCH 2/7] Fix: inline error for Delete Account --- .../account/profile/AccountProfilePage.tsx | 11 +++---- .../account/profile/ActionConfirmModal.tsx | 32 +++++++++++-------- .../account/profile/DeleteAccountError.ts | 4 +++ 3 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 apps/meteor/client/views/account/profile/DeleteAccountError.ts diff --git a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx index d036a88c7fae7..df200a8c08642 100644 --- a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx +++ b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx @@ -21,6 +21,7 @@ import { getProfileInitialValues } from './getProfileInitialValues'; import ConfirmOwnerChangeModal from '../../../components/ConfirmOwnerChangeModal'; import { Page, PageFooter, PageHeader, PageScrollableContentWithShadow } from '../../../components/Page'; import { useAllowPasswordChange } from '../security/useAllowPasswordChange'; +import { InputError } from './DeleteAccountError'; // TODO: enforce useMutation const AccountProfilePage = (): ReactElement => { @@ -92,7 +93,7 @@ const AccountProfilePage = (): ReactElement => { ); const handleDeleteOwnAccount = useCallback(async () => { - const handleConfirm = async (passwordOrUsername: string, setInputError: (message: string) => void ): Promise => { + const handleConfirm = async (passwordOrUsername: string): Promise => { try { await deleteOwnAccount({ password: SHA256(passwordOrUsername) }); dispatchToastMessage({ type: 'success', message: t('User_has_been_deleted') }); @@ -104,12 +105,10 @@ const AccountProfilePage = (): ReactElement => { return handleConfirmOwnerChange(passwordOrUsername, shouldChangeOwner, shouldBeRemoved); } - if ( - error.errorType === 'error-invalid-password' - ) { - setInputError(t('Invalid_password')); - return; + if (error.errorType === 'error-invalid-password') { + throw new InputError(t('Invalid_password')); } + dispatchToastMessage({ type: 'error', message: error }); } }; diff --git a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx index 1a737777dd220..7632c63c55454 100644 --- a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx +++ b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx @@ -2,12 +2,13 @@ import { Box, PasswordInput, TextInput, FieldGroup, Field, FieldRow, FieldError import { useId } from 'react'; import { useForm, Controller } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; +import { InputError } from './DeleteAccountError'; import GenericModal from '../../../components/GenericModal'; type ActionConfirmModalProps = { isPassword: boolean; - onConfirm: (input: string, setInputError: (message: string) => void) => void; + onConfirm: (input: string) => Promise; onCancel: () => void; }; @@ -24,18 +25,22 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo setError, setFocus, formState: { errors }, - } = useForm<{ credential: string}>({ + } = useForm<{ credential: string }>({ defaultValues: { credential: '' }, mode: 'onBlur', }); - const handleSave = handleSubmit(({ credential }) =>{ - onConfirm(credential, (message) =>{ - if (message) { - setError( 'credential', { message }); + const handleSave = handleSubmit(async ({ credential }) => { + try { + await onConfirm(credential); + onCancel(); + } catch (error) { + if (error instanceof InputError) { + setError('credential', { message: error.message }); setFocus('credential'); + return; } - }); + } }); return ( @@ -54,11 +59,11 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo - + render={({ field }) => isPassword ? ( ) : ( ) } /> {errors.credential && ( - {errors.credential.message} + + {errors.credential.message} + )} - diff --git a/apps/meteor/client/views/account/profile/DeleteAccountError.ts b/apps/meteor/client/views/account/profile/DeleteAccountError.ts new file mode 100644 index 0000000000000..d35dfaa332de5 --- /dev/null +++ b/apps/meteor/client/views/account/profile/DeleteAccountError.ts @@ -0,0 +1,4 @@ +export class InputError extends Error { constructor(message: string) { +super(message); + } +} From c1d21d597d3a87d554ac8429db645b0bbdb33fe3 Mon Sep 17 00:00:00 2001 From: Sandra Nymark-Brand Date: Wed, 17 Sep 2025 00:05:47 +0200 Subject: [PATCH 3/7] fix: remove extra onCancel() in ActionConfirmModal submit handler --- apps/meteor/client/views/account/profile/ActionConfirmModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx index be139d9cd9604..68eca1775f17d 100644 --- a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx +++ b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx @@ -32,7 +32,6 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo const handleSave = handleSubmit(async ({ credential }) => { try { await onConfirm(credential); - onCancel(); } catch (error) { if (error instanceof InputError) { setError('credential', { message: error.message }); From 8b2433d818807edbdfe20045f0cb55a982fc4f45 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Fri, 20 Feb 2026 16:42:41 -0300 Subject: [PATCH 4/7] fix: review --- .../account/profile/AccountProfilePage.tsx | 4 +- .../account/profile/ActionConfirmModal.tsx | 39 ++++++++----------- .../account/profile/DeleteAccountError.ts | 4 -- 3 files changed, 18 insertions(+), 29 deletions(-) delete mode 100644 apps/meteor/client/views/account/profile/DeleteAccountError.ts diff --git a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx index 7c6abf22faf4f..a0499ddadcc35 100644 --- a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx +++ b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx @@ -21,7 +21,6 @@ import ActionConfirmModal from './ActionConfirmModal'; import { getProfileInitialValues } from './getProfileInitialValues'; import ConfirmOwnerChangeModal from '../../../components/ConfirmOwnerChangeModal'; import { useAllowPasswordChange } from '../security/useAllowPasswordChange'; -import { InputError } from './DeleteAccountError'; // TODO: enforce useMutation const AccountProfilePage = (): ReactElement => { @@ -106,8 +105,9 @@ const AccountProfilePage = (): ReactElement => { } if (error.errorType === 'error-invalid-password') { - throw new InputError(t('Invalid_password')); + throw error; } + dispatchToastMessage({ type: 'error', message: error }); } }; diff --git a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx index 68eca1775f17d..f4d2a48a80148 100644 --- a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx +++ b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx @@ -1,9 +1,8 @@ import { Box, PasswordInput, TextInput, FieldGroup, Field, FieldRow, FieldError } from '@rocket.chat/fuselage'; +import { GenericModal } from '@rocket.chat/ui-client'; import { useId } from 'react'; import { useForm, Controller } from 'react-hook-form'; -import { GenericModal } from '@rocket.chat/ui-client'; import { useTranslation } from 'react-i18next'; -import { InputError } from './DeleteAccountError'; type ActionConfirmModalProps = { isPassword: boolean; @@ -11,41 +10,35 @@ type ActionConfirmModalProps = { onCancel: () => void; }; -// TODO: Use react-hook-form const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmModalProps) => { const { t } = useTranslation(); const actionTextId = useId(); - const inputId = useId(); - const errorId = `${inputId}-error`; + const credentialFieldId = useId(); + const credentialFieldError = `${credentialFieldId}-error`; const { control, handleSubmit, setError, - setFocus, formState: { errors }, - } = useForm<{ credential: string }>({ + } = useForm({ defaultValues: { credential: '' }, mode: 'onBlur', }); - const handleSave = handleSubmit(async ({ credential }) => { + const handleSave = async ({ credential }: { credential: string }) => { try { await onConfirm(credential); - } catch (error) { - if (error instanceof InputError) { - setError('credential', { message: error.message }); - setFocus('credential'); - return; + } catch (error: any) { + if (error.errorType === 'error-invalid-password') { + setError('credential', { message: t('Invalid_password') }, { shouldFocus: true }); } } - }); + }; return ( } - onClose={onCancel} - onConfirm={handleSave} + wrapperFunction={(props) => } onCancel={onCancel} variant='danger' title={t('Delete_account?')} @@ -60,24 +53,24 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo isPassword ? ( ) : ( @@ -86,7 +79,7 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo /> {errors.credential && ( - + {errors.credential.message} )} diff --git a/apps/meteor/client/views/account/profile/DeleteAccountError.ts b/apps/meteor/client/views/account/profile/DeleteAccountError.ts deleted file mode 100644 index d35dfaa332de5..0000000000000 --- a/apps/meteor/client/views/account/profile/DeleteAccountError.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class InputError extends Error { constructor(message: string) { -super(message); - } -} From a6dc24d26a6696fc164200fc02e5d06414aad0e1 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 25 Feb 2026 19:17:35 -0300 Subject: [PATCH 5/7] fix: improve accessibility and error handling in ActionConfirmModal --- .../account/profile/ActionConfirmModal.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx index f4d2a48a80148..e9d567498168c 100644 --- a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx +++ b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx @@ -1,4 +1,4 @@ -import { Box, PasswordInput, TextInput, FieldGroup, Field, FieldRow, FieldError } from '@rocket.chat/fuselage'; +import { Box, PasswordInput, TextInput, FieldGroup, Field, FieldRow, FieldError, FieldLabel } from '@rocket.chat/fuselage'; import { GenericModal } from '@rocket.chat/ui-client'; import { useId } from 'react'; import { useForm, Controller } from 'react-hook-form'; @@ -12,7 +12,6 @@ type ActionConfirmModalProps = { const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmModalProps) => { const { t } = useTranslation(); - const actionTextId = useId(); const credentialFieldId = useId(); const credentialFieldError = `${credentialFieldId}-error`; @@ -44,11 +43,11 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo title={t('Delete_account?')} confirmText={t('Delete_account')} > - - {isPassword ? t('Enter_your_password_to_delete_your_account') : t('Enter_your_username_to_delete_your_account')} - + + {isPassword ? t('Enter_your_password_to_delete_your_account') : t('Enter_your_username_to_delete_your_account')} + ) : ( @@ -69,9 +68,9 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo {...field} id={credentialFieldId} placeholder={t('Username')} - aria-labelledby={actionTextId} + error={errors.credential?.message} + aria-invalid={errors.credential ? 'true' : 'false'} aria-describedby={errors.credential ? credentialFieldError : undefined} - aria-invalid={Boolean(errors.credential)} aria-required='true' /> ) From ab15ae8092cc8a21023a27f2fec7f6411dccc938 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 25 Feb 2026 19:17:55 -0300 Subject: [PATCH 6/7] test: implement DeleteAccountModal for improved account deletion e2e test flow --- apps/meteor/tests/e2e/delete-account.spec.ts | 32 +++++------------ .../tests/e2e/page-objects/account-profile.ts | 32 +++++------------ .../fragments/modals/delete-account-modal.ts | 36 +++++++++++++++++++ .../page-objects/fragments/modals/index.ts | 1 + 4 files changed, 54 insertions(+), 47 deletions(-) create mode 100644 apps/meteor/tests/e2e/page-objects/fragments/modals/delete-account-modal.ts diff --git a/apps/meteor/tests/e2e/delete-account.spec.ts b/apps/meteor/tests/e2e/delete-account.spec.ts index a1ff584fa0d63..12c03ab494489 100644 --- a/apps/meteor/tests/e2e/delete-account.spec.ts +++ b/apps/meteor/tests/e2e/delete-account.spec.ts @@ -47,24 +47,17 @@ test.describe('Delete Own Account', () => { await page.goto('/account/profile'); await poAccountProfile.profileTitle.waitFor({ state: 'visible' }); await poAccountProfile.btnDeleteMyAccount.click(); - await expect(poAccountProfile.deleteAccountDialog).toBeVisible(); - }); - - await test.step('verify delete confirmation dialog appears', async () => { - await expect(poAccountProfile.deleteAccountDialogMessageWithPassword).toBeVisible(); - await expect(poAccountProfile.inputDeleteAccountPassword).toBeVisible(); - await expect(poAccountProfile.btnDeleteAccountConfirm).toBeVisible(); - await expect(poAccountProfile.btnDeleteAccountCancel).toBeVisible(); + await poAccountProfile.deleteAccountModal.waitForDisplay(); }); await test.step('enter invalid password in the confirmation field and click delete account', async () => { - await poAccountProfile.inputDeleteAccountPassword.fill('invalid-password'); - await expect(poAccountProfile.inputDeleteAccountPassword).toHaveValue('invalid-password'); - await poAccountProfile.btnDeleteAccountConfirm.click(); + await poAccountProfile.deleteAccountModal.inputPassword.fill('invalid-password'); + await expect(poAccountProfile.deleteAccountModal.inputPassword).toHaveValue('invalid-password'); + await poAccountProfile.deleteAccountModal.confirmDelete({ waitForDismissal: false }); }); await test.step('verify error message appears', async () => { - await poAccountProfile.toastMessage.waitForDisplay({ type: 'error', message: 'Invalid password [error-invalid-password]' }); + await expect(poAccountProfile.deleteAccountModal.inputErrorMessage).toBeVisible(); }); await test.step('verify user is still on the profile page', async () => { @@ -84,20 +77,13 @@ test.describe('Delete Own Account', () => { await page.goto('/account/profile'); await poAccountProfile.profileTitle.waitFor({ state: 'visible' }); await poAccountProfile.btnDeleteMyAccount.click(); - await expect(poAccountProfile.deleteAccountDialog).toBeVisible(); - }); - - await test.step('verify delete confirmation dialog appears', async () => { - await expect(poAccountProfile.deleteAccountDialogMessageWithPassword).toBeVisible(); - await expect(poAccountProfile.inputDeleteAccountPassword).toBeVisible(); - await expect(poAccountProfile.btnDeleteAccountConfirm).toBeVisible(); - await expect(poAccountProfile.btnDeleteAccountCancel).toBeVisible(); + await poAccountProfile.deleteAccountModal.waitForDisplay(); }); await test.step('enter password in the confirmation field and click delete account', async () => { - await poAccountProfile.inputDeleteAccountPassword.fill(DEFAULT_USER_CREDENTIALS.password); - await expect(poAccountProfile.inputDeleteAccountPassword).toHaveValue(DEFAULT_USER_CREDENTIALS.password); - await poAccountProfile.btnDeleteAccountConfirm.click(); + await poAccountProfile.deleteAccountModal.inputPassword.fill(DEFAULT_USER_CREDENTIALS.password); + await expect(poAccountProfile.deleteAccountModal.inputPassword).toHaveValue(DEFAULT_USER_CREDENTIALS.password); + await poAccountProfile.deleteAccountModal.confirmDelete(); }); await test.step('verify user is redirected to login page', async () => { diff --git a/apps/meteor/tests/e2e/page-objects/account-profile.ts b/apps/meteor/tests/e2e/page-objects/account-profile.ts index 84b391a292c60..9a672ec34d835 100644 --- a/apps/meteor/tests/e2e/page-objects/account-profile.ts +++ b/apps/meteor/tests/e2e/page-objects/account-profile.ts @@ -1,10 +1,14 @@ import type { Locator, Page } from '@playwright/test'; import { Account } from './account'; +import { DeleteAccountModal } from './fragments'; export class AccountProfile extends Account { + readonly deleteAccountModal: DeleteAccountModal; + constructor(page: Page) { super(page); + this.deleteAccountModal = new DeleteAccountModal(page); } get inputName(): Locator { @@ -108,31 +112,11 @@ export class AccountProfile extends Account { return this.page.getByRole('button', { name: 'Save changes', exact: true }); } - get btnDeleteMyAccount(): Locator { - return this.page.getByRole('button', { name: 'Delete my account' }); - } - - get deleteAccountDialog(): Locator { - return this.page.getByRole('dialog', { name: 'Delete account?' }); - } - - get deleteAccountDialogMessageWithPassword(): Locator { - return this.deleteAccountDialog.getByText('Enter your password to delete your account. This cannot be undone.'); - } - - get inputDeleteAccountPassword(): Locator { - return this.deleteAccountDialog.getByRole('textbox', { name: 'Enter your password to delete your account. This cannot be undone.' }); - } - - get btnDeleteAccountConfirm(): Locator { - return this.deleteAccountDialog.getByRole('button', { name: 'Delete Account' }); - } - - get btnDeleteAccountCancel(): Locator { - return this.deleteAccountDialog.getByRole('button', { name: 'Cancel' }); - } - get profileTitle(): Locator { return this.page.getByRole('heading', { name: 'Profile' }); } + + get btnDeleteMyAccount(): Locator { + return this.page.getByRole('button', { name: 'Delete my account' }); + } } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/modals/delete-account-modal.ts b/apps/meteor/tests/e2e/page-objects/fragments/modals/delete-account-modal.ts new file mode 100644 index 0000000000000..722bfbb507ab9 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/modals/delete-account-modal.ts @@ -0,0 +1,36 @@ +import type { Locator, Page } from 'playwright-core'; + +import { Modal } from './modal'; + +export class DeleteAccountModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Delete account?' })); + } + + get btnDeleteAccount(): Locator { + return this.root.getByRole('button', { name: 'Delete Account' }); + } + + get btnCancel(): Locator { + return this.root.getByRole('button', { name: 'Cancel' }); + } + + async confirmDelete({ waitForDismissal = true } = {}): Promise { + await this.btnDeleteAccount.click(); + if (waitForDismissal) { + await this.waitForDismissal(); + } + } + + get deleteAccountDialogMessageWithPassword(): Locator { + return this.root.getByText('Enter your password to delete your account. This cannot be undone.'); + } + + get inputPassword(): Locator { + return this.root.getByRole('textbox', { name: 'Enter your password to delete your account. This cannot be undone.' }); + } + + get inputErrorMessage(): Locator { + return this.root.locator('[role="alert"]', { hasText: 'Invalid password' }); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts b/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts index 22f3ee49046c4..1f52d90447f9a 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts @@ -2,6 +2,7 @@ export * from './apps-modal'; export * from './confirm-delete-modal'; export * from './confirm-logout-modal'; export * from './create-new-modal'; +export * from './delete-account-modal'; export * from './disable-room-encryption-modal'; export * from './edit-status-modal'; export * from './enable-room-encryption-modal'; From 63a5490ec3eaa81afdb556def2118fdcab2b0f2e Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 4 Mar 2026 15:33:16 -0300 Subject: [PATCH 7/7] fix: remove shouldFocus option from setError in ActionConfirmModal --- apps/meteor/client/views/account/profile/ActionConfirmModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx index e9d567498168c..39cf94affe0fb 100644 --- a/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx +++ b/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx @@ -30,7 +30,7 @@ const ActionConfirmModal = ({ isPassword, onConfirm, onCancel }: ActionConfirmMo await onConfirm(credential); } catch (error: any) { if (error.errorType === 'error-invalid-password') { - setError('credential', { message: t('Invalid_password') }, { shouldFocus: true }); + setError('credential', { message: t('Invalid_password') }); } } };