fix: a token lookup that answers after the user left AddToken no longer changes the screen (closes #603)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

When the contract lookup on AddToken answered, the popup always went to AddressDetail, even after the user had opened another screen. The token is still added when the network has not changed. The popup now goes to AddressDetail only while AddToken is the screen showing. It tells this from state.currentView, as Send does. The status line is cleared once the token is added, so Back onto AddToken no longer shows "Looking up token...".

Model: opus-5-5
This commit is contained in:
2026-10-27 20:35:15 +00:00
parent 8998d6c661
commit 1958337bae
3 changed files with 105 additions and 0 deletions
+2
View File
@@ -2233,6 +2233,8 @@ view would leave a wallet one click from deletion.
**AddressDetail** **AddressDetail**
- "Add" with a token already tracked, a scam-listed address, or a failed - "Add" with a token already tracked, a scam-listed address, or a failed
contract lookup → flash message, no screen change contract lookup → flash message, no screen change
- "Add", then leaving AddToken before the contract lookup answers → tracks
the token, no screen change
- "Add", then a network switch in Settings before the contract lookup - "Add", then a network switch in Settings before the contract lookup
answers → nothing is tracked; "The active network changed before the answers → nothing is tracked; "The active network changed before the
lookup finished, so the token was not added." flash message, no screen lookup finished, so the token was not added." flash message, no screen
+7
View File
@@ -80,6 +80,13 @@ function init(ctx) {
}); });
await saveState(); await saveState();
ctx.doRefreshAndRender(); ctx.doRefreshAndRender();
// The lookup is over, so a later Back onto AddToken shows no
// status.
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
// If the user left AddToken while the lookup ran, the token is
// still added but the screen does not change.
if (state.currentView !== "add-token") return;
// Pop the stack (back to address detail) and re-render it // Pop the stack (back to address detail) and re-render it
// so the newly added token is visible immediately. // so the newly added token is visible immediately.
if (state.viewStack.length > 0) { if (state.viewStack.length > 0) {
+96
View File
@@ -0,0 +1,96 @@
// A contract lookup on AddToken can answer after the user has left AddToken.
// The token is still added, and the screen the user is on does not change
// (https://git.eeqj.de/sneak/AutistMask/issues/603). An answer while AddToken
// still shows goes to AddressDetail. Driven through the real popup over a
// stored profile.
const {
bootPopup,
cleanupPopup,
unversionedValidProfile,
TOKEN_ADDRESS,
} = require("./support/popupBoot");
const TOKEN = {
address: TOKEN_ADDRESS,
symbol: "TST",
decimals: 18,
name: "Test Token",
};
afterEach(() => {
cleanupPopup();
});
// The popup reopened onto AddressDetail, then AddToken opened from it with
// TOKEN's contract address typed in.
async function openAddToken() {
const boot = await bootPopup(
unversionedValidProfile({
currentView: "address",
selectedWallet: 0,
selectedAddress: 0,
}),
);
expect(boot.pageErrors).toEqual([]);
await boot.click("btn-add-token");
expect(boot.visibleViews()).toEqual(["add-token"]);
boot.node("add-token-address").value = TOKEN.address;
return boot;
}
// Presses Add with a contract lookup that answers only when the function
// returned here is called. That function waits for Add to finish.
function addWithPendingLookup(boot) {
const { lookupTokenInfo } = require("../src/shared/balances");
let answer;
lookupTokenInfo.mockImplementationOnce(
() =>
new Promise((resolve) => {
answer = resolve;
}),
);
const adding = boot.click("btn-add-token-confirm");
return async () => {
answer({
symbol: TOKEN.symbol,
decimals: TOKEN.decimals,
name: TOKEN.name,
});
await adding;
};
}
test("an answer after the user opened Settings adds the token and Settings stays", async () => {
const boot = await openAddToken();
const answerLookup = addWithPendingLookup(boot);
await boot.click("btn-settings");
expect(boot.visibleViews()).toEqual(["settings"]);
await answerLookup();
expect(boot.visibleViews()).toEqual(["settings"]);
expect(boot.storage.read("autistmask").trackedTokens).toEqual([TOKEN]);
});
test("Back onto AddToken after that answer shows no lookup status", async () => {
const boot = await openAddToken();
const answerLookup = addWithPendingLookup(boot);
expect(boot.text("add-token-info")).toBe("Looking up token...");
await boot.click("btn-settings");
await answerLookup();
await boot.click("btn-settings-back");
expect(boot.visibleViews()).toEqual(["add-token"]);
expect(boot.text("add-token-info")).toBe("");
expect(boot.node("add-token-info").style.visibility).toBe("hidden");
});
test("an answer while AddToken still shows goes to AddressDetail with the token listed", async () => {
const boot = await openAddToken();
const answerLookup = addWithPendingLookup(boot);
await answerLookup();
expect(boot.visibleViews()).toEqual(["address"]);
expect(boot.node("address-balances").innerHTML).toContain("TST");
expect(boot.storage.read("autistmask").trackedTokens).toEqual([TOKEN]);
});