Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UPM-1260]Amina/fix: reset_password_modal_in_logged_in_state #16061

Merged
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
44 changes: 44 additions & 0 deletions packages/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2150,6 +2150,50 @@ type TPrivateSocketEndpoints = {
[k: string]: unknown;
};
};
reset_password: {
request: {
/**
* Must be `1`
*/
reset_password: 1;
/**
* New password. For validation (Accepts any printable ASCII character. Must be within 8-25 characters, and include numbers, lowercase and uppercase letters. Must not be the same as the user's email address).
*/
new_password: string;
/**
* Email verification code (received from a `verify_email` call, which must be done first)
*/
verification_code: string;
/**
* [Optional] Used to pass data through the websocket, which may be retrieved via the `echo_req` output field.
*/
passthrough?: {
[k: string]: unknown;
};
/**
* [Optional] Used to map request to response.
*/
req_id?: number;
};
response: {
reset_password?: 0 | 1;
/**
* Echo of the request made.
*/
echo_req: {
[k: string]: unknown;
};
/**
* Action name of the request made.
*/
msg_type: 'reset_password';
/**
* Optional field sent in request to map to response, present only when request contains `req_id`.
*/
req_id?: number;
[k: string]: unknown;
};
};
};

// TODO: remove these mock passkeys types after implementing them inside api-types
Expand Down
7 changes: 7 additions & 0 deletions packages/appstore/src/components/modals/modal-manager.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { useLocation } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
import { useWalletMigration } from '@deriv/hooks';
import { makeLazyLoader, moduleLoader } from '@deriv/shared';
Expand Down Expand Up @@ -289,6 +290,12 @@ const ModalManager = () => {
is_mt5_password_invalid_format_modal_visible ||
is_sent_email_modal_enabled;

const url_params = new URLSearchParams(useLocation().search);
const url_action_param = url_params.get('action');
if (url_action_param) {
return null;
}

return (
<React.Fragment>
{is_jurisdiction_modal_visible && <JurisdictionModal openPasswordModal={openRealPasswordModal} />}
Expand Down
115 changes: 58 additions & 57 deletions packages/core/src/App/Containers/Modals/app-modals.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,73 +177,74 @@ const AppModals = observer(() => {
}
break;
}
if (!url_action_param) {
if (
is_logged_in &&
amina-deriv marked this conversation as resolved.
Show resolved Hide resolved
active_account_landing_company === 'maltainvest' &&
!is_trading_assessment_for_new_user_enabled &&
is_trading_experience_incomplete &&
content_flag !== ContentFlag.LOW_RISK_CR_EU &&
content_flag !== ContentFlag.LOW_RISK_CR_NON_EU
) {
ComponentToLoad = <TradingAssessmentExistingUser />;
} else if (is_closing_create_real_account_modal) {
ComponentToLoad = <WarningCloseCreateRealAccountModal />;
} else if (is_account_needed_modal_on) {
ComponentToLoad = <MT5AccountNeededModal />;
} else if (should_show_cooldown_modal) {
ComponentToLoad = <CooldownWarningModal />;
} else if (should_show_assessment_complete_modal) {
ComponentToLoad = <CompletedAssessmentModal />;
} else if (is_deriv_account_needed_modal_visible) {
ComponentToLoad = <DerivRealAccountRequiredModal />;
} else if (should_show_risk_accept_modal) {
ComponentToLoad = <RiskAcceptTestWarningModal />;
} else if (isUrlUnavailableModalVisible) {
ComponentToLoad = <UrlUnavailableModal />;
}

if (
is_logged_in &&
active_account_landing_company === 'maltainvest' &&
!is_trading_assessment_for_new_user_enabled &&
is_trading_experience_incomplete &&
content_flag !== ContentFlag.LOW_RISK_CR_EU &&
content_flag !== ContentFlag.LOW_RISK_CR_NON_EU
) {
ComponentToLoad = <TradingAssessmentExistingUser />;
} else if (is_closing_create_real_account_modal) {
ComponentToLoad = <WarningCloseCreateRealAccountModal />;
} else if (is_account_needed_modal_on) {
ComponentToLoad = <MT5AccountNeededModal />;
} else if (should_show_cooldown_modal) {
ComponentToLoad = <CooldownWarningModal />;
} else if (should_show_assessment_complete_modal) {
ComponentToLoad = <CompletedAssessmentModal />;
} else if (is_deriv_account_needed_modal_visible) {
ComponentToLoad = <DerivRealAccountRequiredModal />;
} else if (should_show_risk_accept_modal) {
ComponentToLoad = <RiskAcceptTestWarningModal />;
} else if (isUrlUnavailableModalVisible) {
ComponentToLoad = <UrlUnavailableModal />;
}

if (has_wallet && should_show_wallets_upgrade_completed_modal) {
ComponentToLoad = <WalletsUpgradeCompletedModal />;
}
if (has_wallet && should_show_wallets_upgrade_completed_modal) {
ComponentToLoad = <WalletsUpgradeCompletedModal />;
}

if (!has_wallet && is_migrated && is_logged_in) {
ComponentToLoad = <WalletsUpgradeLogoutModal />;
}
if (!has_wallet && is_migrated && is_logged_in) {
ComponentToLoad = <WalletsUpgradeLogoutModal />;
}

if (should_show_passkeys_info_modal) {
ComponentToLoad = <EffortlessLoginModal />;
}
if (should_show_passkeys_info_modal) {
ComponentToLoad = <EffortlessLoginModal />;
}

if (is_ready_to_deposit_modal_visible) {
ComponentToLoad = <ReadyToDepositModal />;
}
if (is_ready_to_deposit_modal_visible) {
ComponentToLoad = <ReadyToDepositModal />;
}

if (is_need_real_account_for_cashier_modal_visible) {
ComponentToLoad = <NeedRealAccountForCashierModal />;
}
if (is_need_real_account_for_cashier_modal_visible) {
ComponentToLoad = <NeedRealAccountForCashierModal />;
}

if (is_verification_modal_visible) {
ComponentToLoad = <VerificationModal />;
}
if (is_verification_modal_visible) {
ComponentToLoad = <VerificationModal />;
}

if (is_verification_submitted) {
ComponentToLoad = <VerificationDocumentSubmitted />;
}
if (is_verification_submitted) {
ComponentToLoad = <VerificationDocumentSubmitted />;
}

if (should_show_one_time_deposit_modal) {
ComponentToLoad = <OneTimeDepositModal />;
}
if (should_show_one_time_deposit_modal) {
ComponentToLoad = <OneTimeDepositModal />;
}

if (should_show_account_success_modal) {
ComponentToLoad = <ReadyToVerifyModal />;
}
if (is_additional_kyc_info_modal_open) {
ComponentToLoad = <AdditionalKycInfoModal />;
}
if (should_show_account_success_modal) {
ComponentToLoad = <ReadyToVerifyModal />;
}
if (is_additional_kyc_info_modal_open) {
ComponentToLoad = <AdditionalKycInfoModal />;
}

if (is_kyc_information_submitted_modal_open) {
ComponentToLoad = <InformationSubmittedModal />;
if (is_kyc_information_submitted_modal_open) {
ComponentToLoad = <InformationSubmittedModal />;
}
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React from 'react';
import { render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { WS } from '@deriv/shared';
import ResetPasswordModal from '../reset-password-modal';
import userEvent from '@testing-library/user-event';
import { StoreProvider, mockStore } from '@deriv/stores';
import { APIProvider } from '@deriv/api';
import { TStores } from '@deriv/stores/types';

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
WS: {
resetPassword: jest.fn(() => Promise.resolve()),
},
useWS: () => undefined,
getErrorMessages: jest.fn(() => ({
password_warnings: jest.fn(() => 'common password .'),
password: jest.fn(() => 'Invalid password.'),
})),
redirectToLogin: jest.fn(),
}));

const mock = {
ui: {
is_reset_password_modal_visible: true,
is_loading: false,
},
client: {
verification_code: {
reset_password: 'abcde',
},
setVerificationCode: jest.fn(),
logout: jest.fn(() => Promise.resolve()),
},
};

describe('ResetPasswordModal', () => {
let store = mockStore({});
beforeEach(() => {
store = mockStore(mock);
});
afterEach(() => {
jest.clearAllMocks();
});

const renderComponent = (store: TStores) => {
render(
<StoreProvider store={store}>
<BrowserRouter>
<APIProvider>
<ResetPasswordModal />
</APIProvider>
</BrowserRouter>
</StoreProvider>
);
};

it('should not render the reset password modal if is_reset_password_modal_visible is false ', () => {
store = mockStore({
...mock,
ui: {
...mock.ui,
is_reset_password_modal_visible: false,
},
});
renderComponent(store);
expect(screen.queryByText('Reset your password')).not.toBeInTheDocument();
});

it('should render the reset password modal', () => {
renderComponent(store);
expect(screen.getByText('Reset your password')).toBeInTheDocument();
expect(
screen.getByText(
/strong passwords contain at least 8 characters\. combine uppercase and lowercase letters, numbers, and symbols\./i
)
).toBeInTheDocument();
});

it('should change input of password and trigger change password button', async () => {
WS.resetPassword.mockReturnValue(Promise.resolve({ reset_password: 1 }));

renderComponent(store);

await waitForElementToBeRemoved(() => screen.getByTestId('dt_initial_loader'));

const new_password = screen.getByLabelText('Create a password', { selector: 'input' });

userEvent.type(new_password, 'Tptte1743!@');

expect(new_password).toHaveValue('Tptte1743!@');
expect(screen.getByRole('button', { name: /Reset my password/i })).toBeEnabled();

userEvent.click(
screen.getByRole('button', {
name: /reset my password/i,
})
);
await waitFor(() => {
expect(WS.resetPassword).toHaveBeenCalledWith({
new_password: 'Tptte1743!@',
reset_password: 1,
verification_code: 'abcde',
});
});
expect(store.client.setVerificationCode).toHaveBeenCalledTimes(1);

await waitFor(() => {
expect(WS.resetPassword).toHaveBeenCalledWith({
new_password: 'Tptte1743!@',
reset_password: 1,
verification_code: 'abcde',
});
});

expect(store.client.logout).toHaveBeenCalledTimes(1);
expect(screen.getByText('Your password has been changed')).toBeInTheDocument();
});
});

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ResetPasswordModal from './reset-password-modal';

export default ResetPasswordModal;
Loading
Loading