// Home's "Send" and "Receive" open with no token selected. Three routes reach // Home with a token still selected, Send reads that token ahead of its dropdown, // and Receive warns about it // (https://git.eeqj.de/sneak/AutistMask/issues/753). Driven through the real // popup over a stored profile. const { bootPopup, cleanupPopup, unversionedValidProfile, TOKEN_ADDRESS, } = require("./support/popupBoot"); const RECIPIENT = "0x711e691962E5c054b78071C789A0C8CE657377aD"; const OTHER_WALLET_ADDRESS = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; const PRIVATE_KEY = "0x" + "11".repeat(32); const PASSWORD = "correct horse battery staple"; const TOKEN = { address: TOKEN_ADDRESS, symbol: "TST", decimals: 18, name: "Test Token", }; afterEach(() => { cleanupPopup(); }); // AddressToken opened from AddressDetail, as tapping the token's row does. async function openToken(page) { const { state } = require("../src/shared/state"); state.selectedToken = TOKEN_ADDRESS; require("../src/popup/views/helpers").pushCurrentView(); require("../src/popup/views/addressToken").show(); await page.settle(); expect(page.visibleViews()).toEqual(["address-token"]); } // The popup open on AddressToken, at an address holding 1.5 ETH and 2.5 TST. // A second wallet is there for the route that deletes one. async function bootOnToken() { const profile = unversionedValidProfile({ currentView: "address", viewStack: ["main"], selectedWallet: 0, selectedAddress: 0, trackedTokens: [TOKEN], }); profile.wallets[0].addresses[0].tokenBalances = [ { ...TOKEN, balance: "2.5" }, ]; profile.wallets.push({ type: "hd", name: "Wallet 2", xpub: "xpub-wallet-2", encryptedSecret: "encrypted-secret-2", nextIndex: 1, addresses: [ { address: OTHER_WALLET_ADDRESS, balance: "0", tokenBalances: [], }, ], }); const page = await bootPopup(profile); await openToken(page); return page; } async function reopenAfterTokenSend() { const closed = await bootOnToken(); await closed.click("btn-address-token-send"); cleanupPopup(); return bootPopup(undefined, { storage: closed.storage }); } async function addWalletFromTokenSettings() { const page = await bootOnToken(); await page.click("btn-settings"); await page.click("btn-main-add-wallet"); await page.click("tab-privkey"); page.node("import-private-key").value = PRIVATE_KEY; page.node("add-wallet-password").value = PASSWORD; page.node("add-wallet-password-confirm").value = PASSWORD; await page.click("btn-add-wallet-confirm"); return page; } // Deletes through the lost-password screen. It asks for the wallet's name, and // the stored wallets here have no real password. async function deleteWalletFromTokenSettings() { const page = await bootOnToken(); await page.click("btn-settings"); // What the second wallet's [x] button in Settings does. require("../src/popup/views/helpers").pushCurrentView(); require("../src/popup/views/deleteWallet").show(1); await page.click("btn-delete-wallet-lost-password"); page.node("delete-wallet-lost-name-input").value = "Wallet 2"; await page.click("btn-delete-wallet-lost-confirm"); await page.click("btn-settings-back"); return page; } const ROUTES = [ ["reopening the popup after AddressToken's Send", reopenAfterTokenSend], [ "the Settings gear on AddressToken, then adding a wallet", addWalletFromTokenSettings, ], [ "the Settings gear on AddressToken, then deleting another wallet, then Back", deleteWalletFromTokenSettings, ], ]; // A route that stopped reaching Home with the token selected would prove nothing // in the tests below, so it fails here. async function arriveOnHome(route) { const page = await route(); const { state } = require("../src/shared/state"); expect(page.visibleViews()).toEqual(["main"]); expect(state.selectedToken).toBe(TOKEN_ADDRESS); return page; } // ETH chosen in Send's dropdown, as the user does. async function chooseEth(page) { const dropdown = page.node("send-token"); dropdown.value = "ETH"; for (const fn of dropdown.listeners.change) await fn(); } // Review for 1 of the token Send has, to RECIPIENT. async function review(page) { page.node("send-to").value = RECIPIENT; page.node("send-amount").value = "1"; await page.click("btn-send-review"); expect(page.visibleViews()).toEqual(["confirm-tx"]); } describe.each(ROUTES)("after %s", (_name, route) => { test("choosing ETH on Home's Send reviews ETH", async () => { const page = await arriveOnHome(route); await page.click("btn-main-send"); await chooseEth(page); await review(page); expect(page.text("confirm-type")).toBe("Native ETH transfer"); expect(page.storage.read("autistmask").selectedToken).toBeNull(); }); test("Home's Send starts on ETH", async () => { const page = await arriveOnHome(route); await page.click("btn-main-send"); expect(page.text("send-balance")).toBe("Current balance: 1.5000 ETH"); expect(page.value("send-token")).toBe("ETH"); }); test("Home's Receive shows no token warning", async () => { const page = await arriveOnHome(route); await page.click("btn-main-receive"); expect(page.visibleViews()).toEqual(["receive"]); expect(page.text("receive-erc20-warning")).toBe(""); expect(page.storage.read("autistmask").selectedToken).toBeNull(); }); }); test("AddressToken's Send still sends the token after Home's Send has opened", async () => { const page = await arriveOnHome(deleteWalletFromTokenSettings); await page.click("btn-main-send"); await page.click("btn-send-back"); await openToken(page); await page.click("btn-address-token-send"); expect(page.text("send-balance")).toBe("Current balance: 2.5000 TST"); await review(page); expect(page.text("confirm-type")).toBe("ERC-20 token transfer (TST)"); });