From e6b608ff8095d05020eaf2b5574652885600f8a3 Mon Sep 17 00:00:00 2001 From: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> Date: Mon, 23 Nov 2020 21:40:00 -1000 Subject: [PATCH] Show error on wrong parent password when deriving (#527) * show error on wrong parent password * add tests * fix test * group button and error tests * Show error upon wrong derivation suri (#528) * show error when wrong suri and fix tests * alpha ordering and stray log Co-authored-by: Github Actions Co-authored-by: Github Actions --- .../src/Popup/Derive/Derive.test.tsx | 74 +++++++++++++++++-- .../src/Popup/Derive/SelectParent.tsx | 31 ++++++-- 2 files changed, 89 insertions(+), 16 deletions(-) diff --git a/packages/extension-ui/src/Popup/Derive/Derive.test.tsx b/packages/extension-ui/src/Popup/Derive/Derive.test.tsx index 53ee4f24..4f00f7ed 100644 --- a/packages/extension-ui/src/Popup/Derive/Derive.test.tsx +++ b/packages/extension-ui/src/Popup/Derive/Derive.test.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import '../../../../../__mocks__/chrome'; +import { ResponseDeriveValidate } from '@polkadot/extension-base/background/types'; import React from 'react'; import { MemoryRouter, Route } from 'react-router'; @@ -79,6 +80,14 @@ describe('Derive', () => { // eslint-disable-next-line @typescript-eslint/require-await jest.spyOn(messaging, 'validateAccount').mockImplementation(async (_, pass: string) => pass === 'pass'); + // eslint-disable-next-line @typescript-eslint/require-await + jest.spyOn(messaging, 'validateDerivationPath').mockImplementation(async (_, path) => { + if (path === '//') { + throw new Error('wrong suri'); + } + + return {} as ResponseDeriveValidate; + }); it('"Derive" checkbox is selected by default', () => { const checkbox = wrapper.find('input[type="checkbox"]'); @@ -105,27 +114,76 @@ describe('Derive', () => { expect(wrapper.exists('[data-button-action="create root account"]')).toBe(false); }); - it('"Create derived account" is disabled when password is incorrect', () => { + it('No error is visible when first loading the page', () => { + expect(wrapper.find('.error')).toHaveLength(0); + }); + + it('"Create derived account" is disabled when password is not set', () => { const button = wrapper.find('[data-button-action="create derived account"] button'); expect(button.prop('disabled')).toBe(true); }); - it('"Create derived account" is enabled when password is correct', async () => { - await type(wrapper.find('input[type="password"]'), 'pass'); + it('An error is visible and "Create derived account" is disabled when password is incorrect', async () => { + await type(wrapper.find('input[type="password"]'), 'wrong_pass'); + wrapper.find('[data-button-action="create derived account"] button').simulate('click'); + await act(flushAllPromises); + wrapper.update(); const button = wrapper.find('[data-button-action="create derived account"] button'); - expect(button.prop('disabled')).not.toBe(true); + expect(button.prop('disabled')).toBe(true); + expect(wrapper.find('.error')).toHaveLength(1); }); - it('"Create derived account" is disabled when suri is incorrect', async () => { - await type(wrapper.find('input[type="password"]'), 'pass'); - await type(wrapper.find('[data-input-suri] input'), '//'); + it('The error disappears when typing a new password and "Create derived account" is enabled', async () => { + await type(wrapper.find('input[type="password"]'), 'wrong_pass'); + wrapper.find('[data-button-action="create derived account"] button').simulate('click'); + await act(flushAllPromises); + wrapper.update(); + + await type(wrapper.find('input[type="password"]'), 'new_attempt'); const button = wrapper.find('[data-button-action="create derived account"] button'); - expect(button.prop('disabled')).not.toBe(true); + expect(button.prop('disabled')).toBe(false); + expect(wrapper.find('.error')).toHaveLength(0); + }); + + it('"Create derived account" is enabled when password is set', async () => { + await type(wrapper.find('input[type="password"]'), 'pass'); + + const button = wrapper.find('[data-button-action="create derived account"] button'); + + expect(button.prop('disabled')).toBe(false); + expect(wrapper.find('.error')).toHaveLength(0); + }); + + it('An error is visible and "Create derived account" is disabled when suri is incorrect', async () => { + await type(wrapper.find('input[type="password"]'), 'pass'); + await type(wrapper.find('[data-input-suri] input'), '//'); + wrapper.find('[data-button-action="create derived account"] button').simulate('click'); + await act(flushAllPromises); + wrapper.update(); + + const button = wrapper.find('[data-button-action="create derived account"] button'); + + expect(button.prop('disabled')).toBe(true); + expect(wrapper.find('.error')).toHaveLength(1); + }); + + it('The error disappears and "Create derived account" is enabled when typing a new suri', async () => { + await type(wrapper.find('input[type="password"]'), 'pass'); + await type(wrapper.find('[data-input-suri] input'), '//'); + wrapper.find('[data-button-action="create derived account"] button').simulate('click'); + await act(flushAllPromises); + wrapper.update(); + await type(wrapper.find('[data-input-suri] input'), 'new'); + + const button = wrapper.find('[data-button-action="create derived account"] button'); + + expect(button.prop('disabled')).toBe(false); + expect(wrapper.find('.error')).toHaveLength(0); }); it('takes selected address from URL as parent account', () => { diff --git a/packages/extension-ui/src/Popup/Derive/SelectParent.tsx b/packages/extension-ui/src/Popup/Derive/SelectParent.tsx index c4d5c841..831099b7 100644 --- a/packages/extension-ui/src/Popup/Derive/SelectParent.tsx +++ b/packages/extension-ui/src/Popup/Derive/SelectParent.tsx @@ -73,9 +73,11 @@ function SelectParent ({ className, isLocked, onDerivationConfirmed, parentAddre assert(account, 'Unable to derive'); onDerivationConfirmed({ account, parentPassword }); } catch (error) { + setIsBusy(false); setSuriPath(null); } } else { + setIsBusy(false); setIsProperParentPassword(false); } } @@ -130,14 +132,19 @@ function SelectParent ({ className, isLocked, onDerivationConfirmed, parentAddre type='password' value={parentPassword} /> + {!!parentPassword && !isProperParentPassword &&
{t('Wrong password')}
} {isProperParentPassword && ( - + <> + + {!suriPath &&
{t('Incorrect derivation path')}
} + )} @@ -168,7 +175,7 @@ function SelectParent ({ className, isLocked, onDerivationConfirmed, parentAddre ); } -export default styled(SelectParent)` +export default styled(SelectParent)(({ theme }: ThemeProps) => ` .smallerMargin { margin-top: 0; @@ -183,4 +190,12 @@ export default styled(SelectParent)` pointer-events: none; } } -`; + + .error { + display: block; + margin-top: -10px; + font-size: ${theme.labelFontSize}; + line-height: ${theme.labelLineHeight}; + color: ${theme.errorColor}; + } +`);