diff --git a/src/popup/views/addressToken.js b/src/popup/views/addressToken.js index 6754afe..ec8e3d5 100644 --- a/src/popup/views/addressToken.js +++ b/src/popup/views/addressToken.js @@ -360,6 +360,11 @@ function init(_ctx) { }); $("btn-address-token-back").addEventListener("click", () => { + // AddressDetail's show() clears the token, but Back onto a drawn + // screen only unhides it. "Send" below may have left the dropdown on + // the token as well. + state.selectedToken = null; + $("send-token").value = "ETH"; goBack(); }); diff --git a/tests/addressTokenBack.test.js b/tests/addressTokenBack.test.js new file mode 100644 index 0000000..85bae9d --- /dev/null +++ b/tests/addressTokenBack.test.js @@ -0,0 +1,165 @@ +// "Back" from AddressToken leaves no token selected. AddressDetail's show() +// would clear it, but Back onto a drawn screen only unhides that screen, and +// Send and Receive both read the field +// (https://git.eeqj.de/sneak/AutistMask/issues/751). Driven through the real +// popup over a stored profile. + +const { + bootPopup, + cleanupPopup, + unversionedValidProfile, + TOKEN_ADDRESS, +} = require("./support/popupBoot"); + +const RECIPIENT = "0x711e691962E5c054b78071C789A0C8CE657377aD"; +const TOKEN = { + address: TOKEN_ADDRESS, + symbol: "TST", + decimals: 18, + name: "Test Token", +}; + +afterEach(() => { + cleanupPopup(); +}); + +// The popup reopened onto AddressDetail, at an address holding 1.5 ETH and +// 2.5 TST. +function bootOnAddress() { + const profile = unversionedValidProfile({ + currentView: "address", + viewStack: ["main"], + selectedWallet: 0, + selectedAddress: 0, + trackedTokens: [TOKEN], + }); + profile.wallets[0].addresses[0].tokenBalances = [ + { ...TOKEN, balance: "2.5" }, + ]; + return bootPopup(profile); +} + +// 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"]); +} + +async function backFromToken(page) { + await page.click("btn-address-token-back"); + expect(page.visibleViews()).toEqual(["address"]); +} + +// 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("after Back from AddressToken", () => { + test("no token is selected, on the page or in the stored record", async () => { + const page = await bootOnAddress(); + await openToken(page); + await backFromToken(page); + + const { state } = require("../src/shared/state"); + expect(state.selectedToken).toBeNull(); + expect(page.storage.read("autistmask").selectedToken).toBeNull(); + }); + + test("Send with ETH chosen shows the ETH balance", async () => { + const page = await bootOnAddress(); + await openToken(page); + await backFromToken(page); + + await page.click("btn-send"); + await chooseEth(page); + + expect(page.text("send-balance")).toBe("Current balance: 1.5000 ETH"); + }); + + test("Send with ETH chosen reviews ETH", async () => { + const page = await bootOnAddress(); + await openToken(page); + await backFromToken(page); + + await page.click("btn-send"); + await chooseEth(page); + await review(page); + + expect(page.text("confirm-type")).toBe("Native ETH transfer"); + }); + + test("Receive shows no token warning", async () => { + const page = await bootOnAddress(); + await openToken(page); + await backFromToken(page); + + await page.click("btn-receive"); + + expect(page.visibleViews()).toEqual(["receive"]); + expect(page.text("receive-erc20-warning")).toBe(""); + }); + + // AddressToken's Send sets the dropdown to the token, and nothing else + // rebuilds it on the way back to AddressDetail. + test("Send opens on ETH after AddressToken's Send has been used", async () => { + const page = await bootOnAddress(); + await openToken(page); + await page.click("btn-address-token-send"); + await page.click("btn-send-back"); + await backFromToken(page); + + await page.click("btn-send"); + + expect(page.value("send-token")).toBe("ETH"); + expect(page.text("send-balance")).toBe("Current balance: 1.5000 ETH"); + }); +}); + +describe("Send opened from AddressToken sends that token", () => { + async function expectSendsToken(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)"); + } + + test("the first time", async () => { + const page = await bootOnAddress(); + await openToken(page); + + await expectSendsToken(page); + }); + + test("after Back from Send", async () => { + const page = await bootOnAddress(); + await openToken(page); + await page.click("btn-address-token-send"); + await page.click("btn-send-back"); + + await expectSendsToken(page); + }); + + test("when the token is opened again after Back from AddressToken", async () => { + const page = await bootOnAddress(); + await openToken(page); + await backFromToken(page); + await openToken(page); + + await expectSendsToken(page); + }); +});