From f912097797c52142f75f355a930141fcba0c0079 Mon Sep 17 00:00:00 2001 From: Breno Polanski Date: Sat, 8 Aug 2020 23:02:17 -0300 Subject: [PATCH] feat: add `InputAddress` component (#2614) --- src/app/assets/svg/qrcode.svg | 2 +- src/app/components/Input/Input.stories.tsx | 25 +- .../components/Input/InputAddress.test.tsx | 82 ++ src/app/components/Input/InputAddress.tsx | 70 ++ .../__snapshots__/InputAddress.test.tsx.snap | 35 + .../__snapshots__/InputGroup.test.tsx.snap | 14 +- src/app/components/Input/index.tsx | 5 +- src/app/i18n/common/i18n.ts | 6 + .../pages/Dashboard/Dashboard.test.tsx | 2 +- .../__snapshots__/CustomPeers.test.tsx.snap | 6 +- .../SendTransactionForm.test.tsx.snap | 52 +- .../UpdateWalletName.test.tsx.snap | 6 +- .../wallet/e2e/import-wallet-action.e2e.ts | 123 +- .../pages/ImportWallet/ImportWallet.test.tsx | 349 ++---- .../pages/ImportWallet/ImportWallet.tsx | 54 +- .../__snapshots__/ImportWallet.test.tsx.snap | 1114 ++--------------- 16 files changed, 525 insertions(+), 1420 deletions(-) create mode 100755 src/app/components/Input/InputAddress.test.tsx create mode 100755 src/app/components/Input/InputAddress.tsx create mode 100644 src/app/components/Input/__snapshots__/InputAddress.test.tsx.snap diff --git a/src/app/assets/svg/qrcode.svg b/src/app/assets/svg/qrcode.svg index 6ccbe7b97e..066ca82ba1 100644 --- a/src/app/assets/svg/qrcode.svg +++ b/src/app/assets/svg/qrcode.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/app/components/Input/Input.stories.tsx b/src/app/components/Input/Input.stories.tsx index c056fe1a47..d536b9a701 100644 --- a/src/app/components/Input/Input.stories.tsx +++ b/src/app/components/Input/Input.stories.tsx @@ -1,6 +1,13 @@ +import { ARK } from "@arkecosystem/platform-sdk-ark"; +import { Environment } from "@arkecosystem/platform-sdk-profiles"; +import { EnvironmentProvider } from "app/contexts"; +import { httpClient } from "app/services"; import React from "react"; +import { StubStorage } from "tests/mocks"; -import { Input, InputCounter, InputPassword } from "./index"; +import { Input, InputAddress, InputCounter, InputPassword } from "./index"; + +const env = new Environment({ coins: { ARK }, httpClient, storage: new StubStorage() }); export default { title: "App / Components / Input", @@ -14,10 +21,12 @@ export const Default = () => ( ); -export const Password = () => ( -
- -
+export const Address = () => ( + +
+ +
+
); export const Counter = () => ( @@ -25,3 +34,9 @@ export const Counter = () => ( ); + +export const Password = () => ( +
+ +
+); diff --git a/src/app/components/Input/InputAddress.test.tsx b/src/app/components/Input/InputAddress.test.tsx new file mode 100755 index 0000000000..e1d3b79801 --- /dev/null +++ b/src/app/components/Input/InputAddress.test.tsx @@ -0,0 +1,82 @@ +import { act, renderHook } from "@testing-library/react-hooks"; +import { EnvironmentProvider } from "app/contexts"; +import React from "react"; +import { useForm } from "react-hook-form"; +import { env, fireEvent, render } from "utils/testing-library"; + +import { InputAddress, InputAddressProps } from "./InputAddress"; + +describe("InputAddress", () => { + const TestInputAddress = (props: InputAddressProps) => ( + + + + ); + + it("should render", () => { + const { getByTestId, asFragment } = render(); + expect(getByTestId("InputAddress__input")).toBeInTheDocument(); + expect(getByTestId("InputAddress__qr-button")).toBeInTheDocument(); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should emit event whe clicking on qr button", () => { + const onQRButtonClick = jest.fn(); + const { getByTestId } = render( + , + ); + fireEvent.click(getByTestId("InputAddress__qr-button")); + expect(onQRButtonClick).toHaveBeenCalled(); + }); + + it("should validate a wrong address", async () => { + const { result, waitForNextUpdate } = renderHook(() => useForm({ mode: "onChange" })); + const { register, errors } = result.current; + + const { getByTestId } = render(); + + act(() => { + fireEvent.input(getByTestId("InputAddress__input"), { target: { value: "Abc" } }); + }); + + await waitForNextUpdate(); + expect(errors.address?.message).toBe("The address is not valid"); + }); + + it("should validate a valid address and emit event", async () => { + const onValidAddress = jest.fn(); + const { result, waitForNextUpdate } = renderHook(() => useForm({ mode: "onChange" })); + const { register, errors } = result.current; + const validAddress = "DT11QcbKqTXJ59jrUTpcMyggTcwmyFYRTM"; + + const { getByTestId } = render( + , + ); + + act(() => { + fireEvent.input(getByTestId("InputAddress__input"), { + target: { value: validAddress }, + }); + }); + + await waitForNextUpdate(); + expect(errors.address?.message).toBe(undefined); + expect(onValidAddress).toHaveBeenCalledWith(validAddress); + }); + + it("should validate with additional rules", async () => { + const { result, waitForNextUpdate } = renderHook(() => useForm({ mode: "onChange" })); + const { register, errors } = result.current; + + const { getByTestId } = render( + , + ); + + act(() => { + fireEvent.input(getByTestId("InputAddress__input"), { target: { value: "Abc" } }); + }); + + await waitForNextUpdate(); + expect(errors.address?.type).toBe("minLength"); + }); +}); diff --git a/src/app/components/Input/InputAddress.tsx b/src/app/components/Input/InputAddress.tsx new file mode 100755 index 0000000000..2a6fa8940d --- /dev/null +++ b/src/app/components/Input/InputAddress.tsx @@ -0,0 +1,70 @@ +import { Icon } from "app/components/Icon"; +import { useEnvironmentContext } from "app/contexts"; +import React from "react"; +import { ValidationOptions } from "react-hook-form"; +import { useTranslation } from "react-i18next"; + +import { Input } from "./Input"; +import { InputAddonEnd, InputGroup } from "./InputGroup"; + +export type InputAddressProps = { + coin: string; + network: string; + registerRef?: (options: ValidationOptions) => (ref: HTMLInputElement | null) => void; + additionalRules?: ValidationOptions; + onValidAddress?: (address: string) => void; + onQRCodeClick?: () => void; +} & React.InputHTMLAttributes; + +export const InputAddress = ({ + coin, + network, + registerRef, + additionalRules, + onValidAddress, + onQRCodeClick, + ...props +}: InputAddressProps) => { + const { t } = useTranslation(); + const { env } = useEnvironmentContext(); + + const validateAddress = async (address: string) => { + const isValidAddress = await env.dataValidator().address(coin, network, address); + + if (isValidAddress) { + onValidAddress?.(address); + return true; + } + + return t("COMMON.INPUT_ADDRESS.VALIDATION.NOT_VALID"); + }; + + return ( + + + + + + + ); +}; + +InputAddress.defaultProps = { + additionalRules: {}, +}; diff --git a/src/app/components/Input/__snapshots__/InputAddress.test.tsx.snap b/src/app/components/Input/__snapshots__/InputAddress.test.tsx.snap new file mode 100644 index 0000000000..54d2828c46 --- /dev/null +++ b/src/app/components/Input/__snapshots__/InputAddress.test.tsx.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`InputAddress should render 1`] = ` + +
+ +
+ +
+
+
+`; diff --git a/src/app/components/Input/__snapshots__/InputGroup.test.tsx.snap b/src/app/components/Input/__snapshots__/InputGroup.test.tsx.snap index cc33fea37f..9195c5603a 100644 --- a/src/app/components/Input/__snapshots__/InputGroup.test.tsx.snap +++ b/src/app/components/Input/__snapshots__/InputGroup.test.tsx.snap @@ -3,10 +3,10 @@ exports[`InputGroup should render with both elements 1`] = `
{ .persist(); }); -afterEach(() => nock.cleanAll()); +// afterEach(() => nock.cleanAll()); describe("Dashboard", () => { it("should render", async () => { diff --git a/src/domains/setting/components/CustomPeers/__snapshots__/CustomPeers.test.tsx.snap b/src/domains/setting/components/CustomPeers/__snapshots__/CustomPeers.test.tsx.snap index 7911eacd84..1754ae94fa 100644 --- a/src/domains/setting/components/CustomPeers/__snapshots__/CustomPeers.test.tsx.snap +++ b/src/domains/setting/components/CustomPeers/__snapshots__/CustomPeers.test.tsx.snap @@ -25,7 +25,7 @@ exports[`CustomPeers should render a modal 1`] = ` class="p-1" >
@@ -73,11 +73,11 @@ exports[`CustomPeers should render a modal 1`] = ` id="CustomPeers__network-label" />
@@ -286,7 +286,7 @@ exports[`SendTransactionForm should render 1`] = ` class="rounded-full cursor-pointer bg-theme-primary-100 text-theme-primary-500" >
@@ -363,7 +363,7 @@ exports[`SendTransactionForm should render 1`] = ` data-testid="SelectRecipient__select-contact" >
@@ -391,7 +391,7 @@ exports[`SendTransactionForm should render 1`] = `
- diff --git a/src/domains/wallet/pages/ImportWallet/__snapshots__/ImportWallet.test.tsx.snap b/src/domains/wallet/pages/ImportWallet/__snapshots__/ImportWallet.test.tsx.snap index 4a3c4ab014..5679e7116e 100644 --- a/src/domains/wallet/pages/ImportWallet/__snapshots__/ImportWallet.test.tsx.snap +++ b/src/domains/wallet/pages/ImportWallet/__snapshots__/ImportWallet.test.tsx.snap @@ -7,7 +7,7 @@ exports[`ImportWallet should go to previous step 1`] = ` > -
-
- - arrow-back.svg - -
- -
-
-
-
-
-
-
    -
  • -
  • -
-
-
-
-
-
-
-

- Select a Network -

-
- Select a Network to import your existing wallet address -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -`; - -exports[`ImportWallet should show an error message for invalid address 1`] = ` - -
- -
-
- - arrow-back.svg - -
- -
-
-
-
-
-
-
    -
  • -
  • -
-
-
-
-
-
-
-

- Select a Network -

-
- Select a Network to import your existing wallet address -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-`; - -exports[`ImportWallet should show an error message if trying to import a duplicate address 1`] = ` +exports[`ImportWallet should show an error message for invalid address 1`] = `