diff --git a/web-wallet/src/routes/(welcome)/setup/create/__tests__/__snapshots__/page.spec.js.snap b/web-wallet/src/routes/(welcome)/setup/create/__tests__/__snapshots__/page.spec.js.snap index 341e3ced0a..5c9f28fcad 100644 --- a/web-wallet/src/routes/(welcome)/setup/create/__tests__/__snapshots__/page.spec.js.snap +++ b/web-wallet/src/routes/(welcome)/setup/create/__tests__/__snapshots__/page.spec.js.snap @@ -1167,7 +1167,7 @@ exports[`Create > doesn't let the user proceed if they have entered mismatching `; -exports[`Create > ensures that the Undo button works as expected 1`] = ` +exports[`Create > ensures that the Undo button on the Mnemonic Validate step works as expected 1`] = `
ensures that the Undo button works as expected 1`] = `
`; +exports[`Create > ensures the All Done step renders as expected 1`] = ` +
+
+ + + + + + + + + + + + + + + +

+ Welcome to +
+ + + Dusk + +

+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + +
+
+ +

+ You are all set! +

+ +
+ + All Set +
+ + + + +
+ + + +
+ + + +
+ + + +
+`; + +exports[`Create > ensures the Password step renders as expected 1`] = ` +
+
+ + + + + + + + + +

+ + Password + +
+ + Setup +

+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + +
+
+ + + + + + +

+ Password +

+ +
+ +
+ +
+ + + +
+ + + + + + +

+ Setting a password for your web wallet is optional. Doing so allows you + the convenience of opening your wallet file using a password, but it + weakens the overall security. Not using a password requires you to input + the full mnemonic to open your wallet. +

+
+ + +
+ + + + + + +
+ + + + + + + + + +
+ + + +
+`; + +exports[`Create > ensures the Swap To Native Dusk step renders as expected 1`] = ` +
+
+ + + + + + + + + + + + +

+ Swap ERC20 +
+ + to + + Native Dusk + +

+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + +

+ The ERC20 token swap functionality is currently disabled + and will be provided after the launch of the Dusk mainnet. +

+ + + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+`; + exports[`Create > lets the user proceed if they have entered a matching Mnemonic 1`] = `
} + */ +const fireInput = (input, value) => fireEvent.input(input, { target: { value } }); + +/** @param {HTMLElement} element */ +function asInput (element) { + // eslint-disable-next-line no-extra-parens + return /** @type {HTMLInputElement} */ (element); +} + describe("Create", async () => { const walletGetPsksSpy = vi.spyOn(Wallet.prototype, "getPsks").mockResolvedValue(addresses); const mnemonic = "cart dad sail wreck robot grit combine noble rap farm slide sad"; const mnemonicShuffled = ["grit", "wreck", "cart", "dad", "rap", "sail", "robot", "combine", "noble", "slide", "sad", "farm"]; const pwd = "passwordpassword"; - const loginInfo = await encryptMnemonic(mnemonic, pwd); const seed = getSeedFromMnemonic(mnemonic); const userId = (await new Wallet(seed).getPsks())[0]; const generateMnemonicSpy = vi.spyOn(bip39, "generateMnemonic").mockReturnValue(mnemonic); const shuffleArraySpy = vi.spyOn(shuffleArray, "shuffleArray").mockReturnValue(mnemonicShuffled); - const getWalletSpy = vi.spyOn(walletService, "getWallet"); const gotoSpy = vi.spyOn(appNavigation, "goto"); const settingsResetSpy = vi.spyOn(settingsStore, "reset"); @@ -47,7 +58,6 @@ describe("Create", async () => { getWalletSpy.mockClear(); gotoSpy.mockClear(); settingsResetSpy.mockClear(); - walletGetPsksSpy.mockClear(); }); afterAll(() => { @@ -216,7 +226,7 @@ describe("Create", async () => { expect(nextButton).toBeEnabled(); }); - it("ensures that the Undo button works as expected", async () => { + it("ensures that the Undo button on the Mnemonic Validate step works as expected", async () => { const { container, getByRole, getAllByRole } = render(Create); await fireEvent.click(getByRole("button", { name: "Accept" })); @@ -250,6 +260,102 @@ describe("Create", async () => { expect(nextButton).toBeDisabled(); }); + it("ensures the Password step renders as expected", async () => { + const { container, getByRole, getAllByRole } = render(Create); + + await fireEvent.click(getByRole("button", { name: "Accept" })); + + const firstCheckbox = getAllByRole("checkbox")[0]; + const secondCheckbox = getAllByRole("checkbox")[1]; + + await fireEvent.click(firstCheckbox); + await fireEvent.click(secondCheckbox); + + await fireEvent.click(getByRole("button", { name: "Next" })); + await fireEvent.click(getByRole("button", { name: "Next" })); + + const mnemonicSplit = mnemonic.split(" "); + + // Iterates over the Mnemonic and selects each + // word in the correct order + // Note: This type of test won't work for mnemonic with repeated words + mnemonicSplit.forEach(async word => { + const button = getByRole("button", { name: word }); + await fireEvent.click(button); + }) + + await tick(); + + await fireEvent.click(getByRole("button", { name: "Next" })); + + expect(container.firstChild).toMatchSnapshot(); + }); + + it("ensures the Swap To Native Dusk step renders as expected", async () => { + const { container, getByRole, getAllByRole } = render(Create); + + await fireEvent.click(getByRole("button", { name: "Accept" })); + + const firstCheckbox = getAllByRole("checkbox")[0]; + const secondCheckbox = getAllByRole("checkbox")[1]; + + await fireEvent.click(firstCheckbox); + await fireEvent.click(secondCheckbox); + + await fireEvent.click(getByRole("button", { name: "Next" })); + await fireEvent.click(getByRole("button", { name: "Next" })); + + const mnemonicSplit = mnemonic.split(" "); + + // Iterates over the Mnemonic and selects each + // word in the correct order + // Note: This type of test won't work for mnemonic with repeated words + mnemonicSplit.forEach(async word => { + const button = getByRole("button", { name: word }); + await fireEvent.click(button); + }) + + await tick(); + + await fireEvent.click(getByRole("button", { name: "Next" })); + await fireEvent.click(getByRole("button", { name: "Next" })); + + expect(container.firstChild).toMatchSnapshot(); + }); + + it("ensures the All Done step renders as expected", async () => { + const { container, getByRole, getAllByRole } = render(Create); + + await fireEvent.click(getByRole("button", { name: "Accept" })); + + const firstCheckbox = getAllByRole("checkbox")[0]; + const secondCheckbox = getAllByRole("checkbox")[1]; + + await fireEvent.click(firstCheckbox); + await fireEvent.click(secondCheckbox); + + await fireEvent.click(getByRole("button", { name: "Next" })); + await fireEvent.click(getByRole("button", { name: "Next" })); + + const mnemonicSplit = mnemonic.split(" "); + + // Iterates over the Mnemonic and selects each + // word in the correct order + // Note: This type of test won't work for mnemonic with repeated words + mnemonicSplit.forEach(async word => { + const button = getByRole("button", { name: word }); + await fireEvent.click(button); + }) + + await tick(); + + await fireEvent.click(getByRole("button", { name: "Next" })); + await fireEvent.click(getByRole("button", { name: "Next" })); + await fireEvent.click(getByRole("button", { name: "Next" })); + + expect(container.firstChild).toMatchSnapshot(); + }); + it("should initialize the wallet without setting a password", async () => { const { getByRole, getAllByRole } = render(Create); @@ -300,4 +406,65 @@ describe("Create", async () => { expect(gotoSpy).toHaveBeenCalledTimes(1); expect(gotoSpy).toHaveBeenCalledWith("/dashboard"); }); + + it("should initialize the wallet encrypted mnemonic saved in localStorage", async () => { + const { getByPlaceholderText, getByRole, getAllByRole } = render(Create); + + // ToS step + await fireEvent.click(getByRole("button", { name: "Accept" })); + + // Mnemonic Agreement step + const firstCheckbox = getAllByRole("checkbox")[0]; + const secondCheckbox = getAllByRole("checkbox")[1]; + + await fireEvent.click(firstCheckbox); + await fireEvent.click(secondCheckbox); + + await fireEvent.click(getByRole("button", { name: "Next" })); + + // Mnemonic Generate step + await fireEvent.click(getByRole("button", { name: "Next" })); + + // Mnemonic Validate step + const mnemonicSplit = mnemonic.split(" "); + + mnemonicSplit.forEach(async word => { + const button = getByRole("button", { name: word }); + await fireEvent.click(button); + }) + + await tick(); + + await fireEvent.click(getByRole("button", { name: "Next" })); + + // Set Password step + expect(loginInfoStorage.get()).toBeNull(); + + await fireEvent.click(getByRole("switch")); + + await fireInput(asInput(getByPlaceholderText("Set Password")), pwd); + await fireInput(asInput(getByPlaceholderText("Confirm Password")), pwd); + + expect(loginInfoStorage.get()).toBeNull(); + await fireEvent.click(getByRole("button", { name: "Next" })); + await vi.waitFor(() => { + expect(loginInfoStorage.get()).not.toBeNull(); + }); + + // Swap ERC20 to Native Dusk step + await fireEvent.click(getByRole("button", { name: "Next" })); + + // All Done step + await fireEvent.click(getByRole("button", { name: "Next" })); + + await vi.waitUntil(() => gotoSpy.mock.calls.length > 0); + + expect(settingsResetSpy).toHaveBeenCalledTimes(1); + expect(getWalletSpy).toHaveBeenCalledTimes(1); + expect(getWalletSpy).toHaveBeenCalledWith(seed); + expect(clearAndInitSpy).toHaveBeenCalledTimes(1); + expect(clearAndInitSpy).toHaveBeenCalledWith(expect.any(Wallet)); + expect(gotoSpy).toHaveBeenCalledTimes(1); + expect(gotoSpy).toHaveBeenCalledWith("/dashboard"); + }); });