Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41842b197e |
@@ -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 the contract lookup answers while another screen shows, or
|
||||||
|
after AddToken was opened again → 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
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ const { lookupTokenInfo } = require("../../shared/balances");
|
|||||||
const { isScamAddress } = require("../../shared/scamlist");
|
const { isScamAddress } = require("../../shared/scamlist");
|
||||||
const { log } = require("../../shared/log");
|
const { log } = require("../../shared/log");
|
||||||
|
|
||||||
|
// Counts the times AddToken has opened. A contract lookup started before
|
||||||
|
// AddToken was last opened changes neither the screen nor the status line.
|
||||||
|
let addTokenScreenOpenings = 0;
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
|
addTokenScreenOpenings++;
|
||||||
$("add-token-address").value = "";
|
$("add-token-address").value = "";
|
||||||
$("add-token-info").textContent = "";
|
$("add-token-info").textContent = "";
|
||||||
$("add-token-info").style.visibility = "hidden";
|
$("add-token-info").style.visibility = "hidden";
|
||||||
@@ -55,6 +60,7 @@ function init(ctx) {
|
|||||||
// The network the lookup asks, which Settings may switch away from
|
// The network the lookup asks, which Settings may switch away from
|
||||||
// before it answers, as for a transaction in confirmTx.js.
|
// before it answers, as for a transaction in confirmTx.js.
|
||||||
const chainId = currentNetwork().chainId;
|
const chainId = currentNetwork().chainId;
|
||||||
|
const opening = addTokenScreenOpenings;
|
||||||
try {
|
try {
|
||||||
const info = await lookupTokenInfo(
|
const info = await lookupTokenInfo(
|
||||||
contractAddr,
|
contractAddr,
|
||||||
@@ -80,6 +86,17 @@ function init(ctx) {
|
|||||||
});
|
});
|
||||||
await saveState();
|
await saveState();
|
||||||
ctx.doRefreshAndRender();
|
ctx.doRefreshAndRender();
|
||||||
|
// If the lookup answers after AddToken was opened again, the
|
||||||
|
// token is still added, but the screen and the status line stay
|
||||||
|
// as they are.
|
||||||
|
if (addTokenScreenOpenings !== opening) return;
|
||||||
|
// The lookup is over, so a later Back onto AddToken shows no
|
||||||
|
// status.
|
||||||
|
infoEl.textContent = "";
|
||||||
|
infoEl.style.visibility = "hidden";
|
||||||
|
// If the lookup answers while another screen shows, 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) {
|
||||||
@@ -100,6 +117,7 @@ function init(ctx) {
|
|||||||
? detail
|
? detail
|
||||||
: "Could not add the token.",
|
: "Could not add the token.",
|
||||||
);
|
);
|
||||||
|
if (addTokenScreenOpenings !== opening) return;
|
||||||
infoEl.textContent = "";
|
infoEl.textContent = "";
|
||||||
infoEl.style.visibility = "hidden";
|
infoEl.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
// 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",
|
||||||
|
};
|
||||||
|
|
||||||
|
// A second contract address, typed after AddToken was opened again.
|
||||||
|
const OTHER_TOKEN_ADDRESS = "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
|
||||||
|
|
||||||
|
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 from Settings onto AddToken after the lookup answered 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 after AddToken was opened again adds the token and leaves AddToken and its status line as they are", async () => {
|
||||||
|
const boot = await openAddToken();
|
||||||
|
const answerFirstLookup = addWithPendingLookup(boot);
|
||||||
|
await boot.click("btn-add-token-back");
|
||||||
|
await boot.click("btn-add-token");
|
||||||
|
expect(boot.visibleViews()).toEqual(["add-token"]);
|
||||||
|
boot.node("add-token-address").value = OTHER_TOKEN_ADDRESS;
|
||||||
|
// The second lookup is never answered.
|
||||||
|
addWithPendingLookup(boot);
|
||||||
|
|
||||||
|
await answerFirstLookup();
|
||||||
|
expect(boot.visibleViews()).toEqual(["add-token"]);
|
||||||
|
expect(boot.text("add-token-info")).toBe("Looking up token...");
|
||||||
|
expect(boot.storage.read("autistmask").trackedTokens).toEqual([TOKEN]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a lookup that fails after AddToken was opened again leaves the status line as it is", async () => {
|
||||||
|
const boot = await openAddToken();
|
||||||
|
const { lookupTokenInfo } = require("../src/shared/balances");
|
||||||
|
let failFirstLookup;
|
||||||
|
lookupTokenInfo.mockImplementationOnce(
|
||||||
|
() =>
|
||||||
|
new Promise((_, reject) => {
|
||||||
|
failFirstLookup = reject;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const firstAdd = boot.click("btn-add-token-confirm");
|
||||||
|
await boot.click("btn-add-token-back");
|
||||||
|
await boot.click("btn-add-token");
|
||||||
|
boot.node("add-token-address").value = OTHER_TOKEN_ADDRESS;
|
||||||
|
// The second lookup is never answered.
|
||||||
|
addWithPendingLookup(boot);
|
||||||
|
|
||||||
|
failFirstLookup(new Error("lookup failed"));
|
||||||
|
await firstAdd;
|
||||||
|
expect(boot.text("add-token-info")).toBe("Looking up token...");
|
||||||
|
});
|
||||||
|
|
||||||
|
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]);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user