fix: Home's Send and Receive clear the selected token (closes #753)
Three routes reach Home with a token still selected. Send used that token whatever its dropdown showed, and Receive warned about it. Both now clear it when they open, and Send's dropdown starts on ETH. Model: opus-5-5
This commit is contained in:
@@ -581,8 +581,9 @@ Transitions:
|
||||
- "+": derives the next address in place.
|
||||
- `[info]`: AddressDetail.
|
||||
- `[x]`: DeleteAddress.
|
||||
- "Send": Send. Refused with a flash message when the active address has a zero
|
||||
ETH balance or belongs to a wallet carrying the `walletDefects.js` notice.
|
||||
- "Send": Send, with its dropdown on ETH. Refused with a flash message when the
|
||||
active address has a zero ETH balance or belongs to a wallet carrying the
|
||||
`walletDefects.js` notice.
|
||||
- "Receive": Receive.
|
||||
- Tap a transaction row: TransactionDetail.
|
||||
- "Add additional wallet...": AddWallet.
|
||||
|
||||
@@ -510,11 +510,15 @@ function init(ctx) {
|
||||
showFlash("Cannot send \u2014 zero balance.");
|
||||
return;
|
||||
}
|
||||
// Send uses a selected token ahead of its dropdown, and AddressToken
|
||||
// can leave one selected on the way here.
|
||||
state.selectedToken = null;
|
||||
$("send-to").value = "";
|
||||
$("send-amount").value = "";
|
||||
$("send-token-dropdown").classList.remove("hidden");
|
||||
$("send-token-static").classList.add("hidden");
|
||||
renderSendTokenSelect(addr);
|
||||
$("send-token").value = "ETH";
|
||||
updateSendBalance();
|
||||
resetSendValidation();
|
||||
pushCurrentView();
|
||||
@@ -526,6 +530,9 @@ function init(ctx) {
|
||||
showFlash("No active address selected.");
|
||||
return;
|
||||
}
|
||||
// Receive warns about a selected token, and AddressToken can leave one
|
||||
// selected on the way here.
|
||||
state.selectedToken = null;
|
||||
ctx.showReceive();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
// 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)");
|
||||
});
|
||||
Reference in New Issue
Block a user