Repository: polkadot-js/extension
Pull request #611 (2021-01-05 12:09:22)

Add tests for External import flow
follow-up to #609 


Patch:
diff --git a/__mocks__/react-i18next.ts b/__mocks__/react-i18next.ts
new file mode 100644
index 00000000..68ac12e3
--- /dev/null
+++ b/__mocks__/react-i18next.ts
@@ -0,0 +1,24 @@
+// Copyright 2019-2021 @polkadot/extension-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import React from 'react';
+
+interface useTranslationReturnObj {
+  i18n: { changeLanguage: () => Promise<unknown>; };
+  t: (str: string) => string;
+}
+
+export const useTranslation = (): useTranslationReturnObj => {
+  return {
+    i18n: {
+      changeLanguage: () => new Promise(() => { /**/ })
+    },
+    t: (str: string) => str
+  };
+};
+
+export const withTranslation = () => (component: React.ReactElement): React.ReactElement => component;
+
+export const Trans = ({ children }: { children: React.ReactElement }): React.ReactElement => children;
+
+export default withTranslation;
diff --git a/package.json b/package.json
index 9d4ba3b1..f66504fe 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "repository": "https://github.com/polkadot-js/extension",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "private": true,
   "workspaces": [
     "packages/*"
diff --git a/packages/extension-base/package.json b/packages/extension-base/package.json
index 9869264a..7ed035b7 100644
--- a/packages/extension-base/package.json
+++ b/packages/extension-base/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@polkadot/extension-base",
   "description": "Functions, classes and other utilities used in @polkadot/extension",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
   "main": "index.js",
@@ -9,7 +9,7 @@
   "dependencies": {
     "@babel/runtime": "^7.12.5",
     "@polkadot/api": "^3.3.1",
-    "@polkadot/extension-inject": "^0.36.1",
+    "@polkadot/extension-inject": "^0.36.2-0",
     "@polkadot/keyring": "^5.2.3",
     "@polkadot/phishing": "^0.3.7",
     "@polkadot/ui-keyring": "^0.65.2-0"
diff --git a/packages/extension-chains/package.json b/packages/extension-chains/package.json
index 1e82ecfe..b2361205 100644
--- a/packages/extension-chains/package.json
+++ b/packages/extension-chains/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@polkadot/extension-chains",
   "description": "Definitions for all known chains as exposed by the extension.",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
   "main": "index.js",
diff --git a/packages/extension-dapp/package.json b/packages/extension-dapp/package.json
index 46af99c2..d1d391ff 100644
--- a/packages/extension-dapp/package.json
+++ b/packages/extension-dapp/package.json
@@ -1,14 +1,14 @@
 {
   "name": "@polkadot/extension-dapp",
   "description": "Provides an interfaces around the injected globals for ease of access by dapp developers.",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
   "main": "index.js",
   "sideEffects": false,
   "dependencies": {
     "@babel/runtime": "^7.12.5",
-    "@polkadot/extension-inject": "^0.36.1",
+    "@polkadot/extension-inject": "^0.36.2-0",
     "@polkadot/util": "^5.2.3",
     "@polkadot/util-crypto": "^5.2.3"
   },
diff --git a/packages/extension-inject/package.json b/packages/extension-inject/package.json
index 65e61347..dfcf51da 100644
--- a/packages/extension-inject/package.json
+++ b/packages/extension-inject/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@polkadot/extension-inject",
   "description": "A generic injector (usable to any extension), that populates the base exposed interfaces to be used by dapps.",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
   "main": "index.js",
diff --git a/packages/extension-ui/package.json b/packages/extension-ui/package.json
index f5e276b8..2be04e80 100644
--- a/packages/extension-ui/package.json
+++ b/packages/extension-ui/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@polkadot/extension-ui",
   "description": "A sample signer extension for the @polkadot/api",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
   "dependencies": {
@@ -10,8 +10,8 @@
     "@fortawesome/free-regular-svg-icons": "^5.15.1",
     "@fortawesome/free-solid-svg-icons": "^5.15.1",
     "@fortawesome/react-fontawesome": "^0.1.13",
-    "@polkadot/extension-base": "^0.36.1",
-    "@polkadot/extension-inject": "^0.36.1",
+    "@polkadot/extension-base": "^0.36.2-0",
+    "@polkadot/extension-inject": "^0.36.2-0",
     "@polkadot/keyring": "^5.2.3",
     "@polkadot/react-identicon": "^0.65.2-0",
     "@polkadot/react-qr": "^0.65.2-0",
diff --git a/packages/extension-ui/src/Popup/AuthManagement/WebsiteEntry.tsx b/packages/extension-ui/src/Popup/AuthManagement/WebsiteEntry.tsx
index 3e535f79..cc2e64b7 100644
--- a/packages/extension-ui/src/Popup/AuthManagement/WebsiteEntry.tsx
+++ b/packages/extension-ui/src/Popup/AuthManagement/WebsiteEntry.tsx
@@ -41,7 +41,7 @@ function WebsiteEntry ({ className = '', info, toggleAuth, url }: Props): React.
   );
 }
 
-export default styled(WebsiteEntry)`
+export default styled(WebsiteEntry)(({ theme }: Props) => `
   display: flex;
   align-items: center;
 
@@ -51,8 +51,7 @@ export default styled(WebsiteEntry)`
 
   &.denied {
     .slider::before {
-        opacity: 0.4;
-        background-color: rgb(36, 37, 41);
+        background-color: ${theme.backButtonBackground};
       }
   }
-`;
+`);
diff --git a/packages/extension-ui/src/Popup/ImportQr.tsx b/packages/extension-ui/src/Popup/ImportQr.tsx
index 88169a97..4d507210 100644
--- a/packages/extension-ui/src/Popup/ImportQr.tsx
+++ b/packages/extension-ui/src/Popup/ImportQr.tsx
@@ -62,15 +62,14 @@ export default function ImportQr (): React.ReactElement {
             value={name || ''}
           />
           <VerticalSpace />
-          {name && (
-            <ButtonArea>
-              <NextStepButton
-                onClick={_onCreate}
-              >
-                {t<string>('Add the account with identified address')}
-              </NextStepButton>
-            </ButtonArea>
-          )}
+          <ButtonArea>
+            <NextStepButton
+              isDisabled={!name}
+              onClick={_onCreate}
+            >
+              {t<string>('Add the account with identified address')}
+            </NextStepButton>
+          </ButtonArea>
         </>
       )}
     </>
diff --git a/packages/extension/package.json b/packages/extension/package.json
index 5a889b7b..9eeb05d6 100644
--- a/packages/extension/package.json
+++ b/packages/extension/package.json
@@ -1,14 +1,14 @@
 {
   "name": "@polkadot/extension",
   "description": "A sample signer extension for the @polkadot/api",
-  "version": "0.36.1",
+  "version": "0.36.2-0",
   "author": "Jaco Greeff <jacogr@gmail.com>",
   "license": "Apache-2",
   "dependencies": {
     "@babel/runtime": "^7.12.5",
-    "@polkadot/extension-base": "^0.36.1",
-    "@polkadot/extension-inject": "^0.36.1",
-    "@polkadot/extension-ui": "^0.36.1"
+    "@polkadot/extension-base": "^0.36.2-0",
+    "@polkadot/extension-inject": "^0.36.2-0",
+    "@polkadot/extension-ui": "^0.36.2-0"
   },
   "devDependencies": {
     "@polkadot/dev": "^0.61.22",
diff --git a/yarn.lock b/yarn.lock
index dcaf67d4..feb4038a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1920,13 +1920,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@polkadot/extension-base@^0.36.1, @polkadot/extension-base@workspace:packages/extension-base":
+"@polkadot/extension-base@^0.36.2-0, @polkadot/extension-base@workspace:packages/extension-base":
   version: 0.0.0-use.local
   resolution: "@polkadot/extension-base@workspace:packages/extension-base"
   dependencies:
     "@babel/runtime": ^7.12.5
     "@polkadot/api": ^3.3.1
-    "@polkadot/extension-inject": ^0.36.1
+    "@polkadot/extension-inject": ^0.36.2-0
     "@polkadot/keyring": ^5.2.3
     "@polkadot/phishing": ^0.3.7
     "@polkadot/ui-keyring": ^0.65.2-0
@@ -1949,7 +1949,7 @@ __metadata:
   resolution: "@polkadot/extension-dapp@workspace:packages/extension-dapp"
   dependencies:
     "@babel/runtime": ^7.12.5
-    "@polkadot/extension-inject": ^0.36.1
+    "@polkadot/extension-inject": ^0.36.2-0
     "@polkadot/util": ^5.2.3
     "@polkadot/util-crypto": ^5.2.3
   peerDependencies:
@@ -1957,7 +1957,7 @@ __metadata:
   languageName: unknown
   linkType: soft
 
-"@polkadot/extension-inject@^0.36.1, @polkadot/extension-inject@workspace:packages/extension-inject":
+"@polkadot/extension-inject@^0.36.2-0, @polkadot/extension-inject@workspace:packages/extension-inject":
   version: 0.0.0-use.local
   resolution: "@polkadot/extension-inject@workspace:packages/extension-inject"
   dependencies:
@@ -1969,7 +1969,7 @@ __metadata:
   languageName: unknown
   linkType: soft
 
-"@polkadot/extension-ui@^0.36.1, @polkadot/extension-ui@workspace:packages/extension-ui":
+"@polkadot/extension-ui@^0.36.2-0, @polkadot/extension-ui@workspace:packages/extension-ui":
   version: 0.0.0-use.local
   resolution: "@polkadot/extension-ui@workspace:packages/extension-ui"
   dependencies:
@@ -1978,8 +1978,8 @@ __metadata:
     "@fortawesome/free-regular-svg-icons": ^5.15.1
     "@fortawesome/free-solid-svg-icons": ^5.15.1
     "@fortawesome/react-fontawesome": ^0.1.13
-    "@polkadot/extension-base": ^0.36.1
-    "@polkadot/extension-inject": ^0.36.1
+    "@polkadot/extension-base": ^0.36.2-0
+    "@polkadot/extension-inject": ^0.36.2-0
     "@polkadot/keyring": ^5.2.3
     "@polkadot/react-identicon": ^0.65.2-0
     "@polkadot/react-qr": ^0.65.2-0
@@ -2016,9 +2016,9 @@ __metadata:
   dependencies:
     "@babel/runtime": ^7.12.5
     "@polkadot/dev": ^0.61.22
-    "@polkadot/extension-base": ^0.36.1
-    "@polkadot/extension-inject": ^0.36.1
-    "@polkadot/extension-ui": ^0.36.1
+    "@polkadot/extension-base": ^0.36.2-0
+    "@polkadot/extension-inject": ^0.36.2-0
+    "@polkadot/extension-ui": ^0.36.2-0
     babel-loader: ^8.2.2
     browser-resolve: ^2.0.0
     buffer: ^6.0.3


Test patch:
diff --git a/packages/extension-ui/src/Popup/ImportQr.test.tsx b/packages/extension-ui/src/Popup/ImportQr.test.tsx
new file mode 100644
index 00000000..9aa2a34c
--- /dev/null
+++ b/packages/extension-ui/src/Popup/ImportQr.test.tsx
@@ -0,0 +1,128 @@
+// Copyright 2019-2021 @polkadot/extension-ui authors & contributors
+// SPDX-License-Identifier: Apache-2.0
+
+import '../../../../__mocks__/chrome';
+
+import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
+import { configure, mount, ReactWrapper } from 'enzyme';
+import React from 'react';
+import { act } from 'react-dom/test-utils';
+import { MemoryRouter } from 'react-router';
+
+import { Button } from '../components';
+import * as messaging from '../messaging';
+import { flushAllPromises } from '../testHelpers';
+import ImportQr from './ImportQr';
+
+const mockedAccount = {
+  content: '12bxf6QJS5hMJgwbJMDjFot1sq93EvgQwyuPWENr9SzJfxtN',
+  expectedBannerChain: 'Polkadot',
+  genesisHash: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3',
+  isAddress: true,
+  name: 'My Polkadot Account'
+};
+
+interface ScanType {
+  isAddress: boolean;
+  content: string;
+  genesisHash: string;
+  name?: string;
+}
+
+interface QrScanAddressProps {
+  className?: string;
+  onError?: (error: Error) => void;
+  onScan: (scanned: ScanType) => void;
+  size?: string | number;
+  style?: React.CSSProperties;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
+configure({ adapter: new Adapter() });
+
+const typeName = async (wrapper: ReactWrapper, value:string) => {
+  wrapper.find('input').first().simulate('change', { target: { value } });
+  await act(flushAllPromises);
+  wrapper.update();
+};
+
+jest.mock('@polkadot/react-qr', () => {
+  return {
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    QrScanAddress: ({ onScan }: QrScanAddressProps): null => {
+      return null;
+    }
+  };
+});
+
+describe('ImportQr component', () => {
+  let wrapper: ReactWrapper;
+
+  beforeEach(async () => {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+    wrapper = mount(
+      <MemoryRouter>
+        <ImportQr />
+      </MemoryRouter>
+    );
+
+    act(() => {
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+      (wrapper.find('QrScanAddress').first().prop('onScan') as unknown as QrScanAddressProps['onScan'])(mockedAccount);
+    });
+    await act(flushAllPromises);
+    wrapper.update();
+  });
+
+  describe('Address component', () => {
+    it('shows account as external', () => {
+      expect(wrapper.find('Name').find('FontAwesomeIcon [data-icon="external-link-square-alt"]').exists()).toBe(true);
+    });
+
+    it('shows the correct name', () => {
+      expect(wrapper.find('Name span').text()).toEqual(mockedAccount.name);
+    });
+
+    it('shows the correct address', () => {
+      expect(wrapper.find('[data-field="address"]').text()).toEqual(mockedAccount.content);
+    });
+
+    it('shows the correct banner', () => {
+      expect(wrapper.find('[data-field="chain"]').text()).toEqual(mockedAccount.expectedBannerChain);
+    });
+  });
+
+  it('has the button enabled', () => {
+    expect(wrapper.find(Button).prop('isDisabled')).toBe(false);
+  });
+
+  it('displays and error and the button is disabled with a short name', async () => {
+    await typeName(wrapper, 'a');
+
+    expect(wrapper.find('.warning-message').first().text()).toBe('Account name is too short');
+    expect(wrapper.find(Button).prop('isDisabled')).toBe(true);
+  });
+
+  it('has no error message and button enabled with a long name', async () => {
+    const longName = 'aaa';
+
+    await typeName(wrapper, 'a');
+    await typeName(wrapper, longName);
+
+    expect(wrapper.find('.warning-message')).toHaveLength(0);
+    expect(wrapper.find(Button).prop('isDisabled')).toBe(false);
+    expect(wrapper.find('Name span').text()).toEqual(longName);
+  });
+
+  it('shows the external name in the input field', () => {
+    expect(wrapper.find('input').prop('value')).toBe(mockedAccount.name);
+  });
+
+  it('creates the external account', async () => {
+    jest.spyOn(messaging, 'createAccountExternal').mockResolvedValue(false);
+    wrapper.find(Button).simulate('click');
+    await act(flushAllPromises);
+
+    expect(messaging.createAccountExternal).toHaveBeenCalledWith(mockedAccount.name, mockedAccount.content, mockedAccount.genesisHash);
+  });
+});