diff --git a/packages/extension-ui/src/Popup/Export.test.tsx b/packages/extension-ui/src/Popup/Export.test.tsx index b24ee1b3..857faf82 100644 --- a/packages/extension-ui/src/Popup/Export.test.tsx +++ b/packages/extension-ui/src/Popup/Export.test.tsx @@ -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); diff --git a/packages/extension-ui/src/Popup/Export.tsx b/packages/extension-ui/src/Popup/Export.tsx index a25407fa..1ecfb3e9 100644 --- a/packages/extension-ui/src/Popup/Export.tsx +++ b/packages/extension-ui/src/Popup/Export.tsx @@ -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 ('password for this account')} - onChange={setPass} + onChange={onPassChange} type='password' /> + {error && ( + + {error} + + )}