Show error upon wrong password on Export screen (#594)
* add spinner to forget button * error and test on export with wrong password * reset error when typing and test
This commit is contained in:
parent
5af3be606e
commit
4d6242965a
@ -51,6 +51,39 @@ describe('Export component', () => {
|
||||
expect(wrapper.find(Button).prop('isDisabled')).toBe(true);
|
||||
});
|
||||
|
||||
it('shows an error if the password is wrong', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
jest.spyOn(messaging, 'exportAccount').mockImplementation(async () => {
|
||||
throw new Error('Unable to decode using the supplied passphrase');
|
||||
});
|
||||
enterPassword();
|
||||
wrapper.find('[data-export-button] button').simulate('click');
|
||||
await act(flushAllPromises);
|
||||
wrapper.update();
|
||||
|
||||
// the first message is "You are exporting your account. Keep it safe and don't share it with anyone."
|
||||
expect(wrapper.find('.warning-message').at(1).text()).toBe('Unable to decode using the supplied passphrase');
|
||||
expect(wrapper.find(Button).prop('isDisabled')).toBe(true);
|
||||
expect(wrapper.find('InputWithLabel').first().prop('isError')).toBe(true);
|
||||
});
|
||||
|
||||
it('shows no error when typing again after a wrong password', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
jest.spyOn(messaging, 'exportAccount').mockImplementation(async () => {
|
||||
throw new Error('Unable to decode using the supplied passphrase');
|
||||
});
|
||||
enterPassword();
|
||||
wrapper.find('[data-export-button] button').simulate('click');
|
||||
await act(flushAllPromises);
|
||||
wrapper.update();
|
||||
enterPassword();
|
||||
|
||||
// the first message is "You are exporting your account. Keep it safe and don't share it with anyone."
|
||||
expect(wrapper.find('.warning-message')).toHaveLength(1);
|
||||
expect(wrapper.find(Button).prop('isDisabled')).toBe(false);
|
||||
expect(wrapper.find('InputWithLabel').first().prop('isError')).toBe(false);
|
||||
});
|
||||
|
||||
it('button is enabled after password is typed', async () => {
|
||||
enterPassword();
|
||||
await act(flushAllPromises);
|
||||
|
||||
@ -23,13 +23,20 @@ function Export ({ className, match: { params: { address } } }: Props): React.Re
|
||||
const onAction = useContext(ActionContext);
|
||||
const [isBusy, setIsBusy] = useState(false);
|
||||
const [pass, setPass] = useState('');
|
||||
const [wrongPasswordHighlight, setWrongPasswordHighlight] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const _goHome = useCallback(
|
||||
() => onAction('/'),
|
||||
[onAction]
|
||||
);
|
||||
|
||||
const onPassChange = useCallback(
|
||||
(password: string) => {
|
||||
setPass(password);
|
||||
setError('');
|
||||
}
|
||||
, []);
|
||||
|
||||
const _onExportButtonClick = useCallback(
|
||||
(): void => {
|
||||
setIsBusy(true);
|
||||
@ -47,10 +54,8 @@ function Export ({ className, match: { params: { address } } }: Props): React.Re
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
console.error(error);
|
||||
|
||||
setError(error.message);
|
||||
setIsBusy(false);
|
||||
setWrongPasswordHighlight(true);
|
||||
setTimeout(() => setWrongPasswordHighlight(false), 100);
|
||||
});
|
||||
},
|
||||
[address, onAction, pass]
|
||||
@ -71,17 +76,25 @@ function Export ({ className, match: { params: { address } } }: Props): React.Re
|
||||
<InputWithLabel
|
||||
data-export-password
|
||||
disabled={isBusy}
|
||||
isError={pass.length < MIN_LENGTH || wrongPasswordHighlight}
|
||||
isError={pass.length < MIN_LENGTH || !!error}
|
||||
label={t<string>('password for this account')}
|
||||
onChange={setPass}
|
||||
onChange={onPassChange}
|
||||
type='password'
|
||||
/>
|
||||
{error && (
|
||||
<Warning
|
||||
isBelowInput
|
||||
isDanger
|
||||
>
|
||||
{error}
|
||||
</Warning>
|
||||
)}
|
||||
<Button
|
||||
className='export-button'
|
||||
data-export-button
|
||||
isBusy={isBusy}
|
||||
isDanger
|
||||
isDisabled={pass.length === 0}
|
||||
isDisabled={pass.length === 0 || !!error}
|
||||
onClick={_onExportButtonClick}
|
||||
>
|
||||
{t<string>('I want to export this account')}
|
||||
@ -109,6 +122,10 @@ export default withRouter(styled(Export)`
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.export-button {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.movedWarning {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
import type { ThemeProps } from '../types';
|
||||
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
import React, { useCallback, useContext, useState } from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@ -19,6 +19,7 @@ interface Props extends RouteComponentProps<{ address: string }>, ThemeProps {
|
||||
function Forget ({ className, match: { params: { address } } }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const onAction = useContext(ActionContext);
|
||||
const [isBusy, setIsBusy] = useState(false);
|
||||
|
||||
const _goHome = useCallback(
|
||||
() => onAction('/'),
|
||||
@ -26,10 +27,18 @@ function Forget ({ className, match: { params: { address } } }: Props): React.Re
|
||||
);
|
||||
|
||||
const _onClick = useCallback(
|
||||
(): Promise<void> =>
|
||||
(): void => {
|
||||
setIsBusy(true);
|
||||
forgetAccount(address)
|
||||
.then(() => onAction('/'))
|
||||
.catch((error: Error) => console.error(error)),
|
||||
.then(() => {
|
||||
setIsBusy(false);
|
||||
onAction('/');
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
setIsBusy(false);
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
[address, onAction]
|
||||
);
|
||||
|
||||
@ -46,6 +55,7 @@ function Forget ({ className, match: { params: { address } } }: Props): React.Re
|
||||
</Warning>
|
||||
<div className='actionArea'>
|
||||
<Button
|
||||
isBusy={isBusy}
|
||||
isDanger
|
||||
onClick={_onClick}
|
||||
>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user