Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/containers/Auth/Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export const Auth = ({
saveHandler(item);
}}
>
{({ submitForm, values }) => (
{({ submitForm, values, setValues }) => (
<div className={styles.CenterBox}>
<Form className={styles.Form}>
{formFields.map((field, index) => {
Expand Down Expand Up @@ -218,10 +218,16 @@ export const Auth = ({
component={Button}
variant="contained"
color="primary"
onClick={(token: string) => {
onClick={async (token: string) => {
if (token) {
setLoading(true);
saveHandler({ ...values, captcha: token });
// Set captcha value
await setValues({ ...values, captcha: token });

// Give React time to process the state update
await new Promise((resolve) => setTimeout(resolve, 0));

// Let Formik handle validation & submission
submitForm();
}
}}
className={buttonClass}
Expand Down
18 changes: 18 additions & 0 deletions src/containers/Auth/ResetPassword/ResetPasswordConfirmOTP.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
const saveButton = screen.getByText('Save');
await user.click(saveButton);

await waitFor(() => {

Check failure on line 54 in src/containers/Auth/ResetPassword/ResetPasswordConfirmOTP.test.tsx

View workflow job for this annotation

GitHub Actions / CI

src/containers/Auth/ResetPassword/ResetPasswordConfirmOTP.test.tsx > <ResetPasswordConfirmOTP /> > it should submit the form correctly

TestingLibraryElementError: Unable to find an element with the text: Login page. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. Ignored nodes: comments, script, style <body> <div> <div class="_Container_a83261 " data-testid="AuthContainer" > <div class="_Auth_a83261" > <div> <img alt="Glific" class="_GlificLogo_a83261" src="/src/assets/images/logo/Logo.svg" /> </div> <hr class="_Break_a83261" /> <div class="_OrganizationName_a83261" /> <div class="_Box_a83261 _SecondResetBox_a83261" > <div class="_BoxTitle_a83261 _LoginBoxTitle_a83261" > <h4 class="MuiTypography-root _TitleText_a83261 MuiTypography-h4 css-f84ov1-MuiTypography-root" > Reset your password </h4> </div> <div class="_SubText_a83261" /> <div class="_CenterBox_a83261" > <form action="#" class="_Form_a83261" > <div> <div class="_Spacing_a83261" /> <div class="_Input_73f6ae" data-testid="phoneInput" > <div class="MuiFormControl-root _Input_73f6ae css-1iw3t7y-MuiFormControl-root" > <div class=" react-tel-input " > <div class="special-label" > Phone </div> <input class="form-control _PhoneNumber_73f6ae" name="phoneNumber" placeholder="Phone number" required="" type="tel" value="+91" /> <div class="flag-dropdown " > <div aria-haspopup="listbox" class="selected-flag" role="button" tabindex="0" title="India: + 91" > <div class="flag in" > <div class="arrow" /> </div> </div> </div> </div> <p class="MuiFormHelperText-root _FormHelperText_73f6ae MuiFormHelperText-sizeMedium MuiFormHelperText-contained css-er619e-MuiFormHelperText-root" > Please enter a phone number. </p> <p class="MuiFormHelperText-root _ErrorText_73f6ae _FormHelperText_73f6ae MuiFormHelperText-sizeMedium MuiFormHelperText-contained css-er619e-MuiFormHelperText-root" > Input required </p> </div> </div> </div> <div> <div class="_Spacing_a83261" /> <div class="_Input_1c1d73" data-testid="input" > <div class="MuiFormControl-root MuiFormControl-fullWidth css-ytlejw-MuiFormControl-root" > <div class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputB
expect(screen.getByText('Login page')).toBeInTheDocument();
});
});
Expand All @@ -76,4 +76,22 @@
expect(sendOptMock).toHaveBeenCalledWith('919967665667');
});
});

test('it should show validation error if phone number is empty in state', async () => {
const WrapperEmpty = (
<MemoryRouter initialEntries={[{ state: { phoneNumber: '' } }]}>
<Routes>
<Route path="/" element={<ResetPasswordConfirmOTP />} />
</Routes>
</MemoryRouter>
);

render(WrapperEmpty);
const saveButton = screen.getByText('Save');
await user.click(saveButton);

await waitFor(() => {
expect(screen.getAllByText('Input required').length).toBeGreaterThan(0);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const ResetPasswordConfirmOTP = () => {
];

const FormSchema = Yup.object().shape({
phoneNumber: Yup.string().required(t('Input required')),
OTP: Yup.string().required(t('Input required')),
password: yupPasswordValidation(t),
});
Expand Down
38 changes: 37 additions & 1 deletion src/containers/MyAccount/MyAccount.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const mockedAxios = axios as any;
const user = userEvent.setup();

const wrapper = (
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mocks}>
<MemoryRouter>
<MyAccount />
</MemoryRouter>
Expand Down Expand Up @@ -198,4 +198,40 @@ describe('<MyAccount />', () => {
const saveButton = screen.getByText('Save');
await user.click(saveButton);
});

test('update profile (name and email) flow', async () => {
const { container } = render(wrapper);

await screen.findByTestId('MyAccount');

// change email
const emailInput = container.querySelector('input[name="email"]') as HTMLInputElement;
fireEvent.change(emailInput, { target: { value: '[email protected]' } });

// save button should appear
const saveButton = await screen.findByText('Save');
await user.click(saveButton);

await waitFor(() => {
expect(screen.getByText('Password updated successfully!')).toBeInTheDocument();
});
});

test('update profile error flow', async () => {
const { container } = render(wrapper);

await screen.findByTestId('MyAccount');

// change email to one that triggers an error
const emailInput = container.querySelector('input[name="email"]') as HTMLInputElement;
fireEvent.change(emailInput, { target: { value: '[email protected]' } });

// save button should appear
const saveButton = await screen.findByText('Save');
await user.click(saveButton);

await waitFor(() => {
expect(screen.getByText('Email already exists')).toBeInTheDocument();
});
});
});
64 changes: 47 additions & 17 deletions src/containers/MyAccount/MyAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,20 @@ export const MyAccount = () => {
// set the mutation to update the logged in user password
const [updateCurrentUser] = useMutation(UPDATE_CURRENT_USER, {
onCompleted: (data) => {
if (data.updateCurrentUser.errors) {
if (data.updateCurrentUser.errors[0].message === 'incorrect_code') {
if (data.updateCurrentUser.errors && data.updateCurrentUser.errors.length > 0) {
const error = data.updateCurrentUser.errors[0];
if (error.message === 'incorrect_code') {
setToastMessageInfo({ severity: 'error', message: t('Please enter a valid OTP') });
} else {
} else if (error.message === 'Too many attempts') {
setToastMessageInfo({
severity: 'error',
message: t('Too many attempts, please retry after sometime.'),
});
} else {
setToastMessageInfo({
severity: 'error',
message: t(error.message),
});
}
} else {
setShowOTPButton(true);
Expand Down Expand Up @@ -139,6 +145,11 @@ export const MyAccount = () => {
password: yupPasswordValidation(t),
});

const UserFormSchema = Yup.object().shape({
name: Yup.string().required(t('Name is required.')),
email: Yup.string().email(t('Email is invalid')).required(t('Email is required.')),
});

const userformFields = [
{
component: Input,
Expand All @@ -156,24 +167,43 @@ export const MyAccount = () => {
component: Input,
name: 'email',
label: t('Email'),
disabled: true,
disabled: false,
},
];

const userForm = (
<Formik initialValues={{ name: userName, phone: userPhone, email: userEmail }} onSubmit={() => { }}>
<Form>
{userformFields.map((field) => (
<div className={styles.UserField} key={field.name}>
{field.label && (
<Typography data-testid="formLabel" variant="h5" className={styles.FieldLabel}>
{field.label}
</Typography>
)}
<Field key={field.name} {...field}></Field>
</div>
))}
</Form>
<Formik
initialValues={{ name: userName, phone: userPhone, email: userEmail }}
enableReinitialize={true}
validationSchema={UserFormSchema}
onSubmit={(values) => {
setMessage(t('Password updated successfully!'));
updateCurrentUser({
variables: { input: { name: values.name, email: values.email } },
});
}}
>
{({ dirty, submitForm }) => (
<Form>
{userformFields.map((field) => (
<div className={styles.UserField} key={field.name}>
{field.label && (
<Typography data-testid="formLabel" variant="h5" className={styles.FieldLabel}>
{field.label}
</Typography>
)}
<Field key={field.name} {...field}></Field>
</div>
))}
{dirty && (
<div className={styles.Buttons}>
<Button variant="contained" color="primary" onClick={submitForm} className={styles.Button}>
{t('Save')}
</Button>
</div>
)}
</Form>
)}
</Formik>
);

Expand Down
2 changes: 2 additions & 0 deletions src/graphql/mutations/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export const UPDATE_CURRENT_USER = gql`
user {
id
name
phone
email
}
errors {
key
Expand Down
54 changes: 51 additions & 3 deletions src/mocks/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,45 @@ export const getCurrentUserQuery = {
result: {
data: {
currentUser: {
__typename: 'UserWrapper',
user: {
__typename: 'User',
id: '1',
name: 'John Doe',
phone: '+919820198765',
roles: ['admin'],
roles: ['Admin'],
email: '[email protected]',
contact: {
__typename: 'Contact',
id: '1',
name: 'Glific user',
phone: '9876543210',
},
accessRoles: [
{
__typename: 'Role',
id: '1',
label: 'Admin',
},
],
groups: [
{
__typename: 'Group',
id: '1',
label: 'Default Collection',
description: '',
},
],
organization: {
__typename: 'Organization',
id: '1',
contact: {
__typename: 'Contact',
phone: '917834811114',
},
},
language: {
__typename: 'Language',
id: '1',
locale: 'en',
},
Expand All @@ -58,6 +66,7 @@ export const getUsersQuery = {
data: {
users: [
{
__typename: 'User',
id: '1',
name: 'John Doe',
},
Expand All @@ -79,6 +88,7 @@ export const updateUserQuery = [
user: {
id: '2',
name: 'Updated Name',
phone: '+919820198765',
email: '[email protected]',
},
},
Expand All @@ -93,7 +103,7 @@ export const updateUserQuery = [
result: {
data: {
updateCurrentUser: {
errors: [{ message: 'incorrect_code' }],
errors: [{ key: 'otp', message: 'incorrect_code' }],
user: null,
},
},
Expand All @@ -107,7 +117,7 @@ export const updateUserQuery = [
result: {
data: {
updateCurrentUser: {
errors: [{ message: 'Too many attempts' }],
errors: [{ key: 'otp', message: 'Too many attempts' }],
user: null,
},
},
Expand All @@ -122,6 +132,44 @@ export const updateUserQuery = [
data: {
updateCurrentUser: {
errors: null,
user: {
id: '1',
name: 'John Doe',
phone: '+919820198765',
email: '[email protected]',
},
},
},
},
},
{
request: {
query: UPDATE_CURRENT_USER,
variables: { input: { name: 'John Doe', email: '[email protected]' } },
},
result: {
data: {
updateCurrentUser: {
errors: null,
user: {
id: '1',
name: 'John Doe',
phone: '+919820198765',
email: '[email protected]',
},
},
},
},
},
{
request: {
query: UPDATE_CURRENT_USER,
variables: { input: { name: 'John Doe', email: '[email protected]' } },
},
result: {
data: {
updateCurrentUser: {
errors: [{ key: 'email', message: 'Email already exists' }],
user: null,
},
},
Expand Down
Loading