Skip to content

Commit

Permalink
Add "Create a new wallet" flow when click on "Add Account" button (#1885
Browse files Browse the repository at this point in the history
)
  • Loading branch information
OKendigelyan authored Sep 17, 2024
1 parent de03d6d commit 509b34e
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("<DeriveMnemonicAccountModal />", () => {

const account = mockMnemonicAccount(0);
await renderInModal(<DeriveMnemonicAccountModal account={account} />, store);
await act(() => user.type(screen.getByLabelText("Account name"), "Test Account"));
await act(() => user.type(screen.getByLabelText("Account name (Optional)"), "Test Account"));
await act(() => user.click(screen.getByRole("button", { name: "Continue" })));

await waitFor(() => {
Expand All @@ -53,7 +53,7 @@ describe("<DeriveMnemonicAccountModal />", () => {
const account = mockMnemonicAccount(0);
await renderInModal(<DeriveMnemonicAccountModal account={account} />, store);

await act(() => user.type(screen.getByLabelText("Account name"), "Test Account"));
await act(() => user.type(screen.getByLabelText("Account name (Optional)"), "Test Account"));
await act(() => user.click(screen.getByRole("button", { name: "Continue" })));
await act(() => user.type(screen.getByLabelText("Password"), "test-password"));
await act(() => user.click(screen.getByRole("button", { name: "Submit" })));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ beforeEach(() => {
describe("<AdvancedMenu />", () => {
describe("when user is verified", () => {
it("renders advanced menu items correctly", async () => {
await renderInDrawer(<AdvancedMenu />);
await renderInDrawer(<AdvancedMenu />, store);

expect(screen.getByText("Change Password")).toBeVisible();
expect(screen.getByText("Network")).toBeVisible();
Expand All @@ -33,7 +33,7 @@ describe("<AdvancedMenu />", () => {
])("opens %label menu", async (label, Component) => {
const { openWith } = dynamicDrawerContextMock;

await renderInDrawer(<AdvancedMenu />);
await renderInDrawer(<AdvancedMenu />, store);

await userEvent.click(screen.getByText(label));
expect(openWith).toHaveBeenCalledWith(<Component />);
Expand Down
25 changes: 13 additions & 12 deletions apps/web/src/components/Menu/Menu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
screen,
userEvent,
} from "../../testUtils";
import { OnboardOptionsModal } from "../Onboarding/OnboardOptions";

jest.mock("@chakra-ui/system", () => ({
...jest.requireActual("@chakra-ui/system"),
Expand Down Expand Up @@ -51,7 +52,7 @@ describe("<Menu />", () => {

describe("when user is verified", () => {
it("renders menu items correctly", async () => {
await renderInDrawer(<Menu />);
await renderInDrawer(<Menu />, store);

expect(screen.getByText("Advanced")).toBeVisible();
expect(screen.getByText("Address Book")).toBeVisible();
Expand All @@ -70,7 +71,7 @@ describe("<Menu />", () => {
const user = userEvent.setup();
const { openWith } = dynamicDrawerContextMock;

await renderInDrawer(<Menu />);
await renderInDrawer(<Menu />, store);

await user.click(screen.getByText(label));
expect(openWith).toHaveBeenCalledWith(<Component />);
Expand All @@ -80,15 +81,15 @@ describe("<Menu />", () => {
const user = userEvent.setup();
const { openWith } = dynamicModalContextMock;

await renderInDrawer(<Menu />);
await renderInDrawer(<Menu />, store);

await user.click(screen.getByText("Logout"));
expect(openWith).toHaveBeenCalledWith(<LogoutModal />);
});

it("calls downloadBackupFile function when Save Backup is clicked", async () => {
const user = userEvent.setup();
await renderInDrawer(<Menu />);
await renderInDrawer(<Menu />, store);

await user.click(screen.getByText("Save Backup"));

Expand All @@ -97,22 +98,22 @@ describe("<Menu />", () => {

it("calls toggleColorMode function when Light mode is clicked", async () => {
const user = userEvent.setup();
await renderInDrawer(<Menu />);
await renderInDrawer(<Menu />, store);

await user.click(screen.getByText("Light mode"));

expect(useColorMode().toggleColorMode).toHaveBeenCalled();
});

// TODO: add when Add Account logic is ready
// it("opens Add Account modal when Add Account button is clicked", async () => {
// const user = userEvent.setup();
// await renderInDrawer(<Menu />);
it("opens Add Account modal when Add Account button is clicked", async () => {
const { openWith } = dynamicModalContextMock;
const user = userEvent.setup();
await renderInDrawer(<Menu />, store);

// await user.click(screen.getByText("Add Account"));
await user.click(screen.getByText("Add Account"));

// expect(useOnboardingModal().onOpen).toHaveBeenCalled();
// });
expect(openWith).toHaveBeenCalledWith(<OnboardOptionsModal />);
});
});

describe("when user is unverified", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { defaultDerivationPathTemplate } from "@umami/tezos";

import { NameAccountModal } from "./NameAccountModal";
import { act, renderInModal, screen, userEvent, waitFor } from "../../testUtils";

Expand All @@ -13,16 +15,42 @@ describe("NameAccountModal", () => {
expect(screen.getByText("Custom Title")).toBeVisible();
});
expect(screen.getByText("Custom Subtitle")).toBeVisible();
expect(screen.queryByTestId("advanced-section")).not.toBeInTheDocument();
});

it("calls onSubmit with form data when submitted", async () => {
const user = userEvent.setup();

await renderInModal(<NameAccountModal onSubmit={mockOnSubmit} />);

await act(() => user.type(screen.getByLabelText("Account name"), "Test Account"));
await act(() => user.type(screen.getByLabelText("Account name (Optional)"), "Test Account"));
await act(() => user.click(screen.getByRole("button", { name: "Continue" })));

expect(mockOnSubmit).toHaveBeenCalled();
});

it("renders advanced settings when enabled", async () => {
await renderInModal(<NameAccountModal onSubmit={mockOnSubmit} withAdvancedSettings />);

expect(screen.getByTestId("advanced-section")).toBeVisible();
});

it("submits the form with advanced settings when enabled", async () => {
const user = userEvent.setup();
await renderInModal(<NameAccountModal onSubmit={mockOnSubmit} withAdvancedSettings />);

const input = screen.getByTestId("accountName");
const submitButton = screen.getByRole("button", { name: "Continue" });

await user.type(input, "My Advanced Account");
await user.click(submitButton);

expect(mockOnSubmit).toHaveBeenCalledWith(
expect.objectContaining({
accountName: "My Advanced Account",
derivationPath: defaultDerivationPathTemplate,
curve: "ed25519",
})
);
});
});
64 changes: 43 additions & 21 deletions apps/web/src/components/NameAccountModal/NameAccountModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,40 @@ import {
Text,
} from "@chakra-ui/react";
import { useMultiForm } from "@umami/components";
import { defaultDerivationPathTemplate } from "@umami/tezos";
import { FormProvider } from "react-hook-form";

import { UserIcon } from "../../assets/icons";
import { useColor } from "../../styles/useColor";
import { ModalBackButton } from "../BackButton";
import { ModalCloseButton } from "../CloseButton";
import { AdvancedAccountSettings } from "../Onboarding/AdvancedAccountSettings";

type NameAccountModalProps = {
title?: string;
subtitle?: string;
onSubmit: (values: { accountName: string }) => void;
withAdvancedSettings?: boolean;
buttonLabel?: string;
};

export const NameAccountModal = ({
title = "Name Your Account",
subtitle,
onSubmit,
withAdvancedSettings = false,
buttonLabel = "Continue",
}: NameAccountModalProps) => {
const color = useColor();

const form = useMultiForm({
mode: "onBlur",
defaultValues: {
accountName: "",
...(withAdvancedSettings && {
derivationPath: defaultDerivationPathTemplate,
curve: "ed25519",
}),
},
});

Expand All @@ -50,32 +61,43 @@ export const NameAccountModal = ({
<Icon as={UserIcon} boxSize="24px" marginBottom="4px" color={color("blue")} />
<Heading size="xl">{title}</Heading>
{subtitle && (
<Text width="full" color={color("700")} fontWeight="400" textAlign="center" size="md">
<Text
width="full"
maxWidth="340px"
color={color("700")}
fontWeight="400"
textAlign="center"
whiteSpace="pre-wrap"
size="md"
>
{subtitle}
</Text>
)}
</Center>
</ModalHeader>
<form onSubmit={handleSubmit(onSubmit)} style={{ width: "100%" }}>
<ModalBody>
<FormControl>
<FormLabel>Account name</FormLabel>
<Input
data-testid="accountName"
type="text"
{...register("accountName", {
required: false,
})}
placeholder="Optional"
/>
</FormControl>
</ModalBody>
<ModalFooter>
<Button width="full" type="submit" variant="primary">
Continue
</Button>
</ModalFooter>
</form>
<FormProvider {...form}>
<form onSubmit={handleSubmit(onSubmit)} style={{ width: "100%" }}>
<ModalBody gap="30px">
<FormControl>
<FormLabel>Account name (Optional)</FormLabel>
<Input
data-testid="accountName"
type="text"
{...register("accountName", {
required: false,
})}
placeholder="Enter Account Name"
/>
</FormControl>
{withAdvancedSettings && <AdvancedAccountSettings />}
</ModalBody>
<ModalFooter>
<Button width="full" type="submit" variant="primary">
{buttonLabel}
</Button>
</ModalFooter>
</form>
</FormProvider>
</ModalContent>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,10 @@ export const AdvancedAccountSettings = () => {
<InputRightElement>
<Button
marginRight="10px"
color={color("200")}
fontWeight="600"
background={color("black")}
borderRadius="4px"
_hover={{ background: color("400") }}
onClick={() => resetField("derivationPath")}
size="sm"
variant="inputElement"
>
Reset
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,31 @@ import { OnboardWithRedditButton } from "./OnboardWithRedditButton";
import { OnboardWithTwitterButton } from "./OnboardWithTwitterButton";
import { useColor } from "../../../styles/useColor";
import { AccountTileWrapper } from "../../AccountTile";
import { NameAccountModal } from "../../NameAccountModal";
import { ImportWallet } from "../ImportWallet";
import { SetupPassword } from "../SetupPassword";
import { useIsAccountVerified } from "../VerificationFlow";

export const OnboardOptions = ({ children }: PropsWithChildren) => {
const color = useColor();

const { openWith } = useDynamicModalContext();
const isAccountVerified = useIsAccountVerified();

const handleCreateNewWallet = () => {
if (isAccountVerified) {
return openWith(
<NameAccountModal
buttonLabel="Continue"
onSubmit={() => openWith(<SetupPassword mode="add_account" />)}
subtitle={"Name your account or edit your\n account name later."}
title="Create Account"
withAdvancedSettings
/>
);
} else {
return openWith(<SetupPassword mode="new_mnemonic" />);
}
};

return (
<Flex alignItems="center" flexDirection="column" width="full">
Expand Down Expand Up @@ -50,12 +68,7 @@ export const OnboardOptions = ({ children }: PropsWithChildren) => {
</Center>

<Flex flexDirection="column" gap="12px" width="full">
<Button
width="full"
onClick={() => openWith(<SetupPassword mode="new_mnemonic" />)}
size="lg"
variant="primary"
>
<Button width="full" onClick={handleCreateNewWallet} size="lg" variant="primary">
Create a new wallet
</Button>
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ describe("<SetupPassword />", () => {
});
});

describe("new_mnemonic mode", () => {
describe("adding new account mode", () => {
const store = makeStore();
const mockRestoreFromMnemonic = jest.fn();

Expand All @@ -239,13 +239,16 @@ describe("<SetupPassword />", () => {
jest.mocked(generate24WordMnemonic).mockReturnValue(mnemonic1);
});

it("doesn't render advanced section", async () => {
await renderInModal(<SetupPassword mode="new_mnemonic" />);
it.each(["new_mnemonic", "add_account"] as const)(
"doesn't render advanced section",
async mode => {
await renderInModal(<SetupPassword mode={mode} />);

expect(screen.queryByTestId("advanced-section")).not.toBeInTheDocument();
});
expect(screen.queryByTestId("advanced-section")).not.toBeInTheDocument();
}
);

it("calls restoreFromMnemonic with predefined mnemonic", async () => {
it("calls restoreFromMnemonic with predefined mnemonic for new_mnemonic mode", async () => {
const user = userEvent.setup();

await renderInModal(<SetupPassword mode="new_mnemonic" />, store);
Expand All @@ -270,6 +273,31 @@ describe("<SetupPassword />", () => {
isVerified: false,
});
});

it("calls restoreFromMnemonic with predefined mnemonic for add_account mode", async () => {
jest.mocked(useIsPasswordSet).mockReturnValue(true);
const user = userEvent.setup();

await renderInModal(<SetupPassword mode="add_account" />, store);

const passwordInput = screen.getByLabelText("Password");

await act(() => user.type(passwordInput, password));

const submitButton = screen.getByRole("button", { name: "Add Account" });

await act(() => user.click(submitButton));

await waitFor(() => expect(mockRestoreFromMnemonic).toHaveBeenCalledTimes(1));
expect(mockRestoreFromMnemonic).toHaveBeenCalledWith({
mnemonic: mnemonic1,
password,
derivationPathTemplate: "44'/1729'/?'/0'",
label: "Account",
curve: "ed25519",
isVerified: false,
});
});
});

describe("verification mode", () => {
Expand Down
Loading

1 comment on commit 509b34e

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title Lines Statements Branches Functions
apps/desktop Coverage: 83%
83.79% (1758/2098) 78.94% (825/1045) 78.45% (448/571)
apps/web Coverage: 83%
83.79% (1758/2098) 78.94% (825/1045) 78.45% (448/571)
packages/components Coverage: 97%
97.1% (134/138) 96.49% (55/57) 82.92% (34/41)
packages/core Coverage: 82%
82.89% (223/269) 73.18% (101/138) 81.35% (48/59)
packages/crypto Coverage: 100%
100% (28/28) 100% (3/3) 100% (5/5)
packages/data-polling Coverage: 98%
96.55% (140/145) 95.45% (21/22) 92.85% (39/42)
packages/multisig Coverage: 98%
98.47% (129/131) 89.47% (17/19) 100% (35/35)
packages/social-auth Coverage: 100%
100% (21/21) 100% (11/11) 100% (3/3)
packages/state Coverage: 84%
83.64% (772/923) 80.78% (164/203) 78.22% (291/372)
packages/tezos Coverage: 86%
85.57% (89/104) 89.47% (17/19) 82.75% (24/29)
packages/tzkt Coverage: 86%
84.05% (58/69) 81.25% (13/16) 76.92% (30/39)

Please sign in to comment.