Repository: polkadot-js/extension
Pull request #426 (2020-09-03 19:09:39)

Display accounts first-and-foremost on all creations
Part of https://github.com/polkadot-js/extension/issues/414


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 45822b01..42b78660 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ Changes:
 - Derived accounts uses the parent genesisHash by default (attaches to same chain)
 - Make import from seed, QR & JSON options available on first-start
 - Adjust popup width, allowing full display of e.g. addresses
+- Always display network selection on all accounts
 - Handling signing rejections (any order) transparently
 - Small overall UI and use adjustments
 - Latest upstream polkadot-js dependencies
diff --git a/packages/extension-base/src/background/handlers/State.ts b/packages/extension-base/src/background/handlers/State.ts
index 7503fe4a..7332c503 100644
--- a/packages/extension-base/src/background/handlers/State.ts
+++ b/packages/extension-base/src/background/handlers/State.ts
@@ -65,7 +65,7 @@ const WINDOW_OPTS = {
   top: 150,
   type: 'popup',
   url: chrome.extension.getURL('index.html'),
-  width: 480
+  width: 560
 };
 
 function getId (): string {
diff --git a/packages/extension-ui/src/Popup/Authorize/Request.tsx b/packages/extension-ui/src/Popup/Authorize/Request.tsx
index 5e0c29a8..0f6f6b54 100644
--- a/packages/extension-ui/src/Popup/Authorize/Request.tsx
+++ b/packages/extension-ui/src/Popup/Authorize/Request.tsx
@@ -5,7 +5,7 @@
 import { RequestAuthorizeTab } from '@polkadot/extension-base/background/types';
 import { ThemeProps } from '../../types';
 
-import React, { useContext } from 'react';
+import React, { useCallback, useContext } from 'react';
 import styled from 'styled-components';
 
 import { ActionBar, ActionContext, Button, Icon, Link, Warning } from '../../components';
@@ -21,14 +21,20 @@ interface Props {
 
 function Request ({ authId, className, isFirst, request: { origin }, url }: Props): React.ReactElement<Props> {
   const onAction = useContext(ActionContext);
-  const _onApprove = (): Promise<void> =>
-    approveAuthRequest(authId)
+
+  const _onApprove = useCallback(
+    () => approveAuthRequest(authId)
       .then(() => onAction())
-      .catch((error: Error) => console.error(error));
-  const _onReject = (): Promise<void> =>
-    rejectAuthRequest(authId)
+      .catch((error: Error) => console.error(error)),
+    [authId, onAction]
+  );
+
+  const _onReject = useCallback(
+    () => rejectAuthRequest(authId)
       .then(() => onAction())
-      .catch((error: Error) => console.error(error));
+      .catch((error: Error) => console.error(error)),
+    [authId, onAction]
+  );
 
   return (
     <div className={className}>
diff --git a/packages/extension-ui/src/Popup/CreateAccount/AccountName.tsx b/packages/extension-ui/src/Popup/CreateAccount/AccountName.tsx
index d10bbebc..d88d1e37 100644
--- a/packages/extension-ui/src/Popup/CreateAccount/AccountName.tsx
+++ b/packages/extension-ui/src/Popup/CreateAccount/AccountName.tsx
@@ -4,7 +4,7 @@
 
 import React, { useCallback, useState } from 'react';
 
-import { Address, BackButton, ButtonArea, NextStepButton, VerticalSpace } from '../../components';
+import { BackButton, ButtonArea, NextStepButton, VerticalSpace } from '../../components';
 import { Name, Password } from '../../partials';
 
 interface Props {
@@ -14,7 +14,7 @@ interface Props {
   onCreate: (name: string, password: string) => void | Promise<void | boolean>;
 }
 
-function AccountName ({ address, isBusy, onBackClick, onCreate }: Props): React.ReactElement<Props> {
+function AccountName ({ isBusy, onBackClick, onCreate }: Props): React.ReactElement<Props> {
   const [name, setName] = useState<string | null>(null);
   const [password, setPassword] = useState<string | null>(null);
 
@@ -29,13 +29,7 @@ function AccountName ({ address, isBusy, onBackClick, onCreate }: Props): React.
         isFocused
         onChange={setName}
       />
-      {name && <Password onChange={setPassword} />}
-      {name && password && (
-        <Address
-          address={address}
-          name={name}
-        />
-      )}
+      <Password onChange={setPassword} />
       <VerticalSpace />
       <ButtonArea>
         <BackButton onClick={onBackClick} />
@@ -52,4 +46,4 @@ function AccountName ({ address, isBusy, onBackClick, onCreate }: Props): React.
   );
 }
 
-export default AccountName;
+export default React.memo(AccountName);
diff --git a/packages/extension-ui/src/Popup/CreateAccount/Mnemonic.tsx b/packages/extension-ui/src/Popup/CreateAccount/Mnemonic.tsx
index 1d6e811a..eb834882 100644
--- a/packages/extension-ui/src/Popup/CreateAccount/Mnemonic.tsx
+++ b/packages/extension-ui/src/Popup/CreateAccount/Mnemonic.tsx
@@ -33,12 +33,11 @@ function Mnemonic ({ onNextStep, seed }: Props): React.ReactElement<Props> {
 
   return (
     <>
-      <Warning>Please write down your wallet’s mnemonic seed and keep it in a safe place. <br />
-      Mnemonic seed is used to restore your wallet. Keep it carefully in case you lose your assets.</Warning>
       <MnemonicSeed
         onCopy={_onCopy}
         seed={seed}
       />
+      <Warning>Please write down your wallet’s mnemonic seed and keep it in a safe place. The mnemonic can be used to restore your wallet. Keep it carefully to not lose your assets.</Warning>
       <VerticalSpace />
       <Checkbox
         checked={isMnemonicSaved}
@@ -57,4 +56,4 @@ function Mnemonic ({ onNextStep, seed }: Props): React.ReactElement<Props> {
   );
 }
 
-export default Mnemonic;
+export default React.memo(Mnemonic);
diff --git a/packages/extension-ui/src/Popup/CreateAccount/index.tsx b/packages/extension-ui/src/Popup/CreateAccount/index.tsx
index cfa82148..ff455708 100644
--- a/packages/extension-ui/src/Popup/CreateAccount/index.tsx
+++ b/packages/extension-ui/src/Popup/CreateAccount/index.tsx
@@ -3,7 +3,7 @@
 // of the Apache-2.0 license. See the LICENSE file for details.
 
 import React, { useCallback, useContext, useEffect, useState } from 'react';
-import { ActionContext, Loading } from '../../components';
+import { ActionContext, Address, Loading } from '../../components';
 import { createAccountSuri, createSeed } from '../../messaging';
 import { HeaderWithSteps } from '../../partials';
 import AccountName from './AccountName';
@@ -27,6 +27,7 @@ export default function CreateAccount (): React.ReactElement {
       // this should always be the case
       if (name && password && account) {
         setIsBusy(true);
+
         createAccountSuri(name, password, account.seed)
           .then(() => onAction('/'))
           .catch((error: Error): void => {
@@ -47,23 +48,31 @@ export default function CreateAccount (): React.ReactElement {
         step={step}
         text='Create an account:&nbsp;'
       />
-      <Loading>{account && (
-        step === 1
-          ? (
-            <Mnemonic
-              onNextStep={_onNextStep}
-              seed={account.seed}
-            />
-          )
-          : (
-            <AccountName
-              address={account.address}
-              isBusy={isBusy}
-              onBackClick={_onPreviousStep}
-              onCreate={_onCreate}
-            />
-          )
-      )}</Loading>
+      <Loading>
+        <div>
+          <Address
+            address={account?.address}
+            name={name}
+          />
+        </div>
+        {account && (
+          step === 1
+            ? (
+              <Mnemonic
+                onNextStep={_onNextStep}
+                seed={account.seed}
+              />
+            )
+            : (
+              <AccountName
+                address={account.address}
+                isBusy={isBusy}
+                onBackClick={_onPreviousStep}
+                onCreate={_onCreate}
+              />
+            )
+        )}
+      </Loading>
     </>
   );
 }
diff --git a/packages/extension-ui/src/Popup/Derive/AddressDropdown.tsx b/packages/extension-ui/src/Popup/Derive/AddressDropdown.tsx
index 67fd805b..31d5527a 100644
--- a/packages/extension-ui/src/Popup/Derive/AddressDropdown.tsx
+++ b/packages/extension-ui/src/Popup/Derive/AddressDropdown.tsx
@@ -12,13 +12,14 @@ import { Address, Svg } from '../../components';
 import useOutsideClick from '../../hooks/useOutsideClick';
 
 interface Props {
-  allAddresses: string[];
+  allAddresses: [string, string | null][];
   className?: string;
   onSelect: (address: string) => void;
   selectedAddress: string;
+  selectedGenesis: string | null;
 }
 
-function AddressDropdown ({ allAddresses, className, onSelect, selectedAddress }: Props): React.ReactElement<Props> {
+function AddressDropdown ({ allAddresses, className, onSelect, selectedAddress, selectedGenesis }: Props): React.ReactElement<Props> {
   const [isDropdownVisible, setDropdownVisible] = useState(false);
   const ref = useRef<HTMLDivElement>(null);
 
@@ -34,16 +35,22 @@ function AddressDropdown ({ allAddresses, className, onSelect, selectedAddress }
         onClick={_toggleDropdown}
         ref={ref}
       >
-        <Address address={selectedAddress} />
+        <Address
+          address={selectedAddress}
+          genesisHash={selectedGenesis}
+        />
       </div>
       <HiddenOptions visible={isDropdownVisible}>
-        {allAddresses.map((address) => (
+        {allAddresses.map(([address, genesisHash]) => (
           <div
             data-parent-option
             key={address}
             onClick={_selectParent(address)}
           >
-            <Address address={address} />
+            <Address
+              address={address}
+              genesisHash={genesisHash}
+            />
           </div>
         ))}
       </HiddenOptions>
@@ -54,7 +61,7 @@ function AddressDropdown ({ allAddresses, className, onSelect, selectedAddress }
 const HiddenOptions = styled.div<{ visible: boolean }>`
   position: absolute;
   visibility: ${({ visible }): string => (visible ? 'visible' : 'hidden')};
-  width: 430px;
+  width: 510px;
   z-index: 100;
   background: ${({ theme }: ThemeProps): string => theme.bodyColor};
   max-height: ${({ visible }): string => (visible ? '200px' : '0')};
@@ -77,7 +84,7 @@ export default styled(AddressDropdown)(({ theme }: ThemeProps) => `
   & > div:first-child > ${Address}::after {
     content: '';
     position: absolute;
-    top: 50%;
+    top: 66%;
     transform: translateY(-50%);
     right: 11px;
     width: 30px;
diff --git a/packages/extension-ui/src/Popup/Derive/SelectParent.tsx b/packages/extension-ui/src/Popup/Derive/SelectParent.tsx
index 7044193a..f8fefe4b 100644
--- a/packages/extension-ui/src/Popup/Derive/SelectParent.tsx
+++ b/packages/extension-ui/src/Popup/Derive/SelectParent.tsx
@@ -2,7 +2,7 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
+import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
 import styled from 'styled-components';
 import { assert } from '@polkadot/util';
 
@@ -15,10 +15,11 @@ import DerivationPath from './DerivationPath';
 interface Props {
   isLocked?: boolean;
   parentAddress: string;
+  parentGenesis: string | null;
   onDerivationConfirmed: (derivation: { account: { address: string; suri: string }; parentPassword: string }) => void;
 }
 
-export function SelectParent ({ isLocked, onDerivationConfirmed, parentAddress }: Props): React.ReactElement<Props> {
+export function SelectParent ({ isLocked, onDerivationConfirmed, parentAddress, parentGenesis }: Props): React.ReactElement<Props> {
   const onAction = useContext(ActionContext);
   const [isBusy, setIsBusy] = useState(false);
   const { accounts, hierarchy } = useContext(AccountContext);
@@ -30,6 +31,13 @@ export function SelectParent ({ isLocked, onDerivationConfirmed, parentAddress }
 
   const passwordInputRef = useRef<HTMLDivElement>(null);
 
+  const allAddresses = useMemo(
+    () => hierarchy
+      .filter(({ isExternal }) => !isExternal)
+      .map(({ address, genesisHash }): [string, string | null] => [address, genesisHash || null]),
+    [hierarchy]
+  );
+
   const _goCreate = useCallback(
     () => onAction('/account/create'),
     [onAction]
@@ -91,13 +99,19 @@ export function SelectParent ({ isLocked, onDerivationConfirmed, parentAddress }
       )}
       <DisableableArea isDisabled={!shouldAccountBeDerived}>
         {isLocked
-          ? <Address address={parentAddress} />
+          ? (
+            <Address
+              address={parentAddress}
+              genesisHash={parentGenesis}
+            />
+          )
           : (
             <Label label='Choose Parent Account:'>
               <AddressDropdown
-                allAddresses={hierarchy.filter(({ isExternal }) => !isExternal).map(({ address }) => address)}
+                allAddresses={allAddresses}
                 onSelect={_onParentChange}
                 selectedAddress={parentAddress}
+                selectedGenesis={parentGenesis}
               />
             </Label>
           )
diff --git a/packages/extension-ui/src/Popup/Derive/index.tsx b/packages/extension-ui/src/Popup/Derive/index.tsx
index c08e08ce..2ca35351 100644
--- a/packages/extension-ui/src/Popup/Derive/index.tsx
+++ b/packages/extension-ui/src/Popup/Derive/index.tsx
@@ -2,7 +2,7 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import React, { useCallback, useContext, useState } from 'react';
+import React, { useCallback, useContext, useMemo, useState } from 'react';
 import { useParams } from 'react-router';
 
 import { AccountContext, ActionContext, Address, BackButton, ButtonArea, NextStepButton, VerticalSpace } from '../../components';
@@ -37,22 +37,24 @@ function Derive ({ isLocked }: Props): React.ReactElement<Props> {
   const [password, setPassword] = useState<string | null>(null);
   const [parentPassword, setParentPassword] = useState<string | null>(null);
 
+  const parentGenesis = useMemo(
+    () => accounts.find((a) => a.address === parentAddress)?.genesisHash || null,
+    [accounts, parentAddress]
+  );
+
   const _onCreate = useCallback(() => {
     if (!account || !name || !password || !parentPassword) {
       return;
     }
 
-    const parentAccount = accounts.find((a) => a.address === parentAddress);
-    const genesisHash = parentAccount?.genesisHash || null;
-
     setIsBusy(true);
-    deriveAccount(parentAddress, account.suri, parentPassword, name, password, genesisHash)
+    deriveAccount(parentAddress, account.suri, parentPassword, name, password, parentGenesis)
       .then(() => onAction('/'))
       .catch((error): void => {
         setIsBusy(false);
         console.error(error);
       });
-  }, [account, accounts, name, password, onAction, parentAddress, parentPassword]);
+  }, [account, name, password, onAction, parentAddress, parentGenesis, parentPassword]);
 
   const _onDerivationConfirmed = useCallback(({ account, parentPassword }: ConfirmState) => {
     setAccount(account);
@@ -74,23 +76,23 @@ function Derive ({ isLocked }: Props): React.ReactElement<Props> {
           isLocked={isLocked}
           onDerivationConfirmed={_onDerivationConfirmed}
           parentAddress={parentAddress}
-        />
-      )}
-      {account && (
-        <Name
-          isFocused
-          onChange={setName}
-        />
-      )}
-      {account && name && <Password onChange={setPassword}/>}
-      {account && name && password && (
-        <Address
-          address={account.address}
-          name={name}
+          parentGenesis={parentGenesis}
         />
       )}
       {account && (
         <>
+          <div>
+            <Address
+              address={account.address}
+              genesisHash={parentGenesis}
+              name={name}
+            />
+          </div>
+          <Name
+            isFocused
+            onChange={setName}
+          />
+          <Password onChange={setPassword} />
           <VerticalSpace/>
           <ButtonArea>
             <BackButton onClick={_onBackClick}/>
@@ -108,4 +110,4 @@ function Derive ({ isLocked }: Props): React.ReactElement<Props> {
   );
 }
 
-export default Derive;
+export default React.memo(Derive);
diff --git a/packages/extension-ui/src/Popup/ImportQr.tsx b/packages/extension-ui/src/Popup/ImportQr.tsx
index 40dee916..fb39a1da 100644
--- a/packages/extension-ui/src/Popup/ImportQr.tsx
+++ b/packages/extension-ui/src/Popup/ImportQr.tsx
@@ -36,14 +36,16 @@ export default function ImportQr (): React.ReactElement {
       )}
       {account && (
         <>
+          <div>
+            <Address
+              {...account}
+              name={name}
+            />
+          </div>
           <Name
             isFocused
             onChange={setName}
           />
-          <Address
-            {...account}
-            name={name}
-          />
           <VerticalSpace />
           {name && (
             <ButtonArea>
diff --git a/packages/extension-ui/src/Popup/ImportSeed.tsx b/packages/extension-ui/src/Popup/ImportSeed.tsx
index e5941d4c..c10255f4 100644
--- a/packages/extension-ui/src/Popup/ImportSeed.tsx
+++ b/packages/extension-ui/src/Popup/ImportSeed.tsx
@@ -40,10 +40,14 @@ export default function Import (): React.ReactElement {
   const _onChangeSeed = useCallback(
     async (suri: string | null): Promise<void> => {
       if (suri) {
-        setAccount(await validateSeed(suri));
-      } else {
-        setAccount(null);
+        try {
+          return setAccount(await validateSeed(suri));
+        } catch (error) {
+          console.error(error);
+        }
       }
+
+      setAccount(null);
     },
     []
   );
@@ -69,6 +73,12 @@ export default function Import (): React.ReactElement {
         showBackArrow
         text='Import account'
       />
+      <div>
+        <Address
+          address={account?.address}
+          name={name}
+        />
+      </div>
       <ValidatedInput
         // eslint-disable-next-line @typescript-eslint/no-use-before-define
         component={SeedInput}
@@ -78,14 +88,14 @@ export default function Import (): React.ReactElement {
         rowsCount={2}
         validator={isSeedValid}
       />
-      {account && <Name onChange={setName} />}
-      {account && name && <Password onChange={setPassword} />}
+      {account && (
+        <>
+          <Name onChange={setName} />
+          <Password onChange={setPassword} />
+        </>
+      )}
       {account && name && password && (
         <>
-          <Address
-            address={account.address}
-            name={name}
-          />
           <VerticalSpace />
           <ButtonArea>
             <NextStepButton
diff --git a/packages/extension-ui/src/Popup/RestoreJson.tsx b/packages/extension-ui/src/Popup/RestoreJson.tsx
index dd07e763..7acb8a50 100644
--- a/packages/extension-ui/src/Popup/RestoreJson.tsx
+++ b/packages/extension-ui/src/Popup/RestoreJson.tsx
@@ -96,10 +96,13 @@ export default function Upload (): React.ReactElement {
         text='Restore from JSON'
       />
       <div>
-        <Address
-          address={(isFileValid && address) || null}
-          name={(isFileValid && json?.meta.name as string) || null}
-        />
+        <div>
+          <Address
+            address={(isFileValid && address) || null}
+            genesisHash={(isFileValid && json?.meta.genesisHash as string) || null}
+            name={(isFileValid && json?.meta.name as string) || null}
+          />
+        </div>
         <InputFileWithLabel
           accept={acceptedFormats}
           isError={!isFileValid}
diff --git a/packages/extension-ui/src/Popup/Signing/Request.tsx b/packages/extension-ui/src/Popup/Signing/Request.tsx
index 589eecd6..96acb288 100644
--- a/packages/extension-ui/src/Popup/Signing/Request.tsx
+++ b/packages/extension-ui/src/Popup/Signing/Request.tsx
@@ -48,6 +48,7 @@ export default function Request ({ account: { isExternal }, buttonText, isFirst,
 
   useEffect((): void => {
     setIsLocked(null);
+
     !isExternal && isSignLocked(signId)
       .then((isLocked) => setIsLocked(isLocked))
       .catch((error: Error) => console.error(error));
diff --git a/packages/extension-ui/src/components/MnemonicSeed.tsx b/packages/extension-ui/src/components/MnemonicSeed.tsx
index 6d11da83..a28a79f1 100644
--- a/packages/extension-ui/src/components/MnemonicSeed.tsx
+++ b/packages/extension-ui/src/components/MnemonicSeed.tsx
@@ -40,7 +40,7 @@ function MnemonicSeed ({ className, onCopy, seed }: Props): React.ReactElement<P
 }
 
 export default styled(MnemonicSeed)(({ theme }: ThemeProps) => `
-  margin-top: 21px;
+  margin-bottom: 21px;
 
   .buttonsRow {
     display: flex;
diff --git a/packages/extension/public/index.html b/packages/extension/public/index.html
index d86bc8f6..8dc3fb4a 100644
--- a/packages/extension/public/index.html
+++ b/packages/extension/public/index.html
@@ -5,7 +5,7 @@
     <title>polkadot{.js}</title>
   </head>
   <body style="height: 600px; margin:0; overflow-x:hidden; text-align:center">
-    <div id="root" style="box-sizing:border-box; margin:0 auto; padding:0; text-align:left; width:570px; height: calc(100% - 2px); max-width: 100%;"></div>
+    <div id="root" style="box-sizing:border-box; margin:0 auto; padding:0; text-align:left; width:560px; height: calc(100% - 2px); max-width: 100%;"></div>
     <script src='./extension.js'></script>
   </body>
 </html>


Test patch:
diff --git a/packages/extension-ui/src/Popup/CreateAccount/CreateAccount.test.tsx b/packages/extension-ui/src/Popup/CreateAccount/CreateAccount.test.tsx
index e04cd450..24e3de83 100644
--- a/packages/extension-ui/src/Popup/CreateAccount/CreateAccount.test.tsx
+++ b/packages/extension-ui/src/Popup/CreateAccount/CreateAccount.test.tsx
@@ -42,7 +42,7 @@ describe('Create Account', () => {
     wrapper.update();
   };
 
-  const enterName = (name: string): Promise<void> => type(wrapper.find('input'), name);
+  const enterName = (name: string): Promise<void> => type(wrapper.find('input').first(), name);
   const password = (password: string) => (): Promise<void> => type(wrapper.find('input[type="password"]').first(), password);
   const repeat = (password: string) => (): Promise<void> => type(wrapper.find('input[type="password"]').last(), password);
 
@@ -89,20 +89,20 @@ describe('Create Account', () => {
 
     it('only account name input is visible at first', () => {
       expect(wrapper.find(InputWithLabel).find('[data-input-name]').find(Input)).toHaveLength(1);
-      expect(wrapper.find(InputWithLabel).find('[data-input-password]')).toHaveLength(0);
+      expect(wrapper.find(InputWithLabel).find('[data-input-password]').find(Input)).toHaveLength(1);
       expect(wrapper.find(InputWithLabel).find('[data-input-repeat-password]')).toHaveLength(0);
       expect(wrapper.find('[data-button-action="add new root"] button').prop('disabled')).toBe(true);
     });
 
     it('input should not be highlighted as error until first interaction', () => {
-      expect(wrapper.find(Input).prop('withError')).toBe(false);
+      expect(wrapper.find(InputWithLabel).find('[data-input-name]').find(Input).prop('withError')).toBe(false);
     });
 
     it('after typing less than 3 characters into name input, password input is not visible', async () => {
       await enterName('ab');
-      expect(wrapper.find(Input).prop('withError')).toBe(true);
-      expect(wrapper.find('ErrorMessage').text()).toBe('Account name is too short');
-      expect(wrapper.find(InputWithLabel).find('[data-input-password]')).toHaveLength(0);
+      expect(wrapper.find(InputWithLabel).find('[data-input-name]').find(Input).prop('withError')).toBe(true);
+      expect(wrapper.find('ErrorMessage').first().text()).toBe('Account name is too short');
+      expect(wrapper.find(InputWithLabel).find('[data-input-password]').find(Input)).toHaveLength(1);
       expect(wrapper.find(InputWithLabel).find('[data-input-repeat-password]')).toHaveLength(0);
       expect(wrapper.find('[data-button-action="add new root"] button').prop('disabled')).toBe(true);
     });
@@ -110,12 +110,12 @@ describe('Create Account', () => {
     it('input should keep showing error when something has been typed but then erased', async () => {
       await enterName('ab');
       await enterName('');
-      expect(wrapper.find(Input).prop('withError')).toBe(true);
+      expect(wrapper.find(InputWithLabel).find('[data-input-name]').find(Input).prop('withError')).toBe(true);
     });
 
     it('after typing 3 characters into name input, first password input is visible', async () => {
       await enterName('abc');
-      expect(wrapper.find(Input).first().prop('withError')).toBe(false);
+      expect(wrapper.find(InputWithLabel).find('[data-input-name]').find(Input).first().prop('withError')).toBe(false);
       expect(wrapper.find(InputWithLabel).find('[data-input-password]').find(Input)).toHaveLength(1);
       expect(wrapper.find(InputWithLabel).find('[data-input-repeat-password]')).toHaveLength(0);
       expect(wrapper.find('[data-button-action="add new root"] button').prop('disabled')).toBe(true);